AI

CCA-F Study Day 9/20: Built-in Tools & Tool Distribution

Domain 2: Tool Design & MCP Integration (~18-20% of exam)


๐Ÿ“Œ Today's Focus

Yesterday you mastered MCP architecture โ€” the Hostโ†’Clientโ†’Server layering, the two protocol layers, and the three primitives. Today we complete Domain 2 by covering Claude's built-in tools, how to distribute tools across agents, and the critical rules around parallel vs sequential execution. This material directly feeds the "Developer Productivity with Claude" exam scenario โ€” one of the six scenarios you might encounter.

This is the last day of Domain 2. After today, you'll have covered all tool design and MCP integration concepts. Tomorrow we move to Domain 3 (Claude Code Configuration).


๐Ÿ“š Core Concepts

1. Claude's Built-in Tools (The Full Reference)

Claude Code ships with a suite of built-in tools that give it "access to a computer." The key design principle from Anthropic: "Claude needs the same tools that programmers use every day."

Tool Category What It Does Read-Only?
Read File ops Read file contents โœ… Yes
Edit File ops Modify existing files (surgical edits) โŒ No
Write File ops Create new files โŒ No
Glob Search Find files by pattern (e.g., **/*.py) โœ… Yes
Grep Search Search file content with regex โœ… Yes
Bash Execution Run shell commands โŒ No
WebSearch Web Search the web for information โœ… Yes
WebFetch Web Fetch and parse web pages โœ… Yes
Agent Orchestration Spawn subagents with isolated context โŒ No
Skill Orchestration Invoke reusable skills โŒ No
ToolSearch Discovery Dynamically find tools on-demand โœ… Yes

Exam tip: Know the full list. Expect questions like "Which tool would Claude use to find all Python files matching a pattern?" (Answer: Glob) or "Which tool searches file content?" (Answer: Grep).

2. Parallel vs Sequential Tool Execution โ€” THE Critical Rule

This is a high-frequency exam topic. The rules are simple but you MUST know them cold:

Tool Type Execution Reason
Read-only (Read, Glob, Grep, WebSearch, WebFetch, read-only MCP tools) Can run concurrently(in parallel) No state conflicts possible
State-modifying (Edit, Write, Bash) Must run sequentially Concurrent writes could cause conflicts
Custom tools (via MCP or tool definitions) Default to sequential Conservative default

The escape hatch for custom tools: Set readOnlyHint: true in the tool's annotations to enable parallel execution:

{
  "name": "get_stock_price",
  "description": "Fetches current stock price for a ticker symbol",
  "annotations": {
    "readOnlyHint": true  // โ† This enables parallel execution
  },
  "input_schema": {
    "type": "object",
    "properties": {
      "ticker": {"type": "string"}
    }
  }
}

3. Tool Distribution Patterns

How you distribute tools across agents is an architectural decision with major implications:

Pattern A: Monolithic (Anti-Pattern for complex systems)

# โŒ DON'T: 15+ tools on one agent
agent = Agent(
    tools=[search_files, read_file, write_file, run_tests, 
           deploy, search_web, send_email, query_db, 
           manage_git, lint_code, format_code, ...]  # 15+ tools = confusion
)

Pattern B: Distributed Specialist Agents (โœ… Recommended)

# โœ… DO: 4-5 tools per specialist agent
file_agent = Agent(
    tools=[read_file, write_file, edit_file, glob_files, grep_content]
)

test_agent = Agent(
    tools=[run_tests, lint_code, check_coverage, format_code]
)

deploy_agent = Agent(
    tools=[build_project, deploy_staging, deploy_prod, rollback]
)

# Coordinator delegates to specialists
coordinator = Agent(
    tools=[delegate_to_file_agent, delegate_to_test_agent, delegate_to_deploy_agent]
)

The 4-5 tool sweet spot: Anthropic's research shows that Claude performs optimally with 4-5 tools per agent. Beyond ~8 tools, selection accuracy degrades. Beyond 15+, it becomes unreliable.

4. MCP Server Configuration for Tool Distribution

In production, tools are distributed across MCP servers. Each server is isolated (own process, own permissions):

# .claude/mcp.json - MCP configuration
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-server-filesystem", "/workspace"],
      "annotations": {
        "readOnlyHint": true
      }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "database": {
      "command": "python",
      "args": ["./mcp_servers/db_server.py"],
      "annotations": {
        "readOnlyHint": false
      }
    }
  }
}

5. Built-in Tools for the Developer Productivity Scenario

The exam's "Developer Productivity with Claude" scenario tests your ability to select the right tools for codebase exploration tasks. Here's the decision framework:

Task Best Tool Why NOT the Alternative
Find all files matching *.test.ts Glob Grep searches content, not filenames
Find all usages of deprecated_function() Grep Glob only matches filenames, not content
Read a specific config file Read Bash is overkill; Read is purpose-built
Run a test suite Bash No specific "test runner" built-in tool exists
Install a dependency Bash Write doesn't execute commands
Search the web for API docs WebSearch Bash + curl works but is less structured
Explore a large codebase structure Glob then Read Pattern: discover โ†’ inspect

โš ๏ธ Anti-Patterns & Exam Traps

Trap 1: "Use Bash for everything"

โŒ Wrong: "Use Bash to read files, search code, and find files" โœ… Right: Use the purpose-built tool (Read, Grep, Glob) โ€” they have better error handling, are faster, and enable parallel execution for read-only operations.

Why it's tested: Bash is a state-modifying tool that runs sequentially. Using Bash for read-only tasks means you lose parallelism.

Trap 2: "More tools = more capable agent"

โŒ Wrong: Give one agent 18 tools for maximum flexibility โœ… Right: 4-5 tools per agent, distribute across specialist subagents

Why it's wrong: Tool selection accuracy degrades significantly beyond 8 tools. The model wastes reasoning capacity deciding between too many options.

Trap 3: "Custom MCP tools can always run in parallel"

โŒ Wrong: All MCP tools execute concurrently by default โœ… Right: Custom tools default to sequential. You must explicitly set readOnlyHint: true in annotations for parallel execution.

Trap 4: "Grep and Glob are interchangeable"

โŒ Wrong: Use Grep to find files matching *.py โœ… Right: Glob matches file paths/names. Grep matches file content.

Trap 5: Confusing Edit vs Write

โŒ Wrong: Use Write to modify an existing file โœ… Right: Edit = modify existing files (surgical changes). Write = create new files.


๐Ÿ’ป Code Examples

Example 1: Codebase Exploration Agent with Correct Tool Selection

import anthropic

client = anthropic.Anthropic()

# Developer Productivity agent with well-distributed tools
tools = [
    {
        "name": "glob_files",
        "description": "Find files matching a glob pattern. Use for discovering files by name/path/extension. Returns list of matching file paths.",
        "input_schema": {
            "type": "object",
            "properties": {
                "pattern": {
                    "type": "string",
                    "description": "Glob pattern (e.g., '**/*.py', 'src/**/*.test.ts')"
                }
            },
            "required": ["pattern"]
        }
    },
    {
        "name": "grep_content",
        "description": "Search file content using regex. Use when looking for specific code patterns, function usages, or text within files. Returns matching lines with file paths and line numbers.",
        "input_schema": {
            "type": "object",
            "properties": {
                "pattern": {
                    "type": "string",
                    "description": "Regex pattern to search for in file content"
                },
                "file_pattern": {
                    "type": "string",
                    "description": "Optional: limit search to files matching this glob (e.g., '*.py')"
                }
            },
            "required": ["pattern"]
        }
    },
    {
        "name": "read_file",
        "description": "Read the full contents of a file. Use after discovering files via glob or grep to inspect their content.",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {
                    "type": "string",
                    "description": "Path to the file to read"
                }
            },
            "required": ["path"]
        }
    },
    {
        "name": "run_bash",
        "description": "Execute a shell command. Use for running tests, installing packages, git operations, or any command-line task that modifies state.",
        "input_schema": {
            "type": "object",
            "properties": {
                "command": {
                    "type": "string",
                    "description": "The bash command to execute"
                }
            },
            "required": ["command"]
        }
    }
]

