- Tighten positioning, lift demo, sharpen comparison table. - Refresh temodar star count, drop dead link. - Fold tool/memory/context sections into docs/. - Swap npm downloads badge for GitHub forks. - Correct custom context strategy signature and Copilot env var (README, README_zh, docs/context-management.md). - Inline agent definitions so quick-start snippet is self-contained. - Move CONTRIBUTING/CODE_OF_CONDUCT/SECURITY/codecov to .github/, DECISIONS.md to docs/. - Fix CONTRIBUTING README link after the .github/ move. - Ignore local .claude/ config dir.
4.8 KiB
Tool Configuration
Agents can be configured with fine-grained tool access control using presets, allowlists, and denylists.
Tool Presets
Predefined tool sets for common use cases:
const readonlyAgent: AgentConfig = {
name: 'reader',
model: 'claude-sonnet-4-6',
toolPreset: 'readonly', // file_read, grep, glob
}
const readwriteAgent: AgentConfig = {
name: 'editor',
model: 'claude-sonnet-4-6',
toolPreset: 'readwrite', // file_read, file_write, file_edit, grep, glob
}
const fullAgent: AgentConfig = {
name: 'executor',
model: 'claude-sonnet-4-6',
toolPreset: 'full', // file_read, file_write, file_edit, grep, glob, bash
}
Advanced Filtering
Combine presets with allowlists and denylists for precise control:
const customAgent: AgentConfig = {
name: 'custom',
model: 'claude-sonnet-4-6',
toolPreset: 'readwrite', // Start with: file_read, file_write, file_edit, grep, glob
tools: ['file_read', 'grep'], // Allowlist: intersect with preset = file_read, grep
disallowedTools: ['grep'], // Denylist: subtract = file_read only
}
Resolution order: preset → allowlist → denylist → framework safety rails.
Custom Tools
Two ways to give an agent a tool that is not in the built-in set.
Inject at config time via customTools on AgentConfig. Good when the orchestrator wires up tools centrally. Tools defined here bypass preset/allowlist filtering but still respect disallowedTools.
import { defineTool } from '@jackchen_me/open-multi-agent'
import { z } from 'zod'
const weatherTool = defineTool({
name: 'get_weather',
description: 'Look up current weather for a city.',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => ({ data: await fetchWeather(city) }),
})
const agent: AgentConfig = {
name: 'assistant',
model: 'claude-sonnet-4-6',
customTools: [weatherTool],
}
Register at runtime via agent.addTool(tool). Tools added this way are always available, regardless of filtering.
Tool Output Control
Long tool outputs can blow up conversation size and cost. Two controls work together.
Validation (optional). Add outputSchema to catch malformed tool results before they are forwarded:
Note — two different
outputSchemafields. The one ondefineTool()/ToolDefinition(shown below) validates a single tool'sToolResult.data— it is always aZodSchema<string>because tool output is serialised as text. TheoutputSchemaonAgentConfigis different: it validates the agent's final answer as parsed JSON against an arbitrary Zod schema (see Structured output inexamples/). Different types, different scopes — TypeScript won't warn you if you mix them up, so pick the one that matches the layer you're working at.
const jsonTool = defineTool({
name: 'json_tool',
description: 'Return JSON payload as string.',
inputSchema: z.object({}),
outputSchema: z.string().refine((value) => {
try {
JSON.parse(value)
return true
} catch {
return false
}
}, 'Output must be valid JSON'),
execute: async () => ({ data: '{"ok": true}' }),
})
Truncation. Cap an individual tool result to a head + tail excerpt with a marker in between:
const agent: AgentConfig = {
// ...
maxToolOutputChars: 10_000, // applies to every tool this agent runs
}
// Per-tool override (takes priority over AgentConfig.maxToolOutputChars):
const bigQueryTool = defineTool({
// ...
maxOutputChars: 50_000,
})
Post-consumption compression. Once the agent has acted on a tool result, compress older copies in the transcript so they stop costing input tokens on every subsequent turn. Error results are never compressed.
const agent: AgentConfig = {
// ...
compressToolResults: true, // default threshold: 500 chars
// or: compressToolResults: { minChars: 2_000 }
}
MCP Tools (Model Context Protocol)
open-multi-agent can connect to any MCP server and expose its tools directly to agents.
import { connectMCPTools } from '@jackchen_me/open-multi-agent/mcp'
const { tools, disconnect } = await connectMCPTools({
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-github'],
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN },
namePrefix: 'github',
})
// Register each MCP tool in your ToolRegistry, then include their names in AgentConfig.tools
// Don't forget cleanup when done
await disconnect()
Notes:
@modelcontextprotocol/sdkis an optional peer dependency, only needed when using MCP.- Current transport support is stdio.
- MCP input validation is delegated to the MCP server (
inputSchemaisz.any()).
See integrations/mcp-github for a full runnable setup.