# SDK MCP Integration Guide

> **Version Requirement**: This documentation is for CodeBuddy Agent SDK v0.1.24 and above.
>
> **Feature Status**: SDK MCP support is a **Preview** feature of the CodeBuddy Agent SDK.

This document explains how to integrate and use MCP (Model Context Protocol) servers in the CodeBuddy Agent SDK, extending your applications with custom tools and functionality.

## Overview

MCP servers allow you to integrate custom tools, resources, and prompts into the CodeBuddy Agent SDK. Through the SDK, you can programmatically enable these tools, adding domain-specific capabilities to your AI workflows.

### Core Concepts

- **MCP Server**: A standalone process or service that provides tools, resources, and prompts
- **Tools**: Executable functions exposed by MCP servers
- **Resources**: Readable data or files provided by MCP servers
- **Prompts**: Templated prompts provided by MCP servers

## Supported Transport Types

CodeBuddy Agent SDK supports three MCP server communication methods:

| Transport Type | Use Case | Description |
|----------------|----------|-------------|
| **STDIO** | Local tools | Communicate with local processes via standard input/output |
| **HTTP/SSE** | Remote services | Communicate with remote services via HTTP streaming or Server-Sent Events |
| **SDK MCP** | IDE/SDK integration | MCP servers registered by external SDKs (like IDE extensions) |

## Configuring MCP Servers

`mcpServers` supports two configuration methods:

1. **Object format**: Define server configuration directly in code
2. **File path string**: Point to an MCP configuration file (JSON format)

### Object Format

Use the `mcpServers` option to configure MCP servers. Configuration supports STDIO, HTTP, and SSE transport types.

**TypeScript**:

```typescript
import { query } from '@tencent-ai/agent-sdk';

const result = query({
  prompt: 'Analyze my project structure',
  options: {
    mcpServers: {
      'my-tools': {
        type: 'stdio',
        command: 'node',
        args: ['./mcp-server.js'],
        env: {
          NODE_ENV: 'production'
        }
      },
      'api-server': {
        type: 'http',
        url: 'https://api.example.com/mcp',
        headers: {
          'Authorization': 'Bearer your-token'
        }
      },
      'sse-server': {
        type: 'sse',
        url: 'https://events.example.com/mcp/sse',
        headers: {
          'X-API-Key': 'your-api-key'
        }
      }
    }
  }
});
```

### Python

**Python**:

```python
from codebuddy_agent_sdk import query

result = query(
    prompt='Analyze my project structure',
    options={
        'mcp_servers': {
            'my-tools': {
                'type': 'stdio',
                'command': 'python',
                'args': ['-m', 'my_mcp_server'],
                'env': {
                    'PYTHONPATH': '/path/to/tools'
                }
            },
            'api-server': {
                'type': 'http',
                'url': 'https://api.example.com/mcp',
                'headers': {
                    'Authorization': 'Bearer your-token'
                }
            },
            'sse-server': {
                'type': 'sse',
                'url': 'https://events.example.com/mcp/sse',
                'headers': {
                    'X-API-Key': 'your-api-key'
                }
            }
        }
    }
)
```

### File Path Format

You can also pass an MCP configuration file path. The configuration file is in JSON format, with the same structure as the CLI `--mcp-config` parameter.

**TypeScript**:

```typescript
import { query } from '@tencent-ai/agent-sdk';

const result = query({
  prompt: 'Analyze my project structure',
  options: {
    mcpServers: './mcp-config.json'
  }
});
```

**Python**:

```python
from codebuddy_agent_sdk import query

result = query(
    prompt='Analyze my project structure',
    options={
        'mcp_servers': './mcp-config.json'
    }
)
```

Configuration file format example (`mcp-config.json`):

```json
{
  "mcpServers": {
    "my-tools": {
      "type": "stdio",
      "command": "node",
      "args": ["./mcp-server.js"]
    }
  }
}
```

> **Note**: When using file path format, SDK MCP type (`type: 'sdk'`) server configuration is not supported. SDK MCP servers are only available in object format.

## Server Configuration Details

### STDIO Configuration

STDIO servers communicate with local processes via standard input/output, suitable for local tools.

```typescript
{
  type: 'stdio',
  command: 'python',                    // Executable or command
  args: ['-m', 'my_mcp_server'],       // Command line arguments
  env: {                               // Environment variables
    PYTHONPATH: '/path/to/tools',
    DEBUG: 'true'
  }
}
```

**Common Use Cases**:

```typescript
// Python MCP server
{
  type: 'stdio',
  command: 'python',
  args: ['-m', 'fastmcp']
}

// Node.js MCP server
{
  type: 'stdio',
  command: 'node',
  args: ['./server.js']
}

// Local binary
{
  type: 'stdio',
  command: '/usr/local/bin/my-tool',
  args: ['--config', '/etc/config.yaml']
}
```

### HTTP Configuration

HTTP servers communicate with remote services via HTTP streaming.