# Task: "Find and fix all TODO comments in the codebase"
messages = [
    {"role": "user", "content": "Find all TODO comments in Python files, read the relevant code context, then create a summary of technical debt."}
]

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=4096,
    tools=tools,
    messages=messages
)

# Claude will typically:
# 1. glob_files("**/*.py") - find all Python files (read-only, can parallelize)
# 2. grep_content("TODO|FIXME|HACK", "*.py") - search content (read-only, can parallelize)
# 3. read_file() for each match - inspect context (read-only, can parallelize)
# 4. Return structured summary (no tool needed - end_turn)

Example 2: Parallel Tool Execution with readOnlyHint

# MCP tool annotations that enable parallel execution
read_only_tools = [
    {
        "name": "get_user_profile",
        "description": "Fetch user profile data",
        "annotations": {
            "readOnlyHint": True,    # โ† Enables parallel execution
            "destructiveHint": False,
            "idempotentHint": True
        },
        "input_schema": {...}
    },
    {
        "name": "get_order_history", 
        "description": "Fetch user's order history",
        "annotations": {
            "readOnlyHint": True,    # โ† These two can run in parallel
            "destructiveHint": False,
            "idempotentHint": True
        },
        "input_schema": {...}
    }
]

# State-modifying tools โ€” will ALWAYS run sequentially
write_tools = [
    {
        "name": "update_user_preferences",
        "description": "Update user preferences in database",
        "annotations": {
            "readOnlyHint": False,   # โ† Sequential execution (default)
            "destructiveHint": False,
            "idempotentHint": True
        },
        "input_schema": {...}
    }
]

Example 3: Tool Distribution Across MCP Servers

# Architecture: Tools split across isolated MCP servers
# Each server = own process, own permissions, own failure domain

