Tool Integration & Function Calling

MCP Integration & Tool Orchestration

5 min read

Model Context Protocol (MCP) represents the future of AI tool integration. Understanding how production systems orchestrate multiple tools through MCP reveals patterns for building extensible, composable AI assistants.

What is MCP?

MCP is an open protocol for connecting AI models to external tools and data sources:

MCP Architecture:
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   AI Model  │◄───►│  MCP Host   │◄───►│ MCP Servers │
│ (Claude)    │     │ (Claude Code)│     │ (Tools)     │
└─────────────┘     └─────────────┘     └─────────────┘
                    ┌─────┴─────┐
                    │           │
              ┌─────┴───┐ ┌─────┴───┐
              │Filesystem│ │Database │
              └─────────┘ └─────────┘

MCP Server Configuration

Claude Code MCP Setup

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"],
      "env": {}
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "ghp_..."
      }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "postgresql://..."
      }
    }
  }
}

Server Types

Official MCP Servers (January 2026):
- filesystem: File operations
- github: Repository management
- postgres: Database queries
- sqlite: Local database
- slack: Messaging integration
- google-drive: Document access
- brave-search: Web search
- puppeteer: Browser automation

Tool Discovery Protocol

How hosts discover available tools:

// Request
{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "id": 1
}

// Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "read_file",
        "description": "Read contents of a file",
        "inputSchema": {
          "type": "object",
          "properties": {
            "path": {"type": "string"}
          },
          "required": ["path"]
        }
      },
      {
        "name": "write_file",
        "description": "Write contents to a file",
        "inputSchema": {
          "type": "object",
          "properties": {
            "path": {"type": "string"},
            "content": {"type": "string"}
          },
          "required": ["path", "content"]
        }
      }
    ]
  }
}

Tool Orchestration Patterns

Sequential Orchestration

Tools executed in order:

Sequential Pattern:
Task: "Read config, update value, write back"

Step 1: read_file(path="/config.json")
        ↓ Result: {"debug": false, "port": 3000}

Step 2: Process result
        ↓ Modified: {"debug": true, "port": 3000}

Step 3: write_file(path="/config.json", content=modified)
        ↓ Result: success

Parallel Orchestration

Independent tools run simultaneously:

Parallel Pattern:
Task: "Get weather for multiple cities"

┌─────────────────────────────────────────────┐
│ Parallel Execution                          │
│                                             │
│  get_weather("NYC") ─────┐                  │
│  get_weather("LA")  ─────┼──► Aggregate     │
│  get_weather("CHI") ─────┘     Results      │
│                                             │
└─────────────────────────────────────────────┘

Conditional Orchestration

Tool selection based on results:

Conditional Pattern:
Task: "Find and process data"

search_database(query)
     ├── Found in DB ──► process_db_result()
     └── Not Found ──► search_api(query)
                            └──► process_api_result()

Claude Code's Task Agent System

Claude Code orchestrates tools through specialized agents:

Agent Dispatch Pattern:
┌─────────────────┐
│   Main Agent    │
│   (Orchestrator)│
└────────┬────────┘
    ┌────┴────┐
    ▼         ▼
┌───────┐ ┌───────┐
│Explore│ │ Plan  │
│ Agent │ │ Agent │
└───────┘ └───────┘
    │         │
    └────┬────┘
    ┌─────────┐
    │  Task   │
    │ Result  │
    └─────────┘

Agent Type Selection

Agent Selection from Claude Code:
- general-purpose: Complex multi-step tasks
- Explore: Codebase exploration (quick/medium/thorough)
- Plan: Implementation planning
- claude-code-guide: Documentation queries

Selection criteria:
- Task complexity
- Required tools
- Autonomy level needed

Tool Chaining Patterns

Data Pipeline

Pipeline Pattern:
fetch_data()
transform_data()
validate_data()
store_data()

Each step receives output from previous step

Fan-Out/Fan-In

