claude-agent-sdk-tool-integration
$
npx mdskill add TheBushidoCollective/han/claude-agent-sdk-tool-integrationIntegrate tools, permissions, and MCP servers with Claude agents.
- Enables secure execution of file operations, shell commands, and custom APIs.
- Configures strict or permissive approval modes for tool access control.
- Defines custom tools via input schemas and async execution functions.
- Delivers results through structured tool invocations within agent workflows.
SKILL.md
.github/skills/claude-agent-sdk-tool-integrationView on GitHub ↗
---
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
More from TheBushidoCollective/han
- absinthe-resolversUse when implementing GraphQL resolvers with Absinthe. Covers resolver patterns, dataloader integration, batching, and error handling.
- absinthe-schemaUse when designing GraphQL schemas with Absinthe. Covers type definitions, interfaces, unions, enums, and schema organization patterns.
- absinthe-subscriptionsUse when implementing real-time GraphQL subscriptions with Absinthe. Covers Phoenix channels, PubSub, and subscription patterns.
- act-docker-setupUse when configuring Docker environments for act, selecting runner images, managing container resources, or troubleshooting Docker-related issues with local GitHub Actions testing.
- act-local-testingUse when testing GitHub Actions workflows locally with act. Covers act CLI usage, Docker configuration, debugging workflows, and troubleshooting common issues when running workflows on your local machine.
- act-workflow-syntaxUse when creating or modifying GitHub Actions workflow files. Provides guidance on workflow syntax, triggers, jobs, steps, and expressions for creating valid GitHub Actions workflows that can be tested locally with act.
- ameba-configurationUse when configuring Ameba rules and settings for Crystal projects including .ameba.yml setup, rule management, severity levels, and code quality enforcement.
- ameba-custom-rulesUse when creating custom Ameba rules for Crystal code analysis including rule development, AST traversal, issue reporting, and rule testing.
- ameba-integrationUse when integrating Ameba into development workflows including CI/CD pipelines, pre-commit hooks, GitHub Actions, and automated code review processes.
- analyze-performanceAnalyze performance metrics and identify slow transactions in Sentry