Shared app servers: the PreToolUse hook leaves a ticket naming the calling session, the MCP server takes it per call (middleware), so two sessions of one app on one Harbor server act as themselves; i_am checks instead of binding and is allowed under a stop

This commit is contained in:
KeelrLeek committed 2026-10-06 10:47:08 -05:00
1 parent e283e4cc54
commit fdaa3b0806
4 files changed
+131 -18

No files matched your search

+35
View File
@@ -288,6 +288,41 @@ class ServerWork(unittest.TestCase):
class Mcp(unittest.TestCase):
def test_shared_server_takes_the_calling_session_from_the_hook_ticket(self):
"""One app's server shared by two sessions: each call runs as the agent its hook named in a ticket."""
from fastmcp import Client
from harbor import mcp_server, sessions
d = temp_dir()
project = make_home(d)["test"]
mcp_server._state.clear()
mcp_server._state["project"] = project
saved = {k: os.environ.get(k) for k in ("HARBOR_AGENT", "HARBOR_HOST")}
os.environ.update(HARBOR_AGENT="Codex", HARBOR_HOST="codex")
async def scenario():
async with Client(mcp_server.mcp) as client:
sessions.leave(mcp_server.harbor(), "codex", "doing", {"text": "second session"}, "DeepSeek")
await client.call_tool("doing", {"text": "second session"}) # the ticket names DeepSeek
await client.call_tool("doing", {"text": "first session"}) # no ticket: the server's own
status = (await client.call_tool("status", {})).data
doing = {a["name"]: a["doing"] for a in status["agents"]}
self.assertEqual(doing["DeepSeek"], "second session")
self.assertEqual(doing["Codex"], "first session")
sessions.leave(mcp_server.harbor(), "codex", "i_am", {"agent": "DeepSeek"}, "DeepSeek")
self.assertTrue((await client.call_tool("i_am", {"agent": "DeepSeek"})).data["matches"])
self.assertFalse((await client.call_tool("i_am", {"agent": "DeepSeek"})).data["matches"]) # used up
try:
asyncio.run(scenario())
finally:
for k, v in saved.items():
if v is None:
os.environ.pop(k, None)
else:
os.environ[k] = v
mcp_server._state.pop("h").close()
mcp_server._state.clear()
def test_tools_bind_identity_and_round_trip(self):
from fastmcp import Client
from fastmcp.exceptions import ToolError