Starphix
Agentic Engineering / Sources
The Lab / Sources / Agentic Engineering / Harness/Core-Components/Tool-Registry.md

Tool Registry

The tool registry is the catalog of all capabilities available to the agent. It's responsible for defining, discovering, validating, and executing tools safely.

Purpose

  • Discovery: Tell the model what tools are available
  • Definition: Provide schemas so the model knows how to call them
  • Validation: Ensure tool calls are well-formed
  • Execution: Run tools with proper error handling
  • Security: Enforce permissions and sandboxing
  • Extensibility: Support built-in tools and MCP servers

Tool Definition Structure

Every tool needs a clear definition:

interface Tool {
  name: string;           // Unique identifier (e.g., "read_file")
  description: string;    // Clear description for the model
  parameters: JSONSchema; // Input schema
  category: string;       // Grouping (filesystem, shell, search, etc.)
  requiresPermission: boolean;
  riskLevel: 'low' | 'medium' | 'high';
  execute: (args: any, context: ToolContext) => Promise<ToolResult>;
}

Tool Schema Design

Good tool schemas help the model call tools correctly:

{
  "name": "read_file",
  "description": "Read the contents of a file. Returns the file content as text.",
  "parameters": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Absolute or relative path to the file"
      },
      "offset": {
        "type": "number",
        "description": "Line number to start from (1-based)"
      },
      "limit": {
        "type": "number", 
        "description": "Maximum number of lines to read"
      }
    },
    "required": ["path"]
  }
}

Tool Categories

Category Examples Risk Level Notes
Read read_file, glob, grep, search Low Generally safe, read-only
Write/Edit write_file, edit, str_replace Medium Modify files, need care
Execute bash, run_command High Shell access, most dangerous
Navigate cd, list_dir Low Directory operations
Git git_status, git_diff, git_commit Medium-High Version control changes
Web webfetch, websearch Medium Network access
Browser browser_navigate, browser_click High Full browser control
MCP Dynamic from servers Varies Depends on server

Registry Implementation

class ToolRegistry:
    def __init__(self):
        self.tools = {}
        self.categories = {}

    def register(self, tool: Tool):
        self.tools[tool.name] = tool
        self.categories.setdefault(tool.category, []).append(tool.name)

    def get(self, name: str) -> Tool | None:
        return self.tools.get(name)

    def get_schemas_for_model(self, allowed_tools=None) -> list:
        """Return tool schemas in model's expected format"""
        tools = self.tools.values()
        if allowed_tools:
            tools = [t for t in tools if t.name in allowed_tools]
        return [self._format_schema(t) for t in tools]

    async def execute(self, name: str, args: dict, context: ToolContext):
        tool = self.get(name)
        if not tool:
            raise ToolNotFoundError(name)
        # Validate args against schema
        validate(args, tool.parameters)
        # Check permissions
        await context.permission_checker.check(tool, args)
        # Execute with timeout
        return await asyncio.wait_for(tool.execute(args, context), timeout=300)

Tool Context

Tools need access to harness capabilities:

interface ToolContext {
  sessionId: string;
  workingDirectory: string;
  permissionChecker: PermissionChecker;
  sandbox: Sandbox;
  logger: Logger;
  abortSignal?: AbortSignal;
  userId?: string;
}

Built-in Tool Examples

Filesystem Tools

@tool(name="read_file", category="filesystem", risk_level="low")
async def read_file(args, ctx):
    path = resolve_path(args["path"], ctx.workingDirectory)
    content = await ctx.sandbox.read_file(path)
    return {"content": content, "path": path}

Shell Tool

@tool(name="bash", category="shell", risk_level="high", requiresPermission=True)
async def bash(args, ctx):
    command = args["command"]
    # Permission check will handle approval
    result = await ctx.sandbox.execute_shell(command, timeout=args.get("timeout", 120))
    return {"stdout": result.stdout, "stderr": result.stderr, "exitCode": result.exitCode}

Search Tools

@tool(name="grep", category="search", risk_level="low")
async def grep(args, ctx):
    pattern = args["pattern"]
    path = args.get("path", ctx.workingDirectory)
    results = await ctx.sandbox.grep(pattern, path, args.get("include"))
    return {"matches": results}

MCP Integration

The registry should also support tools from MCP servers:

class MCPToolAdapter:
    def __init__(self, server_name: str, tool_def: MCPTool):
        self.server_name = server_name
        self.name = f"{server_name}__{tool_def.name}"  # Namespaced
        self.description = tool_def.description
        self.parameters = tool_def.inputSchema

    async def execute(self, args, ctx):
        return await ctx.mcp_client.call_tool(
            self.server_name, 
            self.original_name, 
            args
        )

Best Practices

Tool Design

  1. Clear descriptions - Tell the model when to use the tool and what it does
  2. Minimal parameters - Fewer required params = fewer mistakes
  3. Good defaults - Make common cases easy
  4. Consistent naming - Use verb_noun pattern (read_file, run_command)
  5. Return useful info - Include enough context for next steps

Registry Design

  1. Lazy loading - Load MCP tools on demand
  2. Tool filtering - Show only relevant tools based on context
  3. Validation - Validate schemas at registration time
  4. Error messages - Clear errors when tools fail or aren't found
  5. Namespacing - Avoid collisions between built-in and MCP tools

Security

  1. Permission gates - High-risk tools need approval
  2. Input validation - Sanitize paths, commands
  3. Path restrictions - Don't allow escaping working directory
  4. Command filtering - Block dangerous shell patterns
  5. Audit logging - Log all tool executions

Tool Result Format

Consistent result format helps the model understand outcomes:

interface ToolResult {
  success: boolean;
  output?: any;      // Main result data
  error?: string;    // Error message if failed
  metadata?: {
    duration: number;
    truncated?: boolean;
    [key: string]: any;
  };
}
  • Permission System — Security and approvals
  • Function Calling — Model tool calling
  • MCP Protocol — MCP integration
  • Error Recovery — Handling tool failures
  • Filesystem Integration — Filesystem tools

Sources

  • OpenAI Function Calling documentation
  • Anthropic Tool Use documentation
  • MCP Specification
  • LangChain Tools
  • OpenCode tool implementations

From the Agentic Engineering research vault · CC BY 4.0 · all notes · raw markdown