Manifest Auto-Attach
The simplest way to give an agent access to MCP tools is to declare the servers in its manifest. agentd attaches them automatically at spawn time, with no separate ash mcp attach command needed.
Declaring servers in a manifest
Add a mcp_servers list to spec:
apiVersion: scarab/v1
kind: AgentManifest
metadata:
name: research-agent
version: 1.0.0
spec:
trust_level: trusted
capabilities:
- tool.invoke:lm.complete
- tool.invoke:mcp.github.*
- tool.invoke:mcp.search.*
mcp_servers:
- name: github
transport: Stdio
command: /usr/local/bin/github-mcp
args: ["--read-only"]
env_template:
- ["GITHUB_TOKEN", "{{secret:github-token}}"]
description: "GitHub read-only MCP tools"
- name: search
transport: Http
url: https://search-mcp.internal/api
description: "Internal search server"
mcp_servers fields
| Field | Type | Description |
|---|---|---|
name | string | Unique server name; tools are namespaced as mcp.<name>.<tool> |
transport | Stdio | Http | Connection mechanism |
command | string (Stdio) | Path to executable |
args | string[] (Stdio) | Arguments passed to the executable |
url | string (Http) | Base URL for the HTTP endpoint |
env_template | [[key, value]] | Environment variables; values may use {{secret:<name>}} |
description | string | Optional human-readable description |
Capabilities and MCP tools
An agent must declare tool.invoke:mcp.<server-name>.* (or a specific tool pattern) in its capabilities to call the attached tools.
capabilities:
- tool.invoke:mcp.github.list_prs # specific tool
- tool.invoke:mcp.search.* # all tools from a server
- tool.invoke:mcp.* # all MCP tools (broad)
Without the matching tool.invoke capability, the agent can see the tools in ToolList but invocation is denied.
Spawn sequence with auto-attach
When agentd spawns an agent from a manifest containing mcp_servers:
- Agent process is created and enters the
Initstate. - For each entry in
mcp_servers, agentd runs the attach sequence:- Stdio: spawns subprocess, completes JSON-RPC handshake, calls
tools/list. - HTTP: connects, completes handshake, calls
tools/list.
- Stdio: spawns subprocess, completes JSON-RPC handshake, calls
- Discovered tools are registered as
mcp.<name>.<tool>in the agent'sToolRegistry. - Agent transitions to
Plan.
If an MCP server fails to attach at spawn time, the error is recorded in the audit log and the agent continues without those tools.
Pre-approval policy for secrets in env_template
If env_template references secrets, a matching pre-approval policy must exist:
spec:
secret_policy:
- label: "GitHub token for MCP"
secret_pattern: "github-token"
tool_pattern: "*" # resolved at attach, not per tool-invoke
Or register the policy at runtime before spawning:
ash secrets policy add \
--label "GitHub MCP" \
--secret "github-token" \
--tool "*"
Using auto-attached tools in agent code
Auto-attached tools are available as soon as the agent starts. Use the standard invoke_tool API:
#![allow(unused)] fn main() { let result = agent.invoke_tool( "mcp.github.list_prs", serde_json::json!({ "repo": "anomalyco/opencode", "state": "open" }), ).await?; }