feat(server): set FastMCP instructions= so MCP clients see multi-agent recipe#477
Merged
feat(server): set FastMCP instructions= so MCP clients see multi-agent recipe#477
Conversation
…ecipe
Tool docstrings alone left LLMs guessing which memtomem tool to call
when users asked for per-agent isolation — clients silently fell back
to plain `mem_add` instead of `mem_agent_share`. The MCP spec's
`initialize` response carries an `instructions` field that clients
auto-inject into every LLM session alongside the tool list, but
memtomem's `FastMCP("memtomem", lifespan=app_lifespan)` constructor
call left it unset. Pass a workflow-recipe string instead.
Content covers: single-agent quickstart (`mem_add` / `mem_search`),
the multi-agent recipe in order (`mem_agent_register` →
`mem_session_start` → `mem_agent_search` / `mem_agent_share` →
`mem_session_end`), namespace conventions (`default` /
`agent-runtime:<id>` / `shared:`), and pitfalls — notably that
`mem_add` without `namespace=` consults `current_namespace` rather
than the active session's `agent-runtime:*` scope, so multi-agent
write paths must go through `mem_agent_share`.
Source of truth lives in `memtomem/server/instructions.py` so the
constant is grep-able and reusable. The existing `serverInfo.version`
patch in `server/__init__.py` (#383) is the closest prior art for
tweaking the initialize response.
Pin tests in `tests/test_server_instructions.py` mirror
`test_server_version_reporting.py`:
- Unit test asserts `mcp.instructions == INSTRUCTIONS` and that every
workflow token an LLM has to recognize (tool name or namespace
prefix) appears in the constant — renames must move both halves
in lockstep.
- E2E test drives the `initialize` RPC against a real subprocess and
asserts the `instructions` field round-trips, so a future FastMCP
release that drops the parameter is still caught.
Complements PR #475: now that `mem_session_start` derives
`agent-runtime:<agent_id>`, the LLM also knows when to invoke it.
Co-Authored-By: Claude <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
memtomem's MCP server constructed FastMCP without an
instructions=argument:
The MCP spec's
initializeresponse carries aninstructionsfieldthat clients auto-inject into every LLM session alongside the tool
list — but memtomem left it empty, so LLMs had only per-tool
docstrings to go on. When users asked for per-agent isolation, clients
were quietly defaulting to plain
mem_addinstead of routing throughmem_agent_share. Surfaced while walking the v0.1.28 multi-agenttest scenarios from
memtomem-docs(same trail that produced #473and #475).
This PR threads a workflow-recipe string through
instructions=soevery client gets the same hint, paste-free.
What the recipe covers
mem_add/mem_search,defaultnamespace. The 90% case stays one line.
mem_agent_register→mem_session_start(agent_id=...)→mem_agent_search/mem_agent_share→mem_session_end.default/agent-runtime:<id>/shared:with one-line descriptions.mem_addwithoutnamespace=consultscurrent_namespace, not the session'sagent-runtime:*scope, somulti-agent writes must go through
mem_agent_share. Caught whilereviewing fix(sessions): mem_session_start derives namespace from agent_id #475.
Full string lives in
packages/memtomem/src/memtomem/server/instructions.pyso it's grep-able and reusable.
Why this PR (vs. docs / per-tool docstring edits)
picked a tool — they don't help with the routing decision.
USAGE.mdsnippet would require every user to pasteit into
CLAUDE.md/ system prompt manually. The MCPinstructionschannel auto-injects.
instructions=(visiblein any session that has both servers connected). FastMCP supports
the parameter natively; no SDK changes needed.
Test plan
Pin tests in
packages/memtomem/tests/test_server_instructions.pymirror
test_server_version_reporting.py(#383):mcp.instructions == INSTRUCTIONSand every workflowtoken (tool name or namespace prefix) appears in the constant.
Renames force both halves to move in lockstep.
initializeJSON-RPC call against a realsubprocess, parses the response, and asserts the
instructionsfield round-trips. Catches FastMCP regressions that drop or
strip the parameter.
uv run pytest packages/memtomem/tests/test_server_instructions.py -v— 12 / 12 pass.
uv run pytest -m "not ollama"— 2457 / 2457 pass, 46deselected, no regressions.
uv run ruff check packages/memtomem/src packages/memtomem/testsand
ruff format --check— clean.Backward compat
initializeresponse gains a non-empty
instructionsfield.see no behavioral difference.
Follow-ups (out of scope)
memtomem-docs/USAGE-multi-agent.mdlonger-form recipe ifthe 50-line
instructions=proves too thin in practice. The pintest makes it safe to deepen the constant in place first.
🤖 Generated with Claude Code