feat(supervise): provision agent-side MCP config so Claude sees the sidecar
The supervise sidecar (PRD 0013) has been serving MCP at http://supervise:9100/ since it landed, but the in-bottle Claude Code had no `.mcp.json` or settings pointing there — so the agent couldn't actually call cred-proxy-block / pipelock-block / capability-block as tools. To exercise the flow you had to curl the sidecar from a sibling container. This closes that last mile. - claude_bottle/backend/docker/provision/supervise.py (new): provision_supervise(plan, target) writes ~/.claude/settings.json into the running agent container with an mcpServers.supervise entry of type http pointing at the per-bottle sidecar. No-op when bottle.supervise is False. - BottleBackend.provision orchestrator gains provision_supervise as the last step (after CA, prompt, skills, git, cred-proxy). Default impl is a no-op so non-Docker backends aren't forced to implement it. - DockerBottleBackend wires it through to the new module. - Test covers the rendered settings shape so a future regression in the MCP entry format would surface in unit-level CI. To test the full flow end-to-end now: ./cli.py start <agent> --cwd # agent's claude sees supervise # agent calls cred-proxy-block via MCP ./cli.py dashboard # approve ./cli.py resume <identity> # restart with new capabilities Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
"""Unit: supervise MCP settings renderer (PRD 0013 follow-up).
|
||||
|
||||
The docker cp / chown side of provision_supervise is exercised by
|
||||
the existing supervise integration test once the agent container is
|
||||
brought up; here we cover the pure render path so a settings.json
|
||||
shape regression would surface in unit-level CI."""
|
||||
|
||||
import json
|
||||
import unittest
|
||||
|
||||
from claude_bottle.backend.docker.provision.supervise import render_settings
|
||||
from claude_bottle.supervise import SUPERVISE_HOSTNAME, SUPERVISE_PORT
|
||||
|
||||
|
||||
class TestRenderSettings(unittest.TestCase):
|
||||
def test_output_is_valid_json(self):
|
||||
json.loads(render_settings())
|
||||
|
||||
def test_has_mcp_servers_supervise_http_entry(self):
|
||||
cfg = json.loads(render_settings())
|
||||
servers = cfg["mcpServers"]
|
||||
self.assertIn("supervise", servers)
|
||||
sv = servers["supervise"]
|
||||
self.assertEqual("http", sv["type"])
|
||||
self.assertEqual(
|
||||
f"http://{SUPERVISE_HOSTNAME}:{SUPERVISE_PORT}/",
|
||||
sv["url"],
|
||||
)
|
||||
|
||||
def test_only_supervise_server_is_emitted(self):
|
||||
cfg = json.loads(render_settings())
|
||||
# Keep the provisioner narrowly scoped — it owns just the
|
||||
# supervise entry, no other tools/servers.
|
||||
self.assertEqual({"supervise"}, set(cfg["mcpServers"].keys()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user