MCP
MindRoom is a Model Context Protocol (MCP) client: it connects to the MCP servers you configure, discovers their tools, and lets agents call them. MindRoom uses MCP tools only; it does not use MCP resources or prompts. To go the other way and expose your agents' tools to external MCP clients, use the MCP Gateway.
Add an MCP Server
Configure servers in the top-level mcp_servers block of config.yaml.
Each key is a server ID made of letters, numbers, and underscores.
Each enabled server becomes one MindRoom tool named mcp_<server_id>; add that name to an agent's tools: list to give the agent the server's tools.
mcp_servers:
chrome_devtools:
transport: stdio
command: npx
args:
- -y
- chrome-devtools-mcp@latest
tool_prefix: chrome
agents:
browser:
display_name: Browser
role: Debug and inspect web apps in Chrome
model: sonnet
tools:
- mcp_chrome_devtools
MCP tools work on every worker scope, including private agents.
Transports
transport |
Use for | Required | Optional | Not allowed |
|---|---|---|---|---|
stdio |
A local server that MindRoom starts as a subprocess | command |
args, cwd, env |
url, headers, auth |
sse |
A remote server with a Server-Sent Events endpoint | url |
headers, auth |
command, args, cwd, env |
streamable-http |
A remote server with a streamable HTTP endpoint | url |
headers, auth |
command, args, cwd, env |
mcp_servers:
remote_http:
transport: streamable-http
url: https://mcp.example.com/mcp
headers:
Authorization: Bearer ${MCP_API_TOKEN}
Remote transports refuse loopback and private-network addresses; run local servers with stdio instead.
Credentials in Server Config
env and headers values support ${ENV_VAR} placeholders, resolved from MindRoom's environment when the connection opens.
Pass stdio credentials through env, never through args.
config_manager and !config show mask env and headers values, except values that are a whole ${ENV_VAR} placeholder, but show args as written, and args support no placeholders.
Without OAuth, every agent and requester shares one server session and the same static headers, and MindRoom never passes the requester's identity or credentials to the server.
For per-user or per-agent accounts on a remote server, use OAuth.
Tool Names
There are two names to keep apart:
- The tool entry in an agent's
tools:list ismcp_<server_id>. - The function names the model sees are
<prefix>_<remote_tool_name>, where the prefix istool_prefixor, if unset, the server ID.
With tool_prefix: chrome, a remote tool named navigate_page becomes chrome_navigate_page.
A final function name must be 64 characters or fewer.
MindRoom rejects duplicate function names within one server and across the tools and servers visible to the same agent; agents that do not share the colliding surfaces may use identical names.
Choose Which Tools an Agent Sees
include_tools and exclude_tools on the server filter the catalog for every agent.
To narrow it for one agent, set overrides where you assign the tool:
agents:
browser:
tools:
- mcp_chrome_devtools:
include_tools:
- new_page
- navigate_page
- take_snapshot
call_timeout_seconds: 180
Per-agent overrides accept include_tools, exclude_tools, and call_timeout_seconds (greater than 0).
Filters match remote MCP tool names, not prefixed function names, and a name cannot appear in both include_tools and exclude_tools.
Dashboard Name and Icon
display_name, summary, and icon control how the server appears in the dashboard tool catalog and on Connections; they do not change tool names or permissions.
mcp_servers:
team_wiki:
display_name: Team Wiki
summary: Search and edit team documentation
icon: SiConfluence
transport: streamable-http
url: https://wiki.example.com/mcp
icon takes a Lucide icon name such as Book or Calendar, or a bundled React Icons name such as SiConfluence or SiGooglecalendar.
Without a usable icon, Connections picks one matching the server's name, or a plug icon.
Server Options
| Option | Type | Default | Notes |
|---|---|---|---|
enabled |
bool | true |
Set to false to disable the server without removing its config |
transport |
string | required | stdio, sse, or streamable-http |
command |
string | null |
Required for stdio |
args |
list[string] | [] |
stdio arguments; shown unmasked, so never put credentials here |
cwd |
string | null |
stdio working directory |
env |
map[string,string] | {} |
stdio environment variables; supports ${ENV_VAR} |
url |
string | null |
Required for sse and streamable-http |
headers |
map[string,string] | {} |
Remote request headers; supports ${ENV_VAR} |
auth |
object | null |
OAuth settings for remote servers; see OAuth Settings |
tool_prefix |
string | server ID | Prefix for model-visible function names; letters, numbers, and underscores |
include_tools |
list[string] | [] |
Allowlist of remote tool names |
exclude_tools |
list[string] | [] |
Denylist of remote tool names; must not overlap include_tools |
display_name |
string | null |
Catalog name; falls back to auth.display_name, then a name derived from the server ID |
summary |
string | null |
Short capability summary for the dashboard and catalog |
icon |
string | null |
Dashboard and Connections icon name |
description |
string | null |
What the server offers, added to the OAuth bridge tool descriptions the model sees; requires auth |
required |
bool | false |
Keep dependent agents and teams from starting while the server is unavailable |
startup_timeout_seconds |
float | 20.0 |
Time allowed to connect, initialize, and list tools; must be greater than 0 |
call_timeout_seconds |
float | 120.0 |
Default timeout per tool call; must be greater than 0 |
max_concurrent_calls |
int | 1 |
Maximum concurrent tool calls to the server; at least 1 |
auto_reconnect |
bool | true |
Reconnect for later calls after a dropped connection or timeout; the failed call is never replayed |
OAuth-Backed Remote MCP
Use auth.type: oauth when a remote MCP server needs an OAuth bearer token, so each connection belongs to the right user or agent.
OAuth requires sse or streamable-http.
mcp_servers:
example:
transport: streamable-http
url: https://mcp.example.com/mcp
tool_prefix: example
description: Example workspace search, documents, and calendar for the signed-in user.
auth:
type: oauth
display_name: Example MCP
discovery: auto
agents:
assistant:
display_name: Assistant
role: Use the user's Example workspace
model: sonnet
worker_scope: user_agent
tools:
- mcp_example
The connection follows the agent's effective scope (private.per, then worker_scope, then defaults.worker_scope), as described in Where Connections Are Stored.
Changing an agent's scope changes whose connection it uses, and MindRoom never copies a credential into the new scope, so reconnect there.
Connecting and Bridge Tools
Every OAuth-backed server always exposes three functions:
<prefix>_connection_status<prefix>_list_tools<prefix>_call_tool
Before the account is connected, these are the only functions the model sees, so set description to tell the model what connecting unlocks.
When no account is connected, they return a connect link (see OAuth onboarding in conversation).
After connecting, <prefix>_list_tools returns the server's tools and <prefix>_call_tool calls them with that connection's token.
Once MindRoom has loaded the catalog for that connection, the agent also gets typed <prefix>_<remote_tool_name> functions.
A temporary token refresh failure returns MCP server '<server_id>' OAuth token refresh failed; retry shortly and keeps the stored credentials.
To reset a stuck or revoked connection, see Reset A Connection.
Endpoint Discovery
With discovery: auto, MindRoom reads the OAuth protected-resource metadata (/.well-known/oauth-protected-resource) for resource, or url when resource is unset, then fetches the advertised authorization server's metadata.
If no authorization server is advertised, it looks for authorization-server metadata at the resource's origin.
Setting authorization_server skips the protected-resource lookup, and explicit authorization_url, token_url, or registration_url values override the discovered endpoints.
Discovery fails if the authorization server does not support the configured token_endpoint_auth_method or PKCE method.
Use discovery: manual when the server publishes no metadata or you want fixed endpoints:
mcp_servers:
example_manual:
transport: streamable-http
url: https://mcp.example.com/mcp
auth:
type: oauth
discovery: manual
authorization_url: https://mcp.example.com/oauth/authorize
token_url: https://mcp.example.com/oauth/token
registration_url: https://mcp.example.com/oauth/register
Discovery requires HTTPS, refuses loopback and private-network hosts, and does not follow redirects.
For local development, set MINDROOM_MCP_OAUTH_ALLOW_INSECURE_DISCOVERY=1 to allow non-HTTPS discovery URLs and MINDROOM_MCP_OAUTH_ALLOW_PRIVATE_DISCOVERY=1 to allow loopback or private-network discovery hosts.
These variables do not relax the address rules for the MCP connection itself.
OAuth Client Registration
With dynamic_client_registration: true and no stored client, MindRoom registers a client when the first user connects and reuses it for later users.
See Built-In Providers for when a dynamically registered client works from a hosted address.
If discovery later resolves a different token endpoint, MindRoom registers a new client there and logs oauth_dynamic_client_reregistered, and users connected through the old client must reconnect.
With dynamic registration disabled, or when the new server offers no registration endpoint, connecting fails instead.
To use your own OAuth app, store its client config in the credential service <provider_id>_oauth_client, or list other services in client_config_services.
Tokens are stored in <provider_id>_oauth; when provider_id does not start with mcp_, both service names get an mcp_ prefix.
Public clients (token_endpoint_auth_method: none) need only client_id; confidential clients also need client_secret.
MindRoom never re-registers an operator-configured client, so for a confidential client pin authorization_server or token_url to keep the server's metadata from redirecting its secret to another token endpoint.
See Provider And Credential Service Rules for client config service rules.
OAuth Settings
auth field |
Type | Default | Notes |
|---|---|---|---|
type |
string | required | Must be oauth |
provider_id |
string | mcp_<server_id> |
OAuth provider ID; letters, numbers, and underscores |
display_name |
string | null |
Provider name; defaults to MCP <Server Id> |
resource |
string | server url |
Protected resource used for discovery |
discovery |
string | auto |
auto or manual |
authorization_server |
string | null |
Authorization server issuer or base URL; skips protected-resource discovery |
authorization_url |
string | null |
Authorization endpoint; required for manual |
token_url |
string | null |
Token endpoint; required for manual |
registration_url |
string | null |
Dynamic client registration endpoint |
dynamic_client_registration |
bool | true |
Allow registering a client automatically |
token_endpoint_auth_method |
string | none |
none, client_secret_post, or client_secret_basic |
pkce_code_challenge_method |
string | S256 |
S256, or null to disable PKCE |
scopes |
list[string] | [] |
Requested OAuth scopes |
extra_auth_params |
map[string,string] | {} |
Extra authorization request parameters, such as resource |
extra_token_params |
map[string,string] | {} |
Extra code-exchange and refresh parameters; treated as secret |
client_config_services |
list[string] | [] |
Credential services holding the OAuth client config, in lookup order; defaults to <provider_id>_oauth_client |
shared_client_config_services |
list[string] | [] |
Shared client config services checked after client_config_services |
Examples
Echo Server
A minimal local server, saved as echo_mcp_server.py:
from mcp.server.fastmcp import FastMCP
server = FastMCP("Echo Server")
@server.tool()
def echo(text: str) -> str:
return f"echo:{text}"
if __name__ == "__main__":
server.run()
mcp_servers:
echo:
transport: stdio
command: ./.venv/bin/python
args:
- ./echo_mcp_server.py
agents:
code:
display_name: Code
role: Test MCP tools
model: sonnet
tools:
- mcp_echo
The model sees the remote echo tool as echo_echo.
Use a Python interpreter that has the mcp package installed.
To serve it remotely instead, run server.run(transport="sse") (endpoint /sse) or server.run(transport="streamable-http") (endpoint /mcp).
Chrome DevTools
The Add an MCP Server example starts chrome-devtools-mcp, which launches its own Chrome with a dedicated profile.
To attach to an already running debuggable Chrome instead, add --browser-url:
mcp_servers:
chrome_devtools:
transport: stdio
command: npx
args:
- -y
- chrome-devtools-mcp@latest
- --browser-url=http://127.0.0.1:9222
tool_prefix: chrome
If Chrome starts slowly, increase startup_timeout_seconds; if browser operations run long, increase call_timeout_seconds.
MemPalace Memory
MemPalace is a local memory store with MCP tools for search and adding memories.
Running it through uvx keeps its ChromaDB version separate from MindRoom's:
mcp_servers:
mempalace:
transport: stdio
command: uvx
args:
- --from
- mempalace
- python
- -m
- mempalace.mcp_server
- --palace
- /path/to/.mempalace/palace
startup_timeout_seconds: 30
call_timeout_seconds: 60
agents:
assistant:
display_name: Assistant
role: General assistant with persistent memory
model: sonnet
tools:
- mcp_mempalace
Initialize and seed the same palace before the server can return results:
uvx mempalace --palace /path/to/.mempalace/palace init /path/to/content
uvx mempalace --palace /path/to/.mempalace/palace mine /path/to/content
See the MemPalace CLI reference for these commands.
Failures and Catalog Changes
MindRoom connects to MCP servers at startup and whenever config.yaml changes, and logs a warning for each server that fails to start, initialize, or list valid tools.
By default a failed server does not block anything: agents and teams that use it start without its tools.
MindRoom keeps retrying a failed server without OAuth in the background and restarts the affected agents and teams once it recovers.
An OAuth-backed server is retried on its next tool call.
Set required: true to keep dependent agents and teams from starting until the server is available.
A function-name collision is not retried, and the colliding servers' tools stay unavailable.
Fix the remote tool names or tool_prefix values, then reload config.yaml or restart MindRoom.
Errors that the MCP server reports for a tool call return to the agent as tool errors and are not retried.
If the connection drops or times out during a call, the call fails even when auto_reconnect restores the connection, and the action is never replayed.
Check whether a call that changes something actually completed before retrying it.
When a server reports that its tool list changed, MindRoom reloads the list, at most once a minute per server. If the tools changed, the agents and teams that use the server restart to pick them up, waiting for active responses like a config reload.