643 lines
15 KiB
Markdown
643 lines
15 KiB
Markdown
# Adding Custom MCP Servers to Agentic Flow
|
|
|
|
This guide shows you how to integrate custom MCP (Model Context Protocol) servers into agentic-flow.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Overview](#overview)
|
|
2. [Integration Methods](#integration-methods)
|
|
3. [Method 1: In-SDK MCP Server (Recommended)](#method-1-in-sdk-mcp-server-recommended)
|
|
4. [Method 2: External MCP Server via Stdio](#method-2-external-mcp-server-via-stdio)
|
|
5. [Method 3: External MCP Server via NPM Package](#method-3-external-mcp-server-via-npm-package)
|
|
6. [Environment Variables](#environment-variables)
|
|
7. [Testing Your MCP Server](#testing-your-mcp-server)
|
|
8. [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Agentic Flow supports three ways to add custom MCP servers:
|
|
|
|
| Method | Type | Performance | Use Case |
|
|
|--------|------|-------------|----------|
|
|
| **In-SDK** | In-process | Fastest (<1ms) | Custom tools, simple operations |
|
|
| **Stdio** | Subprocess | Fast (10-50ms) | Local MCP servers, CLI tools |
|
|
| **NPM Package** | Subprocess | Fast (10-50ms) | Published MCP packages |
|
|
|
|
**Current MCP Servers in Agentic Flow:**
|
|
|
|
1. **claude-flow-sdk** (In-SDK) - 6 tools
|
|
2. **claude-flow** (NPM) - 101 tools
|
|
3. **flow-nexus** (NPM) - 96 tools
|
|
4. **agentic-payments** (NPM) - 10 tools
|
|
|
|
---
|
|
|
|
## Integration Methods
|
|
|
|
### Method 1: In-SDK MCP Server (Recommended)
|
|
|
|
**Best for:** Custom tools, simple operations, fastest performance
|
|
|
|
In-SDK servers run directly in the agent process without spawning subprocesses.
|
|
|
|
#### Step 1: Create MCP Server File
|
|
|
|
Create `src/mcp/myCustomServer.ts`:
|
|
|
|
```typescript
|
|
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
|
|
import { z } from 'zod';
|
|
import { logger } from '../utils/logger.js';
|
|
|
|
/**
|
|
* Create an in-SDK MCP server with custom tools
|
|
*/
|
|
export const myCustomServer = createSdkMcpServer({
|
|
name: 'my-custom-server',
|
|
version: '1.0.0',
|
|
|
|
tools: [
|
|
// Tool 1: Simple calculator
|
|
tool(
|
|
'calculate',
|
|
'Perform mathematical calculations',
|
|
{
|
|
operation: z.enum(['add', 'subtract', 'multiply', 'divide'])
|
|
.describe('Mathematical operation'),
|
|
a: z.number().describe('First number'),
|
|
b: z.number().describe('Second number')
|
|
},
|
|
async ({ operation, a, b }) => {
|
|
logger.info('Executing calculation', { operation, a, b });
|
|
|
|
let result: number;
|
|
switch (operation) {
|
|
case 'add': result = a + b; break;
|
|
case 'subtract': result = a - b; break;
|
|
case 'multiply': result = a * b; break;
|
|
case 'divide':
|
|
if (b === 0) throw new Error('Division by zero');
|
|
result = a / b;
|
|
break;
|
|
}
|
|
|
|
return {
|
|
operation,
|
|
inputs: { a, b },
|
|
result,
|
|
message: `${a} ${operation} ${b} = ${result}`
|
|
};
|
|
}
|
|
),
|
|
|
|
// Tool 2: Data storage
|
|
tool(
|
|
'store_data',
|
|
'Store key-value data in memory',
|
|
{
|
|
key: z.string().describe('Storage key'),
|
|
value: z.string().describe('Value to store'),
|
|
namespace: z.string().optional().describe('Optional namespace')
|
|
},
|
|
async ({ key, value, namespace }) => {
|
|
// Your storage logic here
|
|
const fullKey = namespace ? `${namespace}:${key}` : key;
|
|
|
|
// Store in memory, database, or filesystem
|
|
logger.info('Storing data', { fullKey, value });
|
|
|
|
return {
|
|
success: true,
|
|
key: fullKey,
|
|
stored: value
|
|
};
|
|
}
|
|
),
|
|
|
|
// Tool 3: API call wrapper
|
|
tool(
|
|
'fetch_data',
|
|
'Fetch data from external API',
|
|
{
|
|
url: z.string().url().describe('API endpoint URL'),
|
|
method: z.enum(['GET', 'POST']).default('GET').describe('HTTP method')
|
|
},
|
|
async ({ url, method }) => {
|
|
logger.info('Fetching data', { url, method });
|
|
|
|
try {
|
|
const response = await fetch(url, { method });
|
|
const data = await response.json();
|
|
|
|
return {
|
|
success: true,
|
|
status: response.status,
|
|
data
|
|
};
|
|
} catch (error: any) {
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
)
|
|
]
|
|
});
|
|
```
|
|
|
|
#### Step 2: Register in Claude Agent
|
|
|
|
Edit `src/agents/claudeAgent.ts`:
|
|
|
|
```typescript
|
|
// Add import at top
|
|
import { myCustomServer } from '../mcp/myCustomServer.js';
|
|
|
|
// Inside claudeAgent function, around line 128:
|
|
if (process.env.ENABLE_MY_CUSTOM_MCP === 'true') {
|
|
mcpServers['my-custom-server'] = myCustomServer;
|
|
}
|
|
```
|
|
|
|
#### Step 3: Enable and Use
|
|
|
|
```bash
|
|
# Enable your custom MCP server
|
|
export ENABLE_MY_CUSTOM_MCP=true
|
|
|
|
# Run agent with your custom tools
|
|
npx agentic-flow --agent coder --task "Calculate 42 + 58 using the calculate tool"
|
|
```
|
|
|
|
**Pros:**
|
|
- ✅ Fastest performance (in-process, <1ms latency)
|
|
- ✅ No subprocess overhead
|
|
- ✅ Full TypeScript type safety
|
|
- ✅ Easy to debug
|
|
|
|
**Cons:**
|
|
- ⚠️ Requires rebuild (`npm run build`)
|
|
- ⚠️ Can't use external CLI tools directly
|
|
|
|
---
|
|
|
|
### Method 2: External MCP Server via Stdio
|
|
|
|
**Best for:** Local MCP servers, custom CLI tools, existing MCP implementations
|
|
|
|
External stdio servers run as subprocesses and communicate via standard input/output.
|
|
|
|
#### Step 1: Create Standalone MCP Server
|
|
|
|
Create `my-mcp-server/index.js`:
|
|
|
|
```javascript
|
|
#!/usr/bin/env node
|
|
// Standalone MCP server using FastMCP or @modelcontextprotocol/sdk
|
|
|
|
import { FastMCP } from 'fastmcp';
|
|
|
|
const server = new FastMCP({
|
|
name: 'my-external-server',
|
|
version: '1.0.0'
|
|
});
|
|
|
|
// Add tools
|
|
server.addTool({
|
|
name: 'custom_search',
|
|
description: 'Search custom database',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
query: { type: 'string', description: 'Search query' },
|
|
limit: { type: 'number', description: 'Max results' }
|
|
},
|
|
required: ['query']
|
|
},
|
|
execute: async ({ query, limit = 10 }) => {
|
|
// Your search logic
|
|
return {
|
|
results: [
|
|
{ id: 1, title: 'Result 1', score: 0.95 },
|
|
{ id: 2, title: 'Result 2', score: 0.87 }
|
|
],
|
|
count: 2
|
|
};
|
|
}
|
|
});
|
|
|
|
server.addTool({
|
|
name: 'send_notification',
|
|
description: 'Send notification via custom service',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
message: { type: 'string' },
|
|
channel: { type: 'string', enum: ['email', 'slack', 'sms'] }
|
|
},
|
|
required: ['message', 'channel']
|
|
},
|
|
execute: async ({ message, channel }) => {
|
|
// Send notification
|
|
console.error(`Sending ${channel} notification: ${message}`);
|
|
return { success: true, channel, message };
|
|
}
|
|
});
|
|
|
|
// Start stdio transport
|
|
server.listen({ transport: 'stdio' });
|
|
```
|
|
|
|
Make it executable:
|
|
```bash
|
|
chmod +x my-mcp-server/index.js
|
|
```
|
|
|
|
#### Step 2: Register in Claude Agent
|
|
|
|
Edit `src/agents/claudeAgent.ts`:
|
|
|
|
```typescript
|
|
// Inside claudeAgent function, around line 169:
|
|
if (process.env.ENABLE_MY_EXTERNAL_MCP === 'true') {
|
|
mcpServers['my-external-server'] = {
|
|
type: 'stdio',
|
|
command: 'node',
|
|
args: ['/path/to/my-mcp-server/index.js'],
|
|
env: {
|
|
...process.env,
|
|
MY_SERVER_CONFIG: 'value'
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
#### Step 3: Enable and Use
|
|
|
|
```bash
|
|
# Enable external MCP server
|
|
export ENABLE_MY_EXTERNAL_MCP=true
|
|
|
|
# Run agent
|
|
npx agentic-flow --agent researcher --task "Search for 'AI trends' using custom_search"
|
|
```
|
|
|
|
**Pros:**
|
|
- ✅ No rebuild required
|
|
- ✅ Can use any language (Node, Python, Go, etc.)
|
|
- ✅ Full access to CLI tools and system commands
|
|
- ✅ Isolated process
|
|
|
|
**Cons:**
|
|
- ⚠️ Subprocess overhead (10-50ms startup)
|
|
- ⚠️ Requires absolute path or PATH setup
|
|
- ⚠️ More complex debugging
|
|
|
|
---
|
|
|
|
### Method 3: External MCP Server via NPM Package
|
|
|
|
**Best for:** Published MCP packages, shared tools, community servers
|
|
|
|
If your MCP server is published as an NPM package, integrate it like existing servers.
|
|
|
|
#### Step 1: Publish MCP Package
|
|
|
|
Create `package.json` for your MCP server:
|
|
|
|
```json
|
|
{
|
|
"name": "my-mcp-package",
|
|
"version": "1.0.0",
|
|
"bin": {
|
|
"my-mcp": "./dist/index.js"
|
|
},
|
|
"main": "./dist/index.js",
|
|
"scripts": {
|
|
"mcp": "node dist/index.js"
|
|
}
|
|
}
|
|
```
|
|
|
|
Publish to NPM:
|
|
```bash
|
|
npm publish my-mcp-package
|
|
```
|
|
|
|
#### Step 2: Register in Claude Agent
|
|
|
|
Edit `src/agents/claudeAgent.ts`:
|
|
|
|
```typescript
|
|
// Inside claudeAgent function, around line 169:
|
|
if (process.env.ENABLE_MY_MCP_PACKAGE === 'true') {
|
|
mcpServers['my-mcp-package'] = {
|
|
type: 'stdio',
|
|
command: 'npx',
|
|
args: ['my-mcp-package@latest', 'mcp'], // Or just 'my-mcp' if using bin
|
|
env: {
|
|
...process.env,
|
|
MY_MCP_API_KEY: process.env.MY_MCP_API_KEY || ''
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
#### Step 3: Enable and Use
|
|
|
|
```bash
|
|
# Enable MCP package
|
|
export ENABLE_MY_MCP_PACKAGE=true
|
|
export MY_MCP_API_KEY=your-api-key
|
|
|
|
# Run agent (will auto-install via npx)
|
|
npx agentic-flow --agent coder --task "Use tools from my-mcp-package"
|
|
```
|
|
|
|
**Pros:**
|
|
- ✅ Easy distribution via NPM
|
|
- ✅ Version management
|
|
- ✅ Auto-installation via npx
|
|
- ✅ Community sharing
|
|
|
|
**Cons:**
|
|
- ⚠️ Requires NPM publishing
|
|
- ⚠️ Network dependency for first install
|
|
- ⚠️ Subprocess overhead
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
Create environment variables to enable/disable your MCP servers:
|
|
|
|
```bash
|
|
# In-SDK servers
|
|
export ENABLE_CLAUDE_FLOW_SDK=true # Built-in (6 tools)
|
|
export ENABLE_MY_CUSTOM_MCP=true # Your custom in-SDK server
|
|
|
|
# External stdio servers
|
|
export ENABLE_CLAUDE_FLOW_MCP=true # claude-flow (101 tools)
|
|
export ENABLE_FLOW_NEXUS_MCP=true # flow-nexus (96 tools)
|
|
export ENABLE_AGENTIC_PAYMENTS_MCP=true # agentic-payments (10 tools)
|
|
export ENABLE_MY_EXTERNAL_MCP=true # Your external server
|
|
export ENABLE_MY_MCP_PACKAGE=true # Your NPM package
|
|
```
|
|
|
|
**Convention:**
|
|
- In-SDK: `ENABLE_<NAME>_MCP=true`
|
|
- External: `ENABLE_<NAME>_MCP=true`
|
|
- Config: `<NAME>_API_KEY=xxx`, `<NAME>_CONFIG=xxx`
|
|
|
|
---
|
|
|
|
## Testing Your MCP Server
|
|
|
|
### Test In-SDK Server
|
|
|
|
```typescript
|
|
// Create test file: src/mcp/__tests__/myCustomServer.test.ts
|
|
import { myCustomServer } from '../myCustomServer.js';
|
|
|
|
describe('MyCustomServer', () => {
|
|
it('should calculate correctly', async () => {
|
|
const tools = myCustomServer.tools;
|
|
const calculateTool = tools.find(t => t.name === 'calculate');
|
|
|
|
const result = await calculateTool?.execute({
|
|
operation: 'add',
|
|
a: 10,
|
|
b: 20
|
|
});
|
|
|
|
expect(result.result).toBe(30);
|
|
});
|
|
});
|
|
```
|
|
|
|
### Test External Server
|
|
|
|
```bash
|
|
# Test standalone server
|
|
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node my-mcp-server/index.js
|
|
|
|
# Test with agentic-flow
|
|
export ENABLE_MY_EXTERNAL_MCP=true
|
|
npx agentic-flow --agent coder --task "List all available tools"
|
|
```
|
|
|
|
### Integration Test
|
|
|
|
```bash
|
|
# Enable your server
|
|
export ENABLE_MY_CUSTOM_MCP=true
|
|
|
|
# Run with verbose logging
|
|
npx agentic-flow --agent coder --task "Test my custom tools" --verbose
|
|
|
|
# Check logs
|
|
# Should see: "Registered MCP server: my-custom-server"
|
|
```
|
|
|
|
---
|
|
|
|
## Code Reference: Existing Integrations
|
|
|
|
### In-SDK Example: claude-flow-sdk
|
|
|
|
**File:** `src/mcp/claudeFlowSdkServer.ts`
|
|
|
|
```typescript
|
|
export const claudeFlowSdkServer = createSdkMcpServer({
|
|
name: 'claude-flow-sdk',
|
|
version: '1.0.0',
|
|
tools: [
|
|
tool('memory_store', 'Store value in memory', {...}),
|
|
tool('memory_retrieve', 'Retrieve value from memory', {...}),
|
|
tool('swarm_init', 'Initialize swarm', {...}),
|
|
// ... 6 tools total
|
|
]
|
|
});
|
|
```
|
|
|
|
**Registration:** `src/agents/claudeAgent.ts:128-130`
|
|
```typescript
|
|
if (process.env.ENABLE_CLAUDE_FLOW_SDK === 'true') {
|
|
mcpServers['claude-flow-sdk'] = claudeFlowSdkServer;
|
|
}
|
|
```
|
|
|
|
### External Example: claude-flow
|
|
|
|
**Registration:** `src/agents/claudeAgent.ts:134-145`
|
|
```typescript
|
|
if (process.env.ENABLE_CLAUDE_FLOW_MCP === 'true') {
|
|
mcpServers['claude-flow'] = {
|
|
type: 'stdio',
|
|
command: 'npx',
|
|
args: ['claude-flow@alpha', 'mcp', 'start'],
|
|
env: {
|
|
...process.env,
|
|
MCP_AUTO_START: 'true',
|
|
PROVIDER: provider
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
### External Example: flow-nexus
|
|
|
|
**Registration:** `src/agents/claudeAgent.ts:147-157`
|
|
```typescript
|
|
if (process.env.ENABLE_FLOW_NEXUS_MCP === 'true') {
|
|
mcpServers['flow-nexus'] = {
|
|
type: 'stdio',
|
|
command: 'npx',
|
|
args: ['flow-nexus@latest', 'mcp', 'start'],
|
|
env: {
|
|
...process.env,
|
|
FLOW_NEXUS_AUTO_START: 'true'
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### MCP Server Not Loading
|
|
|
|
**Problem:** Agent doesn't see your MCP tools
|
|
|
|
**Solutions:**
|
|
```bash
|
|
# 1. Check environment variable
|
|
echo $ENABLE_MY_CUSTOM_MCP # Should be "true"
|
|
|
|
# 2. Rebuild if in-SDK
|
|
npm run build
|
|
|
|
# 3. Check logs
|
|
npx agentic-flow --agent coder --task "test" --verbose
|
|
# Should see: "Registered MCP server: my-custom-server"
|
|
|
|
# 4. Test server directly
|
|
node my-mcp-server/index.js # For external servers
|
|
```
|
|
|
|
### Tools Not Executing
|
|
|
|
**Problem:** Tools registered but don't execute
|
|
|
|
**Solutions:**
|
|
```bash
|
|
# 1. Check tool name in task
|
|
# Correct: "Use the calculate tool to add 5 and 10"
|
|
# Wrong: "Calculate 5 + 10" (doesn't reference tool)
|
|
|
|
# 2. Check Zod schema validation
|
|
# Ensure parameters match schema exactly
|
|
|
|
# 3. Add logging
|
|
logger.info('Tool executed', { toolName, params, result });
|
|
```
|
|
|
|
### Subprocess Failures
|
|
|
|
**Problem:** External MCP server crashes or times out
|
|
|
|
**Solutions:**
|
|
```bash
|
|
# 1. Test server standalone
|
|
node my-mcp-server/index.js
|
|
# Type: {"jsonrpc":"2.0","method":"tools/list","id":1}
|
|
|
|
# 2. Check command/args
|
|
# Ensure absolute path or npx for NPM packages
|
|
|
|
# 3. Increase timeout
|
|
mcpServers['my-server'] = {
|
|
type: 'stdio',
|
|
command: 'node',
|
|
args: ['/path/to/server.js'],
|
|
timeout: 60000 // 60 seconds
|
|
};
|
|
```
|
|
|
|
### Type Errors
|
|
|
|
**Problem:** TypeScript errors with In-SDK tools
|
|
|
|
**Solutions:**
|
|
```typescript
|
|
// Ensure correct imports
|
|
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
|
|
import { z } from 'zod';
|
|
|
|
// Rebuild after changes
|
|
npm run build
|
|
|
|
// Check types
|
|
npx tsc --noEmit
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
1. **Start with In-SDK for Simple Tools**
|
|
- Faster development iteration
|
|
- Better type safety
|
|
- Easier debugging
|
|
|
|
2. **Use External for Complex Operations**
|
|
- System commands
|
|
- Heavy computations
|
|
- External APIs
|
|
|
|
3. **Use NPM Packages for Distribution**
|
|
- Share with community
|
|
- Version management
|
|
- Easy updates
|
|
|
|
4. **Always Add Logging**
|
|
```typescript
|
|
logger.info('Tool executed', { tool, params, result });
|
|
```
|
|
|
|
5. **Test Standalone First**
|
|
- Test MCP server independently
|
|
- Then integrate with agentic-flow
|
|
|
|
6. **Document Your Tools**
|
|
- Clear descriptions
|
|
- Parameter documentation
|
|
- Example usage
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
**Quick Reference:**
|
|
|
|
| Need | Method | Steps |
|
|
|------|--------|-------|
|
|
| Simple custom tool | In-SDK | 1. Create `src/mcp/myServer.ts`<br>2. Register in `claudeAgent.ts`<br>3. `npm run build` |
|
|
| Local MCP server | Stdio | 1. Create standalone server<br>2. Register with command/args<br>3. Enable env var |
|
|
| Published package | NPM | 1. Publish to NPM<br>2. Register with `npx` command<br>3. Enable env var |
|
|
|
|
**Next Steps:**
|
|
- See `src/mcp/claudeFlowSdkServer.ts` for in-SDK example
|
|
- See `src/agents/claudeAgent.ts:134-169` for external examples
|
|
- Read [MCP Specification](https://modelcontextprotocol.io) for protocol details
|
|
|
|
---
|
|
|
|
**Need help?** Open an issue on [GitHub](https://github.com/ruvnet/agentic-flow/issues) or check the [MCP docs](https://modelcontextprotocol.io).
|