MCP Support
MCP support is part of the current harness path, but two different layers matter:
workspace.yamldefines the MCP policy boundary for the run- the harness host may still discover concrete tool catalogs from the connected MCP servers at runtime
Where Workspace-Level MCP Lives
Workspace-level MCP servers are authored in workspace.yaml under mcp_registry.
Remote server example with an explicit allowlist:
mcp_registry:
servers:
context7:
type: remote
url: https://mcp.context7.com/mcp
enabled: true
timeout_ms: 30000
headers:
CONTEXT7_API_KEY: "{env:CONTEXT7_API_KEY}"
allowlist:
tool_ids:
- context7.lookup
- context7.searchFor Context7, the header value must be either:
- a literal API key such as
ctx7sk-... - or an environment placeholder whose contents are the environment variable name, such as
{env:CONTEXT7_API_KEY}
Do not wrap the literal key in placeholder syntax. This is invalid:
headers:
CONTEXT7_API_KEY: "{env:ctx7sk-...}"That shape does not reference an environment variable. It sends a placeholder-shaped string to the remote MCP server instead of the actual API key.
Explicit tool ids apply to the servers named by those ids. Other enabled configured servers can still remain discoverable for the run when they have no explicit tool refs.
Remote server example that allows all discovered tools from the configured server:
mcp_registry:
servers:
context7:
type: remote
url: https://mcp.context7.com/mcp
enabled: true
timeout_ms: 30000An empty allowlist has the same meaning:
mcp_registry:
servers:
context7:
type: remote
url: https://mcp.context7.com/mcp
enabled: true
allowlist:
tool_ids: []What the Runtime Does First
Before the harness runs, the runtime:
- prepares MCP server payloads
- resolves
{env:ENV_VAR_NAME}placeholders in remote MCP headers and environment values - rejects placeholder-shaped literals such as
{env:ctx7sk-...}with a config error before the run starts - starts the workspace MCP sidecar when needed
- resolves MCP tool refs when
mcp_registry.allowlist.tool_idsis present and non-empty - passes the prepared
mcp_serversand any resolvedmcp_tool_refsinto the host request - carries connected MCP server ids into the runtime config so prompt and capability projection can distinguish
no MCP serverfromconnected server with runtime discovery
That means the runtime decides which part of the MCP graph is visible for this run.
What the Host Does Next
The harness host then:
- builds MCP bindings from the prepared server payloads
- discovers tools from those configured servers
- restricts servers that have explicit
mcp_tool_refsto that subset - exposes all discovered tools for configured servers that do not have explicit
mcp_tool_refs
This keeps MCP visibility policy inside the runtime while still allowing a workspace to mix both modes in one run: explicitly constrained servers and unrestricted discovered servers.
What the Agent Sees
There are two valid MCP shapes at run start:
- explicit allowlist present: the runtime resolves concrete
mcp_tool_refs, so the capability manifest and prompt can name those tools directly - allowlist omitted or empty: the runtime still passes the connected
mcp_servers, but concrete remote tool names may not be pre-enumerated yet; the host discovers them at runtime and exposes all discovered tools from those servers
A mixed workspace is also valid:
- some servers have explicit
mcp_tool_refsand stay constrained to those tools - other configured servers have no explicit refs and stay discoverable-all for that run
In the second case, the prompt should not claim MCP is unavailable. It may summarize connected MCP server ids even when concrete tool names are discovered later in the host.
The enforcement boundary is still the actual tool registry materialized by the host for that run, not the prose in the prompt.
When Changes Take Effect
The runtime compiles workspace.yaml at run start. If you add or edit a remote MCP server during one run, the updated server configuration is ready on the next run, not retroactively inside the already running harness session.
Current Boundary
MCP is one of the most important capability surfaces in holaOS, so it needs a stable policy boundary:
- runtime resolves configured MCP servers for the run
- runtime resolves explicit MCP tool refs when allowlisted tool ids exist for a server
- runtime may carry only MCP server ids, not pre-enumerated tool ids, when the allowlist is omitted
- host materializes the resolved subset for servers with explicit refs and all discovered tools for servers without them
- harness consumes the projected tool surface
That split is what keeps MCP support compatible with multiple harnesses later.