Model Context Protocol server
Foundry can expose a governed Model Context Protocol (MCP) server over local stdio. MCP-compatible clients gain a standard, discoverable, read-only view of content, documentation, themes, plugins, and runtime health without scraping HTML, shelling out to the CLI, or reaching into the filesystem.
The transport is an adapter over existing Foundry services. It does not introduce a parallel content model, and it never bypasses Foundry authorization, plugin governance, or auditing.
Enabling the server
MCP is disabled unless it is explicitly enabled in content/config/site.yaml:
mcp:
enabled: true
read_only: true
audit: false
max_concurrency: 16
rate_limit:
requests_per_minute: 600
burst: 120
scopes:
- read:content
- read:docs
- read:themes
- read:plugins
- read:ops
The initial release is read-only. When scopes is omitted, every read scope is
enabled and every mutating scope stays disabled. read_only defaults to
true; setting it to false is reserved for future mutating
capabilities and does not by itself grant write access. max_concurrency
defaults to 16 in-flight requests, and rate_limit defaults to
600 requests per minute with a 120 request burst.
Running the server
foundry mcp serve --transport stdio
In stdio mode the process speaks newline-delimited JSON-RPC on stdout and writes logs and diagnostics to stderr. It exits cleanly when the client closes stdin. Startup banners never touch stdout, so the protocol stream stays clean.
Configuring a client
Point any MCP-compatible client at the Foundry binary. Run it from the project root (or set
cwd) so Foundry loads the normal configuration and content.
{
"mcpServers": {
"foundry": {
"command": "foundry",
"args": ["mcp", "serve", "--transport", "stdio"],
"cwd": "/path/to/foundry-project"
}
}
}
Capability catalog
All capabilities are read-only in the initial release and are namespaced and versioned.
Tools
| Tool | Scope | Purpose |
|---|---|---|
| search_content | read:content | Ranked search across content. |
| list_documents | read:content | List content with type, language, and status filters. |
| get_document | read:content | Fetch a single document by slug, URL, or id. |
| get_navigation | read:content | Read navigation menus and the published page index. |
| get_project_documentation | read:docs | List or read project documentation files. |
| get_api_documentation | read:docs | Read the API documentation definition. |
| get_theme_manifest | read:themes | Read a theme manifest. |
| get_theme_security_report | read:themes | Read the external asset and CSP report. |
| validate_theme | read:themes | Validate a theme without applying changes. |
| list_plugins | read:plugins | List installed plugins and their status. |
| get_plugin_status | read:plugins | Read a plugin health and diagnostics report. |
| get_runtime_health | read:ops | Read runtime health and readiness. |
| validate_configuration | read:ops | Validate config, theme, and site graph. |
Resource templates
| URI template | Scope |
|---|---|
| foundry://content/pages/{slug} | read:content |
| foundry://content/collections/{type} | read:content |
| foundry://themes/{name}/manifest | read:themes |
| foundry://themes/{name}/security-report | read:themes |
| foundry://plugins | read:plugins |
| foundry://runtime/health | read:ops |
| foundry://docs/{path...} | read:docs |
Capability schemas and stable names
Every capability is registered with a stable name, a version, an input schema, an output
schema, a read-only or mutating classification, a required scope, an optional owning
plugin, an audit category, a timeout, a result-size limit, and a default-enabled state.
Names are namespaced: core capabilities use plain snake_case names such as
search_content, and plugin capabilities are prefixed with the plugin name,
for example myplugin_reports.
Representative input schemas:
search_content
{
"type": "object",
"properties": {
"query": { "type": "string" },
"type": { "type": "string" },
"lang": { "type": "string" },
"limit": { "type": "integer" },
"cursor": { "type": "string" }
},
"required": ["query"]
}
get_document
{
"type": "object",
"properties": {
"slug": { "type": "string" },
"url": { "type": "string" },
"id": { "type": "string" }
}
}
get_plugin_status
{
"type": "object",
"properties": { "name": { "type": "string" } },
"required": ["name"]
}
Names and schemas are part of the public contract. Renaming a capability or removing a field is a breaking change; add a new version instead.
Plugin-provided capabilities
Plugin-provided MCP capabilities are planned after the core read-only contract is stable. The registry already reserves the namespace and governance hooks for them, and the intent is that a plugin capability must:
- Use the
foundry-plugin://scheme and a plugin-namespaced capability name. - Declare input and output schemas, required plugin permissions, and a read-only or mutating classification.
- Declare an audit category and risk level.
- Be listed in the admin UI and be independently enabled or disabled.
- Execute inside the plugin's existing permission boundary, under the same timeout, rate, and response-size controls as core capabilities.
A plugin never gains filesystem, network, admin, or runtime privileges simply because it registers an MCP capability. Until plugin registration ships, only the core read-only capabilities in this guide are exposed.
Scopes and authorization
MCP scopes map onto existing Foundry capabilities. A scope that is not enabled is denied by default, and an authenticated actor must also hold a matching Foundry capability.
| MCP scope | Foundry capability |
|---|---|
| read:content | documents.read |
| read:docs | dashboard.read |
| read:themes | themes.manage |
| read:plugins | plugins.manage |
| read:ops | dashboard.read |
| write:content | documents.write |
| publish:content | documents.publish |
| manage:plugins | plugins.manage |
| manage:themes | themes.manage |
Local process access is not the same as authenticated access. The stdio server runs as a local actor and only exposes the scopes enabled in configuration.
Redaction and limits
- Responses are redacted for sensitive keys such as passwords, password hashes, session and access tokens, API keys, private keys, and connection strings.
- List and search operations are bounded: default page size 20, maximum 100.
- Every capability has an execution timeout (default 10 seconds) and a maximum result size (default 256 KiB).
- Oversized responses return an explicit error instead of streaming unbounded data.
- Request payloads over 8 MiB on the stdio transport are rejected before dispatch.
- Requests are checked against a per-client rate limit and a concurrency cap; over-limit requests are rejected rather than queued.
Disabling MCP
Remove the mcp block or set mcp.enabled to false. The
foundry mcp serve command then refuses to start, and no MCP capabilities are
exposed.
Protocol revision
Foundry pins MCP protocol revision 2026-07-28 and also accepts
2025-06-18 during initialization. The negotiated revision is reported in the
initialize response.
Roadmap
Authenticated Streamable HTTP transport, mutating tools (with explicit opt-in, confirmation, idempotency, and before/after auditing), and plugin-provided capabilities are planned after the read-only contract is reviewed and tested.
