> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/QwenLM/qwen-code/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server Tools

> Integrate external tools via Model Context Protocol

# MCP Server Tools

Model Context Protocol (MCP) servers extend Qwen Code's capabilities by providing access to external tools, APIs, and data sources.

## Overview

MCP servers act as bridges between Qwen Code and external systems, allowing the AI to:

* **Discover tools:** List available tools with schemas
* **Execute tools:** Call tools with structured parameters
* **Access resources:** Read data from external sources
* **Extend functionality:** Add custom capabilities without modifying Qwen Code

## Architecture

### Integration Flow

```
Qwen Code
    │
    v
┌──────────────────────────┐
│ MCP Client                │
│ (mcp-client.ts)           │
│                            │
│ 1. Discover servers        │
│ 2. Connect via transport   │
│ 3. Fetch tool schemas      │
│ 4. Register in registry    │
└──────────┬───────────────┘
           │
           v
┌──────────────────────────┐
│ Tool Registry              │
│                            │
│ - Built-in tools           │
│ - MCP tools (dynamic)      │
└──────────┬───────────────┘
           │
           v
┌──────────────────────────┐
│ MCP Tool Wrapper           │
│ (mcp-tool.ts)              │
│                            │
│ - Confirmation logic       │
│ - Parameter validation     │
│ - Execution & response     │
└──────────┬───────────────┘
           │
           v
┌──────────────────────────┐
│ MCP Server                 │
│ (External Process)         │
│                            │
│ - Custom tools             │
│ - API integrations         │
│ - Database access          │
└──────────────────────────┘
```

### Transport Mechanisms

Qwen Code supports three transport types:

#### 1. Stdio Transport

Communicates via standard input/output:

```json theme={null}
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["path/to/server.js"],
      "transport": "stdio"
    }
  }
}
```

**Use for:**

* Local scripts
* Command-line tools
* Simple integrations

#### 2. SSE Transport

Server-Sent Events over HTTP:

```json theme={null}
{
  "mcpServers": {
    "remote-server": {
      "url": "https://api.example.com/mcp",
      "transport": "sse",
      "headers": {
        "Authorization": "Bearer $API_TOKEN"
      }
    }
  }
}
```

**Use for:**

* Remote services
* Cloud APIs
* Webhooks

#### 3. Streamable HTTP

HTTP streaming:

```json theme={null}
{
  "mcpServers": {
    "http-server": {
      "url": "https://api.example.com/mcp",
      "transport": "streamable-http"
    }
  }
}
```

**Use for:**

* RESTful APIs
* Modern web services

## Configuration

### Basic Setup

Add to `settings.json`:

```json theme={null}
{
  "mcpServers": {
    "serverName": {
      "command": "path/to/server",
      "args": ["--arg1", "value1"],
      "env": {
        "API_KEY": "$MY_API_TOKEN"
      },
      "cwd": "./server-directory",
      "timeout": 30000,
      "trust": false
    }
  }
}
```

### Configuration Properties

```typescript theme={null}
interface MCPServerConfig {
  // Execution
  command?: string;           // Command to run server
  args?: string[];           // Command arguments
  env?: Record<string, string>; // Environment variables
  cwd?: string;              // Working directory
  
  // Connection
  url?: string;              // For SSE/HTTP transport
  transport?: 'stdio' | 'sse' | 'streamable-http';
  headers?: Record<string, string>; // HTTP headers
  
  // Behavior
  timeout?: number;          // Timeout in ms
  trust?: boolean;           // Skip confirmation
  disabled?: boolean;        // Disable this server
}
```

### Environment Variables

Use `$VAR_NAME` syntax for environment variables:

```json theme={null}
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "$GITHUB_PERSONAL_ACCESS_TOKEN"
      }
    }
  }
}
```

Variables are resolved from:

1. Process environment
2. User's shell environment
3. `.env` files (if supported)

### Global MCP Settings

```json theme={null}
{
  "mcp": {
    "allowed": ["trusted-server"],     // Allowlist
    "excluded": ["experimental-server"], // Blocklist
    "serverCommand": "node"             // Default command
  }
}
```

## Tool Discovery

### Discovery Process

```typescript theme={null}
// packages/core/src/tools/mcp-client.ts
export async function discoverMcpTools(
  config: Config,
): Promise<void> {
  const serverConfigs = config.getMcpServers();
  
  for (const [name, serverConfig] of Object.entries(serverConfigs)) {
    // 1. Create transport
    const transport = createTransport(serverConfig);
    
    // 2. Connect to server
    const client = new Client({ name, version: '1.0' });
    await client.connect(transport);
    
    // 3. List available tools
    const toolsList = await client.listTools();
    
    // 4. Register each tool
    for (const toolDef of toolsList.tools) {
      const mcpTool = new DiscoveredMCPTool(
        toolDef,
        name,
        serverConfig.trust,
      );
      config.getToolRegistry().registerTool(mcpTool);
    }
  }
}
```

