test(mcp): assert the agent-reachable tool surface is exactly the six memory_* tools
Closes out finding 5: rather than relying on inspection of
mcp_server.py, assert directly that the MCP tool list is exactly
{memory_search, memory_get, memory_write, memory_update,
memory_supersede, memory_flag} and that none of edit, merge_into,
set_state, approve, reject or hard_delete is reachable through it. No
production code change was needed — mcp_server.py already only
registers the six tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139vHnNpS2sLNELjrAHX5Cu
This commit is contained in:
1 parent
10bb14189d
commit
40710ad23a
1 file changed
+24
@@ -199,3 +199,27 @@ async def test_pending_vectors_are_retried_in_the_background(settings, monkeypat
|
||||
assert service.health().vec_pending == 0
|
||||
finally:
|
||||
await service.stop()
|
||||
|
||||
|
||||
async def test_mcp_surface_cannot_mutate_or_promote_an_approved_note(svc):
|
||||
"""§2.4/§9: only the owner (via the web UI) may promote, edit in place, or
|
||||
mutate lifecycle state; agents get exactly the six memory_* tools. This
|
||||
closes out finding 5 by asserting the invariant in a test rather than
|
||||
relying on inspection of mcp_server.py."""
|
||||
from mcp.client import Client
|
||||
|
||||
from mdmem.mcp_server import build_mcp_server
|
||||
|
||||
async with Client(build_mcp_server(svc)) as client:
|
||||
names = {t.name for t in (await client.list_tools()).tools}
|
||||
|
||||
assert names == {
|
||||
"memory_search",
|
||||
"memory_get",
|
||||
"memory_write",
|
||||
"memory_update",
|
||||
"memory_supersede",
|
||||
"memory_flag",
|
||||
}
|
||||
owner_only = {"edit", "merge_into", "set_state", "approve", "reject", "hard_delete"}
|
||||
assert names.isdisjoint(owner_only)
|
||||
Reference in new issue
Block a user