```typescript
{
  type: 'http',
  url: 'https://mcp.example.com/api/v1',
  headers: {
    'Authorization': 'Bearer your-token',
    'Content-Type': 'application/json'
  }
}
```

### SSE Configuration

SSE servers communicate with remote services via Server-Sent Events.

```typescript
{
  type: 'sse',
  url: 'https://events.example.com/mcp/sse',
  headers: {
    'Authorization': 'Bearer your-token',
    'X-API-Version': 'v1'
  }
}
```

## Permission Management

MCP tools support fine-grained permission control. Through the `canUseTool` callback, you can decide which tools can be used.

### Tool Permission Modes

```typescript
type PermissionMode =
  | 'default'           // Ask user
  | 'acceptEdits'       // Accept automatic edits
  | 'bypassPermissions' // Skip permission checks (not recommended for production)
  | 'plan';             // Plan mode only

const result = query({
  prompt: 'Process data',
  options: {
    permissionMode: 'acceptEdits',
    canUseTool?: (toolCall) => {
      // Custom permission check logic
      if (toolCall.name === 'dangerous_operation') {
        return false;
      }
      return true;
    }
  }
});
```

### Specific Tool Permission Control

```typescript
options: {
  canUseTool: (toolCall) => {
    // Block tools from specific server
    if (toolCall.name.startsWith('mcp__restricted')) {
      return false;
    }

    // Allow specific tools
    if (toolCall.name === 'mcp__github__list_issues') {
      return true;
    }

    // Default to asking
    return null;
  }
}
```

## Using MCP Tools

After configuring MCP servers, the Agent will automatically discover tools provided by these servers and call them when needed.

### Automatic Tool Discovery

```typescript
const result = query({
  prompt: `
    Using the available MCP tools, complete these tasks:
    1. Query the database for recent transactions
    2. Analyze the results
    3. Generate a summary report
  `,
  options: {
    mcpServers: {
      'database': {
        type: 'stdio',
        command: 'python',
        args: ['-m', 'db_mcp_server']
      }
    }
  }
});

for await (const message of result) {
  if (message.type === 'tool_use') {
    console.log(`Tool: ${message.name}`);
    console.log(`Arguments: ${JSON.stringify(message.input)}`);
  }
}
```

### Handling Tool Results

```typescript
for await (const message of result) {
  if (message.type === 'content') {
    console.log('Agent Response:', message.text);
  } else if (message.type === 'tool_use') {
    console.log(`Executing: ${message.name}`);
  } else if (message.type === 'tool_result') {
    console.log('Tool Result:', message.content);
  }
}
```

## Example: Database Query MCP Server

The following is a complete example showing how to create and use a database MCP server.

### Creating MCP Server

**db_mcp_server.py**:

```python
from fastmcp import FastMCP

mcp = FastMCP('database')

@mcp.tool()
def query_database(sql: str) -> str:
    """Execute a SQL query and return results"""
    # Implement database query logic
    return f"Query results for: {sql}"

@mcp.tool()
def get_schema(table_name: str) -> str:
    """Get the schema of a specific table"""
    # Return table structure
    return f"Schema for: {table_name}"

if __name__ == '__main__':
    mcp.run()
```

### Using in SDK

**TypeScript**:

```typescript
import { query } from '@tencent-ai/agent-sdk';

async function analyzeData() {
  const result = query({
    prompt: `
      I need to analyze our user activity data.
      1. First, check the schema of the users table
      2. Query for users active in the last 7 days
      3. Provide insights based on the results
    `,
    options: {
      mcpServers: {
        'database': {
          type: 'stdio',
          command: 'python',
          args: ['-m', 'db_mcp_server'],
          env: {
            DATABASE_URL: process.env.DATABASE_URL
          }
        }
      },
      permissionMode: 'acceptEdits'
    }
  });

  for await (const message of result) {
    if (message.type === 'content') {
      console.log('Analysis:', message.text);
    }
  }
}

analyzeData().catch(console.error);
```

**Python**:

```python
from codebuddy_agent_sdk import query
import os

async def analyze_data():
    result = query(
        prompt="""
            I need to analyze our user activity data.
            1. First, check the schema of the users table
            2. Query for users active in the last 7 days
            3. Provide insights based on the results
        """,
        options={
            'mcp_servers': {
                'database': {
                    'type': 'stdio',
                    'command': 'python',
                    'args': ['-m', 'db_mcp_server'],
                    'env': {
                        'DATABASE_URL': os.environ.get('DATABASE_URL')
                    }
                }
            },
            'permission_mode': 'acceptEdits'
        }
    )

    async for message in result:
        if message.get('type') == 'content':
            print('Analysis:', message.get('text'))

# Run example
import asyncio
asyncio.run(analyze_data())
```

## Example: API Integration MCP Server

The following example shows how to create an MCP server that connects to multiple APIs via HTTP.

### Server Implementation

**api_mcp_server.py**:

