wenchang/integrate-new-server.md View as Markdown (for AI agents; also llms.txt)
Integrate: a new MCP server#
wenchang.mcp.build_server(...) returns a new mcp 2.x MCPServer that carries the memory prompt as its instructions, the seven memory tools, and the prompt resource wenchang://memory-prompt. You run it with server.run(...). Quickstart builds one end to end for Claude Code; this page covers every argument and both transports.
MCPServer only. The mcp extra installs mcp>=2.2,<3, and the adapter targets mcp.server.mcpserver.MCPServer. FastMCP servers and mcp 1.x servers do not work: with mcp 1.x installed, importing wenchang.mcp raises ImportError, and register_memory_tools raises TypeError("server must be an MCPServer, not ...") for any other server type. For another framework, see Integrate without MCP.Install with the extra: pip install "wenchang[mcp] @ git+https://github.com/msiebert/wenchang@v0.1.1".
Arguments#
Every argument is keyword-only. build_server checks them all before it creates the server, and raises TypeError or ValueError for a bad one.
| Argument | Required | What it does |
|---|---|---|
slots |
yes | A PromptSlots. The server's instructions are build_memory_prompt(slots). See Customizing the prompts. |
client |
yes | A TransportClient, normally InProcessClient(MemoryStore(...)). Tool calls run concurrently on worker threads and share it. See Threads for what is safe to share. |
resolver |
yes | Your IdentityResolver. On this path it runs on every tool call. Its resolve must be a plain synchronous method; an async one raises TypeError at registration. See Identity. |
policy |
yes | A ScopePolicy: the roles that may write each scope. |
credentials_from_context |
yes | A plain (non-async) function that takes the MCP request Context and returns the raw credentials your resolver verifies. See Credentials. |
source |
yes | The surface name added to each written file's sources metadata. Non-empty. |
product |
no | Your product's name, put in the first line of each tool description. One non-empty line. |
tool_prefix |
no | Registers each tool as {tool_prefix}_{name}. 1 to 64 letters, digits, _ or -, starting and ending with a letter or digit. |
on_call |
no | A plain function called with a ToolCallRecord after every tool call. See Observing calls. |
name |
no | The server name. Default "wenchang". |
The server's version is the installed wenchang version. Names on the tools has more on product, tool_prefix, and source.
Where the guidance goes#
Some clients, including Claude Desktop and claude.ai, ignore the server's instructions. The server therefore also puts the core rules where every client sees them:
get_memory_index's description starts with yourpurpose, then says to call it first and that its result includes the memory rules.- The descriptions of
write_file,append_line, andreplace_factstart with a short preamble: scope by the index's Scopes rules, label lines[stated],[observed], or[inferred], never write a new[system]line, save facts as they arise, and never store financial account numbers, health diagnoses, or anything indicating a minor. - A successful
get_memory_indexcall returns the full memory prompt as a second text content block.
instructions and the wenchang://memory-prompt resource are unchanged. wenchang.mcp.mcp_tool_descriptions(slots=None, product=None) returns the descriptions the server registers. Startup raises ValueError if one exceeds MAX_TOOL_DESCRIPTION_CHARS (2000), which only a very long purpose can cause. The core tool_descriptions() and MemoryTools.descriptions() are unchanged, since a non-MCP integrator owns its system prompt.
Two things help the agent find and use the tools. Keep purpose short and specific, because tool search matches on it. Give the connector a short, descriptive display name so the model recognizes when it applies.
Credentials#
Every tool call runs credentials_from_context(ctx), passes the result to your resolver, and binds that caller's own tools. ctx.headers holds the request headers on HTTP and is None on stdio. Return the raw value and leave verification to the resolver. If the function raises, the call fails with a permanent ResolverFailureError, and only the exception's type is logged, since its message may carry the credential.
Transports#
- stdio.
server.run("stdio"). The client starts one server process per session, so identity usually comes from the process environment: a variable holding a token, or the grants themselves for a single-developer setup as in Quickstart. Return it fromcredentials_from_contextasos.environ.get("MEMORY_TOKEN")and let the resolver verify it. - Streamable HTTP.
server.run("streamable-http", host="0.0.0.0", port=8000)serves the MCP endpoint at/mcp(mcp's defaults are host127.0.0.1and port 8000). Put TLS in front of it. Each request carries its own credentials in headers, so one process serves many callers. The MCP SDK also has its own auth options onMCPServer(auth,token_verifier) if you want requests rejected before they reach wenchang; see themcpdocumentation. Identity has a complete multi-tenant HTTP server, which has been run against fake-gcs-server and driven by mcp's streamable-HTTP client.
Observing calls#
on_call receives a wenchang.observer.ToolCallRecord after every tool call (wenchang.mcp re-exports it). On this path:
toolis the registered name, prefix included.request_idis the MCP request's ID, for correlating records that arrive in completion order.duration_scovers reading credentials, binding, the tool, and rendering.- It runs on worker threads, so it must be thread-safe and fast.
Calls MCP rejects while validating arguments never produce a record. An exception the observer raises is logged at ERROR and swallowed. The reference lists every field.
Next#
- Identity and multi-tenant auth: a resolver for real users.
- Integrate: an existing mcp 2.x server: the same tools on a server you already run.