diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..a662c0f --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "clare": { + "type": "sse", + "url": "http://10.9.0.3:8767/mcp/sse" + } + } +} diff --git a/src/clare/orchestrator/mcp_server.py b/src/clare/orchestrator/mcp_server.py index 84bd8f1..1962fc0 100644 --- a/src/clare/orchestrator/mcp_server.py +++ b/src/clare/orchestrator/mcp_server.py @@ -23,6 +23,7 @@ from pathlib import Path from typing import Any from mcp.server.fastmcp import FastMCP +from mcp.server.transport_security import TransportSecuritySettings from ..config import load_or_init from ..db import migrate, open_db @@ -130,7 +131,16 @@ def build_server() -> FastMCP: Factory style so tests can build their own server bound to a different db_path without process-wide globals. """ - mcp = FastMCP(name="clare", instructions=_INSTRUCTIONS) + # DNS-rebinding protection defaults reject anything but 127.0.0.1/localhost. + # Clare binds to the LAN IP (e.g. 10.9.0.3) so the orchestrator session + + # dev tooling on other hosts can reach /mcp/sse — relax the allowlist. + mcp = FastMCP( + name="clare", + instructions=_INSTRUCTIONS, + transport_security=TransportSecuritySettings( + enable_dns_rebinding_protection=False, + ), + ) # Slash mirror ---------------------------------------------------------- @mcp.tool() diff --git a/src/clare/web/chat/handler.py b/src/clare/web/chat/handler.py index 02429fe..63f3126 100644 --- a/src/clare/web/chat/handler.py +++ b/src/clare/web/chat/handler.py @@ -120,7 +120,7 @@ def _run_orchestrator( try: _send_via_rclaude( text=f"[turn:{turn_id}] {body}", - match=cfg.session_uuid[:8], + match=_tmux_match_for_cwd(_ORCHESTRATOR_CWD), ) except OrchestratorError as exc: # Drain the slot so the registry doesn't leak — we never sent. diff --git a/tests/test_orchestrator_turn.py b/tests/test_orchestrator_turn.py index f624e1d..6423f37 100644 --- a/tests/test_orchestrator_turn.py +++ b/tests/test_orchestrator_turn.py @@ -89,8 +89,8 @@ def test_orchestrator_round_trip_with_fake_claude( m = _TURN_RE.search(text) assert m, f"missing [turn:..] prefix in: {text!r}" tid = m.group(1) - # Sanity: we addressed the right session. - assert match == fake_session[:8] + # Sanity: we addressed by tmux-name slug (UUID isn't in the tmux name). + assert "clare-orchestrator" in match def deliver() -> None: time.sleep(0.05) # simulate Claude thinking