Local tools
Combine reviewed MCP tools with local tools when application-owned permissions, transactions, approval, or side effects must remain inside the product boundary.
1. Register both sources
const agent = new Agent({
id: 'operations',
model,
mcpServers: [runbookServer, monitoringServer],
tools: [
createIncidentTool(scope),
createApprovalStatusTool(scope),
],
maxTurns: 6,
})Both sources appear in the same model-facing tool set and use the normal agent loop.
Use MCP tools for reviewed remote lookup or constrained remote capability. Use local tools for product authorization, database writes, application approval, idempotency, and transactions.
2. Register an allow-listed subset
const allowed = new Set(['search_docs', 'read_doc'])
const docsSubset = docsServer.tools.filter((tool) => allowed.has(tool.name))
const agent = new Agent({
id: 'support',
model,
mcpServers: [{ name: docsServer.name, tools: docsSubset }],
tools: [createCustomerLookupTool(scope), createTicketTool(scope)],
})MCP tools cannot be mixed into tools; construction rejects them. Filter the server snapshot and register the { name, tools } subset through mcpServers, so unreviewed remote capability stays unexposed while local tools keep their own registration.
3. Keep routing distinct
Names and descriptions should distinguish external lookup from product action. Prefer search_runbooks and create_incident over two tools described as “handle incidents.”
Check collisions across every local, MCP, and skill source before constructing the agent.
4. Keep lifecycle ownership outside the agent
The agent does not close MCP servers. The application that connected them must close them during shutdown or job cleanup, even when an agent run fails.
Local tool dependencies have their own application lifecycle and do not change MCP connection ownership.
Next, add observability.