```python
from fastmcp import FastMCP
import httpx
import os

mcp = FastMCP('api-gateway')

async def call_api(method: str, path: str, **kwargs):
    """Helper to call APIs with authentication"""
    headers = kwargs.pop('headers', {})
    headers['Authorization'] = f"Bearer {os.environ.get('API_TOKEN')}"

    async with httpx.AsyncClient() as client:
        response = await client.request(
            method,
            f"https://api.example.com{path}",
            headers=headers,
            **kwargs
        )
        return response.json()

@mcp.tool()
async def get_github_repos(username: str) -> dict:
    """Get GitHub repositories for a user"""
    return await call_api('GET', f'/github/users/{username}/repos')

@mcp.tool()
async def search_issues(query: str, labels: list[str] = None) -> dict:
    """Search for issues in GitHub"""
    params = {'q': query}
    if labels:
        params['labels'] = ','.join(labels)
    return await call_api('GET', '/github/search/issues', params=params)

@mcp.tool()
async def create_slack_message(channel: str, text: str) -> dict:
    """Send a message to Slack"""
    return await call_api(
        'POST',
        '/slack/chat.postMessage',
        json={'channel': channel, 'text': text}
    )

if __name__ == '__main__':
    mcp.run()
```

### Using in SDK

```typescript
import { query } from '@tencent-ai/agent-sdk';

async function searchAndNotify() {
  const result = query({
    prompt: `
      1. Search for open issues labeled "bug" and "critical"
      2. Get my GitHub repositories
      3. Send a summary to the #dev-team Slack channel
    `,
    options: {
      mcpServers: {
        'api-gateway': {
          type: 'http',
          url: 'https://mcp-gateway.example.com/api',
          headers: {
            'X-API-Key': process.env.API_GATEWAY_KEY,
            'X-Request-ID': `req-${Date.now()}`
          }
        }
      },
      permissionMode: 'acceptEdits'
    }
  });

  for await (const message of result) {
    console.log(message);
  }
}
```

## Example: Remote SSE Server

SSE servers are suitable for scenarios requiring real-time data streaming or event pushing.

```typescript
import { query } from '@tencent-ai/agent-sdk';

async function monitorSystem() {
  const result = query({
    prompt: 'Monitor system metrics and alert if any threshold is exceeded',
    options: {
      mcpServers: {
        'monitoring': {
          type: 'sse',
          url: 'https://monitor.example.com/mcp/events',
          headers: {
            'Authorization': `Bearer ${process.env.MONITOR_TOKEN}`,
            'X-Client-ID': 'codebuddy-sdk'
          }
        }
      }
    }
  });

  for await (const message of result) {
    if (message.type === 'content') {
      console.log('Alert:', message.text);
    }
  }
}
```

## Error Handling

When handling MCP server connections, monitor initialization status and identify failed connections:

### Checking Server Initialization Status

**TypeScript**:

```typescript
import { query } from '@tencent-ai/agent-sdk';

const result = query({
  prompt: 'Use my MCP tools',
  options: {
    mcpServers: {
      'my-tool': {
        type: 'stdio',
        command: 'python',
        args: ['-m', 'my_mcp_server']
      }
    }
  }
});

for await (const message of result) {
  // Check MCP server status during initialization
  if (message.type === 'system' && message.subtype === 'init') {
    const failedServers = message.mcp_servers.filter(
      s => s.status !== 'connected'
    );
    if (failedServers.length > 0) {
      console.warn('Failed to connect:', failedServers);
    }
  }

  // Handle execution errors
  if (message.type === 'result' && message.subtype === 'error_during_execution') {
    console.error('Tool execution failed:', message);
  }
}
```

**Python**:

```python
from codebuddy_agent_sdk import query

result = query(
    prompt='Use my MCP tools',
    options={
        'mcp_servers': {
            'my-tool': {
                'type': 'stdio',
                'command': 'python',
                'args': ['-m', 'my_mcp_server']
            }
        }
    }
)

async for message in result:
    # Check MCP server status during initialization
    if message.get('type') == 'system' and message.get('subtype') == 'init':
        failed_servers = [
            s for s in message.get('mcp_servers', [])
            if s.get('status') != 'connected'
        ]
        if failed_servers:
            print(f'Failed to connect: {failed_servers}')

    # Handle execution errors
    if message.get('type') == 'result' and message.get('subtype') == 'error_during_execution':
        print('Tool execution failed:', message)
```

## Related Documentation

- [SDK Overview](sdk.md)
- [TypeScript SDK Reference](sdk-typescript.md)
- [Python SDK Reference](sdk-python.md)
- [MCP Usage Documentation](mcp.md)
- [SDK Permission System](sdk-permissions.md)
- [SDK Hooks System](sdk-hooks.md)

## Additional Resources

- [MCP Official Documentation](https://modelcontextprotocol.io/)
- [MCP Python SDK - FastMCP](https://github.com/modelcontextprotocol/python-sdk)
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