# Server 1: Read-only codebase exploration
class CodeExplorerServer:
    """All tools here are read-only โ†’ can execute in parallel"""
    
    @tool(annotations={"readOnlyHint": True})
    def glob(self, pattern: str) -> list[str]:
        """Find files matching glob pattern"""
        return glob.glob(pattern, recursive=True)
    
    @tool(annotations={"readOnlyHint": True})
    def grep(self, pattern: str, path: str = ".") -> list[dict]:
        """Search file content with regex"""
        # Returns [{file, line_num, content}, ...]
        ...
    
    @tool(annotations={"readOnlyHint": True})
    def read(self, path: str) -> str:
        """Read file contents"""
        ...

# Server 2: Code modification (sequential)
class CodeEditorServer:
    """State-modifying tools โ†’ execute sequentially"""
    
    @tool(annotations={"readOnlyHint": False})
    def edit(self, path: str, old_text: str, new_text: str) -> dict:
        """Edit a file by replacing old_text with new_text"""
        ...
    
    @tool(annotations={"readOnlyHint": False})  
    def write(self, path: str, content: str) -> dict:
        """Create a new file"""
        ...

# Server 3: Execution environment (sequential, higher risk)
class ExecutionServer:
    """Bash execution โ€” always sequential, requires explicit permission"""
    
    @tool(annotations={"readOnlyHint": False, "destructiveHint": True})
    def bash(self, command: str) -> dict:
        """Run a shell command"""
        ...

๐Ÿ“– Reading

Primary: Building agents with the Claude Agent SDK โ€” Anthropic's engineering blog post explaining the design philosophy of "giving Claude a computer" and how built-in tools enable agent capabilities. Focus on the "Gather context โ†’ Take action โ†’ Verify work" loop.

Secondary: Writing effective tools for AI agents โ€” using AI agents โ€” Essential reading on tool design principles including namespacing, token efficiency, and when NOT to implement a tool.

Reference: Claude Code Overview (docs.anthropic.com) โ€” Official docs covering all built-in tools and their behaviors.


๐Ÿ› ๏ธ Hands-On Exercise (20 minutes)

Task: "Find and Fix All TODO Comments" โ€” Plan Your Tool Strategy

  1. You're building a "technical debt tracker" agent. The task: scan a codebase, find all TODO/FIXME/HACK comments, read surrounding context, categorize them by urgency, and generate a report.
  2. Write out the exact sequence of tool calls Claude should make, noting which can run in parallel: 
    • Step 1: glob("**/*.{py,ts,js}") โ€” find all source files [read-only, parallelizable]
    • Step 2: grep("TODO|FIXME|HACK") โ€” find all comments [read-only, parallelizable with step 1? YES!]
    • Step 3: For each match, read(file_path) โ€” get context [read-only, ALL can run in parallel]
    • Step 4: Claude synthesizes and returns report โ€” end_turn
  3. Now redesign for a multi-agent system
    • Agent A (Explorer): glob + grep + read (4 read-only tools)
    • Agent B (Classifier): Uses the report from A, classifies by urgency
    • Agent C (Fixer): edit + write + bash (writes fixes for "easy" TODOs)
  4. Bonus: Write the MCP server configuration (.claude/mcp.json) that implements this 3-server architecture.

๐Ÿ“ Quick Quiz

Question 1: A developer wants to search a large codebase for all files that import a deprecated library. Which built-in tool should Claude use?

A) Glob โ€” search for files matching a pattern B) Grep โ€” search file content for the import statement C) Read โ€” read each file and check for imports D) Bash โ€” run grep -r "import deprecated_lib" .

Question 2: An agent needs to fetch a user's profile AND their order history simultaneously. Both tools are custom MCP tools. What must be true for them to execute in parallel?

A) They must be in the same MCP server B) They must have readOnlyHint: true in their annotations C) They must use the stdio transport D) They will automatically run in parallel since they don't share dependencies

Question 3: You're designing an agent for codebase exploration that needs: file search, content search, file reading, and running tests. How should you distribute these tools?

A) All 4 tools on one agent โ€” keeps it simple B) Split into 2 agents: read-only tools (glob, grep, read) on one, execution (bash for tests) on another C) One tool per agent for maximum isolation D) Only use Bash for everything โ€” it can do all four tasks


Answers:

1. B โ€” Grep searches file content. Glob searches file names/paths. The question asks about finding import statements (content), so Grep is correct. D (Bash with grep) technically works but is wrong because: (a) Bash is a state-modifying tool that runs sequentially, and (b) the built-in Grep tool is purpose-built and enables parallelism.

2. B โ€” Custom MCP tools default to sequential execution. You must explicitly annotate them with readOnlyHint: true to enable parallel execution. Being in the same server (A) doesn't affect parallelism. Transport type (C) is irrelevant. There's no automatic dependency detection (D).

3. B โ€” The optimal split separates read-only tools (which can parallelize) from state-modifying tools (sequential). A has too many tools but isn't terrible for 4. C is over-engineered. D loses the benefits of purpose-built tools and forces sequential execution for everything.


๐Ÿ‘€ Tomorrow's Preview

We start Domain 3: Claude Code Configuration & Workflows with the CLAUDE.md hierarchy โ€” the 6-level configuration system that controls Claude Code's behavior. You'll learn about enterprise policies, project/subdirectory configs, imports, and how conflicts resolve. This is highly testable material.