### Tool Registration

MCP tools are registered with unique names:

```
Original: get_user
Registered: mcp_github_get_user

Original: list_repos  
Registered: mcp_github_list_repos
```

Naming pattern: `mcp_{serverName}_{toolName}`

This prevents conflicts between:

* Built-in tools
* Different MCP servers
* Tools with same names

## Tool Execution

### Execution Flow

```typescript theme={null}
// User/Model requests tool
mcp_github_get_user({ username: "octocat" });

// 1. Tool validation
const tool = registry.getTool("mcp_github_get_user");

// 2. Confirmation (if needed)
if (requiresConfirmation) {
  await confirmWithUser();
}

// 3. Call MCP server
const result = await mcpClient.callTool({
  name: "get_user",
  arguments: { username: "octocat" },
});

// 4. Process response
return {
  llmContent: result.content,
  returnDisplay: formatForUI(result),
};
```

### Confirmation

MCP tools require confirmation unless:

1. **Server is trusted:**
   ```json theme={null}
   {
     "mcpServers": {
       "my-server": {
         "trust": true  // Skip confirmations
       }
     }
   }
   ```

2. **Tool is read-only:**
   ```typescript theme={null}
   // MCP tool annotations
   {
     readOnlyHint: true,  // Safe, no confirmation
     destructiveHint: false,
     idempotentHint: true,
     openWorldHint: false,
   }
   ```

3. **User allowlisted it:**
   * Choose "Always allow" in confirmation dialog
   * Applies to current session

### Tool Annotations

MCP tools can provide hints about their behavior:

```typescript theme={null}
interface McpToolAnnotations {
  readOnlyHint?: boolean;      // Safe read operation
  destructiveHint?: boolean;   // Modifies or deletes data
  idempotentHint?: boolean;    // Same result on repeated calls
  openWorldHint?: boolean;     // Accesses external network
}
```

These help Qwen Code make informed decisions about confirmation and execution.

## Examples

### GitHub Server

```json theme={null}
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-github"
      ],
      "env": {
        "GITHUB_TOKEN": "$GITHUB_PERSONAL_ACCESS_TOKEN"
      }
    }
  }
}
```

**Available Tools:**

* `mcp_github_create_or_update_file`
* `mcp_github_search_repositories`
* `mcp_github_create_repository`
* `mcp_github_get_file_contents`
* `mcp_github_push_files`
* `mcp_github_create_issue`
* `mcp_github_create_pull_request`
* `mcp_github_fork_repository`
* `mcp_github_create_branch`

### Filesystem Server

```json theme={null}
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/allowed/path"
      ]
    }
  }
}
```

**Available Tools:**

* `mcp_filesystem_read_file`
* `mcp_filesystem_read_multiple_files`
* `mcp_filesystem_write_file`
* `mcp_filesystem_create_directory`
* `mcp_filesystem_list_directory`
* `mcp_filesystem_move_file`
* `mcp_filesystem_search_files`
* `mcp_filesystem_get_file_info`

### Database Server

```json theme={null}
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-postgres"
      ],
      "env": {
        "POSTGRES_CONNECTION_STRING": "$DATABASE_URL"
      }
    }
  }
}
```

**Available Tools:**

* `mcp_postgres_query`
* `mcp_postgres_list_tables`
* `mcp_postgres_describe_table`
* `mcp_postgres_insert`
* `mcp_postgres_update`

### Custom Server

```json theme={null}
{
  "mcpServers": {
    "my-custom-server": {
      "command": "node",
      "args": ["./mcp-servers/custom.js"],
      "cwd": "./",
      "timeout": 60000,
      "trust": false
    }
  }
}
```

## Creating MCP Servers

### Server Structure

MCP servers follow a standard protocol:

