home / skills / thebushidocollective / han / tool-integration

This skill helps integrate Claude Agent with tools, permissions, and MCP servers to securely empower tool usage in agents.

npx playbooks add skill thebushidocollective/han --skill tool-integration

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
6.1 KB
---
name: claude-agent-sdk-tool-integration
description: Use when integrating tools, permissions, and MCP servers with Claude AI agents using the Agent SDK.
allowed-tools:
  - Read
  - Write
  - Edit
  - Bash
  - Grep
  - Glob
---

# Claude Agent SDK - Tool Integration

Working with tools, permissions, and MCP (Model Context Protocol) servers in the Claude Agent SDK.

## Tool Permissions

### Allowing Specific Tools

```typescript
import { Agent } from '@anthropic-ai/claude-agent-sdk';

const agent = new Agent({
  allowedTools: [
    'read_file',
    'write_file',
    'list_files',
    'grep',
    'bash',
  ],
});
```

### Blocking Tools

```typescript
const agent = new Agent({
  disallowedTools: ['bash', 'web_search'],
});
```

### Permission Modes

```typescript
// Strict mode - requires explicit user approval
const agent = new Agent({
  permissionMode: 'strict',
});

// Permissive mode - auto-approves known safe operations
const agent = new Agent({
  permissionMode: 'permissive',
});
```

## Custom Tools

### Defining Custom Tools

```typescript
import { Agent, Tool } from '@anthropic-ai/claude-agent-sdk';

const customTool: Tool = {
  name: 'get_weather',
  description: 'Get current weather for a location',
  input_schema: {
    type: 'object',
    properties: {
      location: {
        type: 'string',
        description: 'City name',
      },
    },
    required: ['location'],
  },
  execute: async (input) => {
    const { location } = input;
    // Call weather API
    return {
      location,
      temperature: 72,
      conditions: 'sunny',
    };
  },
};

const agent = new Agent({
  tools: [customTool],
});
```

### Tool Execution Context

```typescript
const customTool: Tool = {
  name: 'read_database',
  description: 'Query the database',
  input_schema: {
    type: 'object',
    properties: {
      query: { type: 'string' },
    },
    required: ['query'],
  },
  execute: async (input, context) => {
    // Context provides agent state and utilities
    console.log('Agent model:', context.model);

    const result = await runQuery(input.query);
    return result;
  },
};
```

## MCP Server Integration

### Adding MCP Servers

```typescript
const agent = new Agent({
  mcpServers: {
    filesystem: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/allowed'],
    },
    git: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-git'],
    },
  },
});
```

### Using MCP Resources

```typescript
// Agent automatically has access to MCP server resources
const agent = new Agent({
  mcpServers: {
    filesystem: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-filesystem', './data'],
    },
  },
});

// Agent can now read files via MCP
await agent.chat('Read the contents of data/config.json');
```

### MCP Server Configuration

```typescript
const agent = new Agent({
  mcpServers: {
    database: {
      command: 'node',
      args: ['./mcp-servers/database.js'],
      env: {
        DATABASE_URL: process.env.DATABASE_URL,
      },
    },
  },
});
```

## Tool Response Handling

### Streaming Tool Responses

```typescript
const response = await agent.chat('List all files in src/');

for await (const chunk of response) {
  if (chunk.type === 'tool_use') {
    console.log('Tool called:', chunk.name);
  }
  if (chunk.type === 'tool_result') {
    console.log('Tool result:', chunk.content);
  }
}
```

### Error Handling

```typescript
const customTool: Tool = {
  name: 'risky_operation',
  description: 'Perform risky operation',
  input_schema: {
    type: 'object',
    properties: {
      action: { type: 'string' },
    },
    required: ['action'],
  },
  execute: async (input) => {
    try {
      const result = await performOperation(input.action);
      return { success: true, result };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  },
};
```

## Best Practices

### Principle of Least Privilege

```typescript
// Good: Only allow necessary tools
const agent = new Agent({
  allowedTools: ['read_file', 'list_files'],
});

// Avoid: Allowing all tools unnecessarily
const agent = new Agent({
  allowedTools: ['*'],
});
```

### Tool Input Validation