Fan-Out/Fan-In Pattern:
                    ┌── process_chunk_1() ──┐
                    │                        │
split_data() ───────┼── process_chunk_2() ──┼──► merge_results()
                    │                        │
                    └── process_chunk_3() ──┘

Retry with Fallback

Retry Pattern:
primary_tool()
    ├── Success ──► Continue
    └── Failure ──► retry(max=3)
                        └── All failed ──► fallback_tool()

Error Handling in Orchestration

Tool-Level Errors

// Error Response
{
  "jsonrpc": "2.0",
  "id": 2,
  "error": {
    "code": -32602,
    "message": "Invalid params: path is required"
  }
}

Orchestration-Level Recovery

Error Recovery Strategy:
On tool failure:
1. Check error type
   - Transient → Retry with backoff
   - Permanent → Log and skip or use fallback

2. Check dependency impact
   - Independent → Continue other tools
   - Blocking → Halt dependent chain

3. Aggregate errors for reporting
   - Partial success possible?
   - User notification needed?

Permission and Security

Tool Approval System

From Claude Code's prompt:

Permission Levels:
ALLOWED (auto-approve):
- Read operations
- Search operations
- Safe bash commands

REQUIRES_APPROVAL:
- Write operations
- Delete operations
- Network requests to unknown hosts
- Bash commands with side effects

NEVER_ALLOWED:
- Credential access
- System modification
- Destructive operations

Sandboxing Patterns

Sandbox Configuration:
{
  "permissions": {
    "filesystem": {
      "read": ["/project/**"],
      "write": ["/project/**"],
      "deny": ["/project/.env", "/project/secrets/**"]
    },
    "network": {
      "allow": ["api.github.com", "registry.npmjs.org"],
      "deny": ["*"]
    },
    "exec": {
      "allow": ["npm", "node", "git"],
      "deny": ["rm", "sudo"]
    }
  }
}

Building Custom MCP Servers

Server Structure

import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";

const server = new Server({
  name: "custom-server",
  version: "1.0.0"
});

// Register tool
server.setRequestHandler("tools/list", async () => ({
  tools: [{
    name: "custom_tool",
    description: "Does something useful",
    inputSchema: {
      type: "object",
      properties: {
        input: { type: "string" }
      },
      required: ["input"]
    }
  }]
}));

// Handle tool calls
server.setRequestHandler("tools/call", async (request) => {
  if (request.params.name === "custom_tool") {
    const result = await doSomething(request.params.arguments);
    return { content: [{ type: "text", text: result }] };
  }
});

// Start server
const transport = new StdioServerTransport();
await server.connect(transport);

Best Practices

1. Minimize Tool Calls

Batching Pattern:
// Instead of:
read_file("a.ts")
read_file("b.ts")
read_file("c.ts")

// Use:
read_files(["a.ts", "b.ts", "c.ts"])

2. Provide Rich Context

{
  "name": "search_codebase",
  "description": "Search for code patterns. Use for finding definitions, usages, or patterns. Returns file paths with line numbers. Use Grep for content search, Glob for file names.",
  "inputSchema": {
    "properties": {
      "pattern": {
        "type": "string",
        "description": "Regex pattern. Examples: 'function\\s+\\w+', 'TODO:', 'import.*from'"
      }
    }
  }
}

3. Validate Before Execute

Validation Pattern:
Before tool execution:
1. Check required parameters present
2. Validate parameter types
3. Check permissions
4. Estimate resource usage
5. Confirm with user if high-impact

Key Insight: MCP transforms AI assistants from isolated models to connected systems. Effective tool orchestration requires understanding sequential vs parallel execution, proper error handling, and security boundaries. The best orchestration is invisible—tools combine seamlessly to solve complex problems.

Next module, we'll explore safety, guardrails, and constraints in production prompts. :::

Quiz

Module 4: Tool Integration & Function Calling

Take Quiz