```typescript theme={null}
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const server = new Server(
  {
    name: 'my-server',
    version: '1.0.0',
  },
  {
    capabilities: {
      tools: {},
    },
  },
);

// Register tools
server.setRequestHandler('tools/list', async () => ({
  tools: [
    {
      name: 'my_tool',
      description: 'Does something useful',
      inputSchema: {
        type: 'object',
        properties: {
          param: {
            type: 'string',
            description: 'A parameter',
          },
        },
        required: ['param'],
      },
    },
  ],
}));

server.setRequestHandler('tools/call', async (request) => {
  const { name, arguments: args } = request.params;
  
  if (name === 'my_tool') {
    const result = await doSomething(args.param);
    return {
      content: [
        {
          type: 'text',
          text: `Result: ${result}`,
        },
      ],
    };
  }
  
  throw new Error(`Unknown tool: ${name}`);
});

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

### Tool Schema

Define tools with JSON Schema:

```typescript theme={null}
{
  name: 'search_code',
  description: 'Search for code patterns in the repository',
  inputSchema: {
    type: 'object',
    properties: {
      query: {
        type: 'string',
        description: 'Search query (regex supported)',
      },
      file_pattern: {
        type: 'string',
        description: 'File pattern to search in (glob)',
      },
      case_sensitive: {
        type: 'boolean',
        description: 'Whether search is case-sensitive',
        default: false,
      },
    },
    required: ['query'],
  },
  annotations: {
    readOnlyHint: true,  // Safe read operation
  },
}
```

### Response Format

Return results in MCP format:

```typescript theme={null}
return {
  content: [
    // Text content
    {
      type: 'text',
      text: 'Search found 5 results',
    },
    // Image content
    {
      type: 'image',
      data: base64Data,
      mimeType: 'image/png',
    },
    // Resource link
    {
      type: 'resource',
      resource: {
        uri: 'file:///path/to/file',
        text: 'Content...',
      },
    },
  ],
  isError: false,
};
```

## Security

### Trust Levels

**Untrusted (default):**

* Requires confirmation for each tool use
* Shows tool name and parameters
* User can allowlist specific tools

**Trusted:**

* No confirmation required
* Use only for verified servers
* Set `trust: true` in config

### Best Practices

1. **Review Server Code:**
   * Inspect server implementation
   * Verify it's from trusted source
   * Check for suspicious behavior

2. **Limit Permissions:**
   * Give minimum necessary access
   * Use environment variables for secrets
   * Don't store secrets in config

3. **Use Allowlists:**
   ```json theme={null}
   {
     "mcp": {
       "allowed": ["github", "filesystem"]
     }
   }
   ```

4. **Monitor Activity:**
   * Review confirmation prompts
   * Check logs for suspicious calls
   * Disable unused servers

5. **Sandbox if Possible:**
   ```bash theme={null}
   export QWEN_SANDBOX=docker
   ```

### Environment Variable Security

Store sensitive data in environment:

```bash theme={null}
# .env (never commit this)
export GITHUB_TOKEN="ghp_..."
export DATABASE_URL="postgresql://..."
export API_KEY="sk-..."
```

Reference in config:

```json theme={null}
{
  "env": {
    "GITHUB_TOKEN": "$GITHUB_TOKEN",
    "API_KEY": "$API_KEY"
  }
}
```

## Troubleshooting

### Server Not Found

**Error:** `MCP server "my-server" not found`

**Solutions:**

1. Check server name in config
2. Verify command is in PATH
3. Use absolute path: `/usr/local/bin/server`
4. Check `disabled: false`

### Connection Timeout

**Error:** `Connection to MCP server timed out`

**Solutions:**

1. Increase timeout: `"timeout": 60000`
2. Check server starts quickly
3. Verify network connectivity (for remote servers)
4. Check server logs

### Tool Not Available

**Error:** `Tool "mcp_server_tool" not found`

**Solutions:**

1. Restart Qwen Code (tools discovered on startup)
2. Check server is enabled
3. Verify server implements tool
4. Check for name conflicts

### Permission Denied

**Error:** `Permission denied: /path/to/server`

**Solutions:**

1. Make server executable: `chmod +x /path/to/server`
2. Check file permissions
3. Run with correct user

## Implementation

**Key Files:**

* `packages/core/src/tools/mcp-client.ts` - Discovery and client
* `packages/core/src/tools/mcp-tool.ts` - Tool wrapper
* `packages/core/src/tools/mcp-client-manager.ts` - Connection management

### Client Manager

```typescript theme={null}
export class McpClientManager {
  private clients = new Map<string, McpDirectClient>();

  async getOrCreateClient(
    serverName: string,
    config: MCPServerConfig,
  ): Promise<McpDirectClient> {
    if (this.clients.has(serverName)) {
      return this.clients.get(serverName)!;
    }

    const transport = createTransport(config);
    const client = new Client({ name: serverName, version: '1.0' });
    await client.connect(transport);

    this.clients.set(serverName, client);
    return client;
  }
}
```

## Next Steps

* [Tools System](../tools-system.mdx) - Tools architecture
* [File System Tools](./file-system.mdx) - Built-in file operations
* [Shell Tool](./shell.mdx) - Shell command execution
* [Configuration System](../configuration-system.mdx) - MCP configuration
