6e46ca4478
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>
39 lines
1.3 KiB
Python
39 lines
1.3 KiB
Python
"""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()
|