```typescript
const customTool: Tool = {
  name: 'delete_file',
  description: 'Delete a file',
  input_schema: {
    type: 'object',
    properties: {
      path: { type: 'string' },
    },
    required: ['path'],
  },
  execute: async (input) => {
    // Validate input
    if (!input.path || input.path.includes('..')) {
      throw new Error('Invalid file path');
    }

    // Prevent deleting critical files
    if (input.path.startsWith('/etc') || input.path.startsWith('/sys')) {
      throw new Error('Cannot delete system files');
    }

    await deleteFile(input.path);
    return { deleted: input.path };
  },
};
```

### MCP Server Sandboxing

```typescript
// Good: Restrict filesystem access to specific directory
const agent = new Agent({
  mcpServers: {
    filesystem: {
      command: 'npx',
      args: [
        '-y',
        '@modelcontextprotocol/server-filesystem',
        './workspace', // Sandboxed to workspace only
      ],
    },
  },
});
```

## Anti-Patterns

### Don't Allow Unrestricted Bash

```typescript
// Bad: Unrestricted bash access
const agent = new Agent({
  allowedTools: ['bash'],
});

// Better: Use specific tools instead
const agent = new Agent({
  allowedTools: ['read_file', 'write_file', 'list_files'],
});
```

### Don't Ignore Tool Errors

```typescript
// Bad: Silent failure
const customTool: Tool = {
  execute: async (input) => {
    try {
      return await riskyOperation(input);
    } catch {
      return null; // Silent failure
    }
  },
};

// Good: Explicit error handling
const customTool: Tool = {
  execute: async (input) => {
    try {
      return await riskyOperation(input);
    } catch (error) {
      return {
        error: true,
        message: error instanceof Error ? error.message : 'Operation failed',
      };
    }
  },
};
```

## Related Skills

- **agent-creation**: Agent initialization and configuration
- **context-management**: Managing agent context and memory

Overview

This skill helps integrate tools, permission controls, and Model Context Protocol (MCP) servers into Claude AI agents using the Agent SDK. It focuses on safe, auditable tool access, custom tool definitions, and secure MCP server mounting for agent context. Use it to add, restrict, and manage capabilities for production-ready agents.

How this skill works

You configure an Agent with allowed or disallowed tools, set permission modes (strict or permissive), and register custom Tool objects with input schemas and execute handlers. MCP servers are launched as subprocesses and mounted as resources the agent can query, e.g., sandboxed filesystems or Git. Tool calls stream events back to the client so you can observe tool use, results, and handle errors explicitly.

When to use it

  • When you need the agent to interact with files, databases, or external services via discrete tools.
  • When you want to restrict or audit what operations an agent can perform (principle of least privilege).
  • When you must expose project files or Git history to the agent through MCP servers.
  • When implementing custom business logic or APIs as tools with validated inputs.
  • When you need streaming insight into tool usage and results for observability.

Best practices

  • Apply principle of least privilege: only allow specific tools required for the task.
  • Use permissionMode 'strict' for production or sensitive workflows; 'permissive' for trusted, internal tasks.
  • Define explicit input_schema for every custom tool and validate inputs to prevent abuse.
  • Sandbox MCP filesystem servers to a dedicated workspace directory, never global root.
  • Handle tool errors explicitly and return structured error objects instead of silent failures.

Example use cases

  • Provide a read-only MCP filesystem containing documentation and let the agent answer questions about it.
  • Register a custom get_weather tool that validates location input and calls a weather API.
  • Launch a database MCP server with credentials in env to let the agent query application state safely.
  • Replace broad bash permissions with narrowly scoped file and grep tools for codebase automation.
  • Stream file listing results back to a UI while showing which tools were invoked in real time.

FAQ

How do I prevent an agent from running arbitrary shell commands?

Do not enable 'bash' as an allowed tool. Expose only specific file and helper tools and sandbox MCP servers. Use permissionMode 'strict' to require explicit user approval for high-risk operations.

Can custom tools access agent state?

Yes. The execute handler receives a context object with agent model and utilities so tools can consult agent state while running.

How should I handle tool errors?

Return structured error responses from execute and avoid swallowing exceptions. Log errors and propagate meaningful messages for observability and safe retries.