Tools & MCP
Agents need tools to interact with the world. cycgraph uses structured tool sources and the Model Context Protocol (MCP) for secure, standardized tool integration. This decouples the agent definition from the underlying transport configuration and connection secrets.
Tool source types
Section titled “Tool source types”Agents declare their tools using a ToolSource[] array with two possible types:
- Built-in tools: Provided by the orchestrator itself. No external connection needed.
- MCP tools: Provided by a registered MCP server. References the server by ID.
import { InMemoryAgentRegistry } from '@cycgraph/orchestrator';
const agentRegistry = new InMemoryAgentRegistry();
const RESEARCH_AGENT = agentRegistry.register({ name: 'Research Specialist', model: 'claude-sonnet-4-20250514', provider: 'anthropic', system_prompt: 'You are a research specialist...', tools: [ { type: 'builtin', name: 'save_to_memory' }, { type: 'mcp', server_id: 'web-search' } ],});// Single-key agent — no save_to_memory neededconst WRITER = agentRegistry.register({ name: 'Writer', model: 'claude-sonnet-4-20250514', provider: 'anthropic', system_prompt: 'You write clear summaries.', tools: [], permissions: { read_keys: ['notes'], write_keys: ['draft'] },});Optionally, you can filter to specific tools from an MCP server by providing tool_names:
{ type: 'mcp', server_id: 'web-search', tool_names: ['search', 'fetch']}Node-level tool overrides
Section titled “Node-level tool overrides”Graph nodes can override an agent’s configured tools for a specific execution step. This lets you reuse the same general-purpose agent with different contextual tool sets throughout a graph.
{ id: 'initial-research', type: 'agent', agent_id: RESEARCH_AGENT, tools: [ { type: 'builtin', name: 'save_to_memory' }, { type: 'mcp', server_id: 'web-search' }, { type: 'mcp', server_id: 'twitter-search' } ], read_keys: ['goal'], write_keys: ['initial_notes'],}In this example, save_to_memory is included because the node may need to write structured data to multiple keys. For nodes that write to a single key, you can omit it — the orchestrator captures text output automatically.
MCP Server Registry
Section titled “MCP Server Registry”The trusted MCP Server Registry holds transport configurations and connection secrets. This is the security boundary — agents reference servers by ID, but never see connection details.
Registering servers
Section titled “Registering servers”import { InMemoryMCPServerRegistry } from '@cycgraph/orchestrator';
const mcpRegistry = new InMemoryMCPServerRegistry();
// HTTP transportmcpRegistry.register({ id: 'web-search', name: 'Web Search', description: 'Search the web via Brave Search API', transport: { type: 'http', url: 'https://mcp.example.com/web-search', headers: { 'Authorization': `Bearer <API_KEY>`, }, },});
// Stdio transport (local MCP server)mcpRegistry.register({ id: 'code-executor', name: 'Code Executor', transport: { type: 'stdio', command: 'npx', args: ['-y', '@mcp/code-sandbox'], env: { SANDBOX_TIMEOUT: '30000' }, },});
// SSE transportmcpRegistry.register({ id: 'slack-tools', name: 'Slack Integration', transport: { type: 'sse', url: 'https://mcp.example.com/slack/sse', }, timeout_ms: 60_000,});(Note: For production environments, use DrizzleMCPServerRegistry from @cycgraph/orchestrator-postgres to store server configurations durably in the database.)
Transport types
Section titled “Transport types”| Transport | Use case | Security |
|---|---|---|
stdio | Local MCP server processes | Command allowlist: npx, node, python3, python, uvx |
http | Remote MCP servers (stateless) | HTTPS URLs only in production |
sse | Remote MCP servers (streaming) | HTTPS URLs only in production |
Each MCPServerEntry also supports the following optional fields:
| Field | Type | Default | Description |
|---|---|---|---|
timeout_ms | number | — | Connection-level timeout for the MCP transport |
tool_timeout_ms | number | — | Per-tool-call execution timeout (overrides manager default) |
max_retries | number | 2 | Number of connection retry attempts with exponential backoff |
allowed_agents | string[] | — | Restrict which agents can access this server |
Access control
Section titled “Access control”You can restrict which agents are allowed to use a specific server with the allowed_agents field:
mcpRegistry.register({ id: 'admin-tools', name: 'Admin Tools', transport: { type: 'http', url: 'https://internal.example.com/admin' }, allowed_agents: ['admin-agent-001', 'ops-agent-002'],});When allowed_agents is set, only the listed agents can resolve tools from that server. Omit the field for unrestricted access.
Connection resilience
Section titled “Connection resilience”The MCPConnectionManager includes built-in resilience features for production reliability:
Connection retry with backoff: Failed connections are automatically retried with exponential backoff. Configure max_retries on each server entry (default: 2):
mcpRegistry.register({ id: 'web-search', name: 'Web Search', transport: { type: 'http', url: 'https://mcp.example.com/search' }, max_retries: 3, // Retry up to 3 times with backoff (1s, 2s, 4s)});Per-tool execution timeouts: Set tool_timeout_ms on the server entry to enforce a timeout on each individual tool call. This prevents hung tools from blocking the entire workflow:
mcpRegistry.register({ id: 'slow-api', name: 'External API', transport: { type: 'http', url: 'https://api.example.com/mcp' }, tool_timeout_ms: 10_000, // 10 second timeout per tool call});You can also set a default timeout for all servers via MCPConnectionManagerOptions:
const manager = new MCPConnectionManager(mcpRegistry, { default_tool_timeout_ms: 30_000, // 30s default for all servers});Server-level tool_timeout_ms overrides the default.
Tool manifest caching: Tool manifests from MCP servers are cached for 5 minutes by default, avoiding redundant client.tools() calls. Configure via cache_ttl_ms:
const manager = new MCPConnectionManager(mcpRegistry, { cache_ttl_ms: 600_000, // 10 minute cache TTL});Set to 0 to disable caching.
Manual reconnection: Use manager.reconnect(serverId) to invalidate a stale connection and force a fresh reconnection on the next resolveTools() call.
Taint tracking
Section titled “Taint tracking”All results returned from MCP tools are automatically taint-tracked. The raw tool result is returned directly to the LLM (no wrapper), while taint metadata is accumulated internally by the MCPConnectionManager. After agent execution completes, taint entries are drained via drainTaintEntries() and applied to any memory keys that received MCP tool results.
This design ensures:
- The LLM sees clean results — no taint metadata leaks into the model’s context
- The taint registry is accurate — provenance is tracked in
memory._taint_registry - The tool node executor also correctly handles taint for
tool-type nodes
See Taint Tracking for the full taint propagation model and API reference.
Default MCP servers
Section titled “Default MCP servers”cycgraph includes pre-configured entries for two common MCP reference servers. Use registerDefaultMCPServers() for one-line setup:
import { InMemoryMCPServerRegistry, registerDefaultMCPServers, MCPConnectionManager,} from '@cycgraph/orchestrator';
const mcpRegistry = new InMemoryMCPServerRegistry();await registerDefaultMCPServers(mcpRegistry);// Registers: web-search (Brave Search via npx) and fetch (URL content via uvx)| Server ID | Package | Command | Requires |
|---|---|---|---|
web-search | @modelcontextprotocol/server-brave-search | npx | BRAVE_API_KEY env var |
fetch | mcp-server-fetch (Python) | uvx | uv package manager |
Options for selective registration:
// Only fetch (no web search)await registerDefaultMCPServers(mcpRegistry, { only: ['fetch'] });
// Override the Brave API keyawait registerDefaultMCPServers(mcpRegistry, { brave_api_key: 'BSA-...' });
// Restrict to specific agentsawait registerDefaultMCPServers(mcpRegistry, { allowed_agents: [RESEARCHER_ID] });Next steps
Section titled “Next steps”- Adding MCP Tools — wiring tools into the execution pipeline and building custom MCP servers
- Agents — how agents use tools
- Nodes — node-level tool overrides
- Security — access control and taint tracking