Expand description
Discovery of .mcp.json — the MCP servers a workspace wants connected.
Tools reach the model three ways: mentra’s builtins, skills, and MCP
servers. mentra owns the client half — spawning the process, the
initialize handshake, bridging every advertised tool into the runtime’s
roster. basis owns the convention half: which file names a server, where that
file lives, and what its fields mean. Nothing here interprets a server.
§The format is not basis’s
An mcpServers object in a repo-root .mcp.json is what the agents that
already read a project-local MCP file write, so basis reads that rather than
inventing a spelling for the same idea. The one place basis is stricter: a
file that exists but names no mcpServers key is an error, because the
alternative is that a typo disables every server and says nothing.
§Three places a server can come from, and no fourth
In precedence order — supplied by the host, then the workspace file, then
the global one. “Supplied” is an ACP client’s mcpServers on
session/new, or a Rust host’s own list; the client is the most specific
authority there is, because it is answering for this session in particular.
There is deliberately no parent walk, which is where this module parts
company with context and skills.
Those walk from the workspace root outward, and for instructions that is
right: a monorepo’s house rules should reach every crate inside it, and the
worst case of picking one up is prose the model did not need.
.mcp.json is not prose. It names commands to spawn and credentials to
spawn them with — it is in basis’s own .gitignore for that reason, and in
most projects’ — so inheriting one from a directory the operator did not
point basis at means running a program they never chose, with a token they
never offered, because of where they happened to cd. Two roots the
operator names explicitly (this workspace, their own config) are the whole
set. A server in a parent directory is one cd away from being asked for
properly.
Nothing read here is ever repeated back: see McpError.
Names are the identity. mentra namespaces every bridged tool by its server’s name, so two servers sharing a name would collide in the tool roster; a more specific one therefore shadows a weaker one instead of joining it.
§Transports
stdio, the legacy HTTP+SSE transport, and Streamable HTTP — the three
mentra has clients for. Streamable HTTP is the transport current MCP
servers ship; a server that answers 404 on a legacy /sse path wants
McpServer::Http. One deliberate asymmetry survives in .mcp.json: a
bare url with no type still means SSE, because files written before
the third transport existed keep their meaning.
mentra’s allow_plaintext_credentials override is deliberately not a
.mcp.json key. A committed file must not be able to grant its own
headers plaintext passage to a non-loopback host — the same line drawn at
base_url — so the refusal stays mentra’s, checked at parse, and the
override stays with hosts that construct the config in code.
Structs§
- McpConfig
- Which MCP servers a run gets: where to look for configured ones, and any the host already has in hand.
- McpSource
- One
.mcp.jsonthat exists on disk, and what it configured.
Enums§
- McpError
- Anything that can go wrong turning configuration into servers.
- McpServer
- One MCP server, as basis hands it to mentra.
Constants§
- DEFAULT_
GLOBAL_ MCP_ FILE - Where basis looks inside the global config directory. Not the dotted name: a hidden file inside a directory that exists to hold configuration would be hiding it from the person who put it there.
- DEFAULT_
WORKSPACE_ MCP_ FILE - Where basis looks inside a workspace, relative to its root.