Skip to content

3.4 开发工具配置 ​

🎯 学习目标:配置完整的MCP开发工具链,包括IDE、调试工具、版本控制等
⏱️ 预计时间:35分钟
📊 难度等级:⭐⭐⭐

🛠️ 工具链概览 ​

一个完整的MCP开发环境需要以下工具:

🎨 代码编辑器配置 ​

🏆 VS Code配置(强烈推荐) ​

VS Code是MCP开发的最佳选择,因为它:

  • 🔌 丰富的扩展生态
  • 🐍 优秀的Python/TypeScript支持
  • 🛠️ 内置调试器
  • 🔄 Git集成
  • 📡 可能的官方MCP支持

📦 必需扩展安装 ​

bash
# 通过命令行安装扩展
code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylance
code --install-extension ms-vscode.vscode-typescript-next
code --install-extension ms-vscode.vscode-json
code --install-extension bradlc.vscode-tailwindcss  # 如果使用Web界面
code --install-extension ms-vscode.vscode-eslint
code --install-extension esbenp.prettier-vscode
code --install-extension ms-python.black-formatter
code --install-extension ms-python.flake8
code --install-extension ms-toolsai.jupyter
code --install-extension GitLab.gitlab-workflow
code --install-extension GitHub.copilot  # AI辅助编程

⚙️ VS Code工作区配置 ​

创建.vscode/settings.json:

json
{
    "// 通用设置": "",
    "editor.fontSize": 14,
    "editor.tabSize": 4,
    "editor.insertSpaces": true,
    "editor.renderWhitespace": "boundary",
    "editor.rulers": [80, 120],
    "files.trimTrailingWhitespace": true,
    "files.insertFinalNewline": true,
    
    "// Python设置": "",
    "python.defaultInterpreterPath": "./venv/bin/python",
    "python.formatting.provider": "black",
    "python.formatting.blackArgs": ["--line-length", "88"],
    "python.linting.enabled": true,
    "python.linting.flake8Enabled": true,
    "python.linting.flake8Args": ["--max-line-length", "88"],
    "python.linting.mypyEnabled": true,
    "python.testing.pytestEnabled": true,
    "python.testing.pytestArgs": ["tests", "-v"],
    
    "// TypeScript/JavaScript设置": "",
    "typescript.preferences.importModuleSpecifier": "relative",
    "javascript.preferences.importModuleSpecifier": "relative",
    "eslint.workingDirectories": ["./"],
    "editor.codeActionsOnSave": {
        "source.organizeImports": true,
        "source.fixAll.eslint": true
    },
    
    "// JSON设置": "",
    "json.schemas": [
        {
            "fileMatch": ["**/package.json"],
            "url": "https://json.schemastore.org/package.json"
        },
        {
            "fileMatch": ["**/.vscode/*.json"],
            "url": "https://json.schemastore.org/vscode-task.json"
        }
    ],
    
    "// 文件排除": "",
    "files.exclude": {
        "**/__pycache__": true,
        "**/*.pyc": true,
        "**/node_modules": true,
        "**/.git": true,
        "**/venv": true,
        "**/.env": true
    },
    
    "// 搜索排除": "",
    "search.exclude": {
        "**/node_modules": true,
        "**/venv": true,
        "**/*.min.js": true
    }
}

🚀 任务配置 ​

创建.vscode/tasks.json:

json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "MCP Server - Python",
            "type": "shell",
            "command": "${workspaceFolder}/venv/bin/python",
            "args": ["src/server.py"],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "new"
            },
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": []
        },
        {
            "label": "MCP Server - Node.js",
            "type": "shell",
            "command": "npm",
            "args": ["run", "dev"],
            "group": "build",
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "new"
            },
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": ["$tsc"]
        },
        {
            "label": "Run Tests - Python",
            "type": "shell",
            "command": "${workspaceFolder}/venv/bin/python",
            "args": ["-m", "pytest", "tests/", "-v"],
            "group": "test",
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "new"
            }
        },
        {
            "label": "Run Tests - Node.js",
            "type": "shell",
            "command": "npm",
            "args": ["test"],
            "group": "test",
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "new"
            }
        },
        {
            "label": "Format Code - Python",
            "type": "shell",
            "command": "${workspaceFolder}/venv/bin/python",
            "args": ["-m", "black", "src/", "tests/"],
            "group": "build",
            "presentation": {
                "echo": true,
                "reveal": "silent"
            }
        },
        {
            "label": "Format Code - TypeScript",
            "type": "shell",
            "command": "npx",
            "args": ["prettier", "--write", "src/**/*.ts"],
            "group": "build",
            "presentation": {
                "echo": true,
                "reveal": "silent"
            }
        }
    ]
}

🐛 调试配置 ​

创建.vscode/launch.json:

json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug MCP Server (Python)",
            "type": "python",
            "request": "launch",
            "program": "${workspaceFolder}/src/server.py",
            "args": [],
            "console": "integratedTerminal",
            "cwd": "${workspaceFolder}",
            "env": {
                "PYTHONPATH": "${workspaceFolder}/src"
            },
            "envFile": "${workspaceFolder}/.env"
        },
        {
            "name": "Debug MCP Server (Node.js)",
            "type": "node",
            "request": "launch",
            "program": "${workspaceFolder}/src/server.ts",
            "outFiles": ["${workspaceFolder}/dist/**/*.js"],
            "runtimeArgs": ["-r", "ts-node/register"],
            "env": {
                "NODE_ENV": "development"
            },
            "envFile": "${workspaceFolder}/.env"
        },
        {
            "name": "Debug Tests (Python)",
            "type": "python",
            "request": "launch",
            "module": "pytest",
            "args": ["tests/", "-v", "-s"],
            "cwd": "${workspaceFolder}",
            "console": "integratedTerminal"
        },
        {
            "name": "Attach to MCP Server",
            "type": "node",
            "request": "attach",
            "port": 9229,
            "restart": true,
            "localRoot": "${workspaceFolder}",
            "remoteRoot": "/app"
        }
    ]
}

🧠 其他优秀IDE配置 ​

WebStorm/PyCharm配置 ​

优点:

  • 🔍 强大的代码分析
  • 🛠️ 内置重构工具
  • 📊 优秀的调试体验
  • 🔄 Git集成

基础配置:

1. 配置Python解释器
   Settings → Project → Python Interpreter → 选择虚拟环境

2. 配置Node.js
   Settings → Languages & Frameworks → Node.js → 设置Node.js路径

3. 配置代码风格
   Settings → Editor → Code Style → 选择项目风格

4. 配置调试器
   Run/Debug Configurations → 添加Python/Node.js配置

Vim/Neovim配置 ​

适合:命令行工作者、远程开发

vim
" ~/.vimrc 或 ~/.config/nvim/init.vim
" 基础配置
set number
set relativenumber
set tabstop=4
set shiftwidth=4
set expandtab
set autoindent

" 插件管理(使用vim-plug)
call plug#begin('~/.vim/plugged')

" 语言支持
Plug 'neoclide/coc.nvim', {'branch': 'release'}  " LSP支持
Plug 'psf/black', {'for': 'python'}              " Python格式化
Plug 'prettier/vim-prettier'                     " JS/TS格式化

" 文件管理
Plug 'preservim/nerdtree'
Plug 'junegunn/fzf.vim'

" Git集成
Plug 'tpope/vim-fugitive'

call plug#end()

" 快捷键配置
nnoremap <leader>t :NERDTreeToggle<CR>
nnoremap <leader>f :Files<CR>
nnoremap <leader>g :Rg<CR>

🔍 专业调试工具 ​

🐛 MCP协议调试器 ​

创建MCP协议调试工具:

python
#!/usr/bin/env python3
"""
mcp_debugger.py - MCP协议调试工具
"""

import json
import asyncio
import httpx
import argparse
from datetime import datetime
from typing import Dict, Any
import colorama
from colorama import Fore, Style

colorama.init()

class MCPDebugger:
    def __init__(self, host: str = "localhost", port: int = 8080):
        self.base_url = f"http://{host}:{port}/mcp"
        self.message_id = 1
        
    def log_message(self, direction: str, message: Dict[str, Any]):
        """记录消息"""
        timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
        color = Fore.GREEN if direction == "SEND" else Fore.BLUE
        
        print(f"{color}[{timestamp}] {direction}{Style.RESET_ALL}")
        print(f"  {json.dumps(message, indent=2, ensure_ascii=False)}")
        print()
    
    def build_meta(self) -> Dict[str, Any]:
        """构造每请求的 _meta(无状态协议:版本与能力随每个请求携带)"""
        return {
            "io.modelcontextprotocol/protocolVersion": "2026-07-28",
            "io.modelcontextprotocol/clientCapabilities": {"elicitation": {}},
            "io.modelcontextprotocol/clientInfo": {
                "name": "MCP Debugger",
                "version": "1.0.0"
            }
        }

    async def send_request(self, client: httpx.AsyncClient, method: str, params: Dict[str, Any] = None):
        """通过 Streamable HTTP 发送 MCP 请求"""
        # 每个请求的 params 中必须注入 _meta
        request_params = params or {}
        request_params.setdefault("_meta", self.build_meta())

        request = {
            "jsonrpc": "2.0",
            "id": self.message_id,
            "method": method,
            "params": request_params
        }

        self.message_id += 1
        self.log_message("SEND", request)

        # Streamable HTTP:用 POST 发送,并带上协议相关请求头
        response = await client.post(
            self.base_url,
            json=request,
            headers={
                "Accept": "application/json, text/event-stream",
                "MCP-Protocol-Version": "2026-07-28",
                "Mcp-Method": method,
                "Content-Type": "application/json",
            }
        )

        # 兼容 application/json 与 text/event-stream(SSE)两种响应
        content_type = response.headers.get("Content-Type", "")
        if "text/event-stream" in content_type:
            data_lines = [line for line in response.text.splitlines() if line.startswith("data:")]
            response_data = json.loads(data_lines[-1][5:].strip()) if data_lines else {}
        else:
            response_data = response.json()

        self.log_message("RECV", response_data)
        return response_data
    
    async def interactive_session(self):
        """交互式调试会话(基于 Streamable HTTP 传输)"""
        try:
            async with httpx.AsyncClient(timeout=30.0) as client:
                print(f"{Fore.YELLOW}🔗 已连接到 {self.base_url}{Style.RESET_ALL}")
                print("📝 可用命令: list_tools, call_tool <name>, discover, quit")
                print()

                # 能力发现(取代旧版 initialize 握手)
                await self.send_request(client, "server/discover")

                while True:
                    try:
                        command = input(f"{Fore.CYAN}mcp> {Style.RESET_ALL}").strip()

                        if command == "quit":
                            break
                        elif command == "list_tools":
                            await self.send_request(client, "tools/list")
                        elif command.startswith("call_tool "):
                            tool_name = command.split(" ", 1)[1]
                            await self.send_request(client, "tools/call", {
                                "name": tool_name,
                                "arguments": {}
                            })
                        elif command == "discover":
                            await self.send_request(client, "server/discover")
                        else:
                            print(f"{Fore.RED}未知命令: {command}{Style.RESET_ALL}")

                    except KeyboardInterrupt:
                        break
                    except Exception as e:
                        print(f"{Fore.RED}错误: {e}{Style.RESET_ALL}")

        except Exception as e:
            print(f"{Fore.RED}连接失败: {e}{Style.RESET_ALL}")

def main():
    parser = argparse.ArgumentParser(description="MCP协议调试工具")
    parser.add_argument("--host", default="localhost", help="MCP服务器主机")
    parser.add_argument("--port", type=int, default=8080, help="MCP服务器端口")
    
    args = parser.parse_args()
    
    debugger = MCPDebugger(args.host, args.port)
    asyncio.run(debugger.interactive_session())

if __name__ == "__main__":
    main()

🌐 HTTP调试工具 ​

创建HTTP MCP调试器:

javascript
// mcp-http-debugger.js - HTTP版本的MCP调试器
const express = require('express');
const axios = require('axios');
const chalk = require('chalk');

class MCPHTTPDebugger {
    constructor(targetUrl = 'http://localhost:3000') {
        this.targetUrl = targetUrl;
        this.messageId = 1;
        this.app = express();
        this.setupRoutes();
    }
    
    setupRoutes() {
        this.app.use(express.json());
        this.app.use(express.static('public'));
        
        // 代理所有MCP请求
        this.app.post('/mcp/*', async (req, res) => {
            const method = req.path.replace('/mcp/', '');
            const mcpRequest = {
                jsonrpc: '2.0',
                id: this.messageId++,
                method: method,
                params: req.body
            };
            
            this.logMessage('SEND', mcpRequest);
            
            try {
                const response = await axios.post(this.targetUrl, mcpRequest, {
                    headers: { 'Content-Type': 'application/json' }
                });
                
                this.logMessage('RECV', response.data);
                res.json(response.data);
            } catch (error) {
                console.error(chalk.red('请求失败:'), error.message);
                res.status(500).json({
                    jsonrpc: '2.0',
                    id: mcpRequest.id,
                    error: {
                        code: -32603,
                        message: 'Internal error',
                        data: error.message
                    }
                });
            }
        });
        
        // 调试界面
        this.app.get('/', (req, res) => {
            res.send(`
                <html>
                <head><title>MCP HTTP Debugger</title></head>
                <body>
                    <h1>MCP HTTP Debugger</h1>
                    <div>
                        <h2>发送请求</h2>
                        <select id="method">
                            <option value="server/discover">server/discover</option>
                            <option value="tools/list">tools/list</option>
                            <option value="tools/call">tools/call</option>
                        </select>
                        <br><br>
                        <textarea id="params" rows="10" cols="50">{}</textarea>
                        <br><br>
                        <button onclick="sendRequest()">发送</button>
                    </div>
                    <div id="response"></div>
                    
                    <script>
                        async function sendRequest() {
                            const method = document.getElementById('method').value;
                            const params = JSON.parse(document.getElementById('params').value || '{}');
                            
                            const response = await fetch('/mcp/' + method, {
                                method: 'POST',
                                headers: {'Content-Type': 'application/json'},
                                body: JSON.stringify(params)
                            });
                            
                            const result = await response.json();
                            document.getElementById('response').innerHTML = 
                                '<pre>' + JSON.stringify(result, null, 2) + '</pre>';
                        }
                    </script>
                </body>
                </html>
            `);
        });
    }
    
    logMessage(direction, message) {
        const timestamp = new Date().toISOString().split('T')[1].slice(0, -1);
        const color = direction === 'SEND' ? chalk.green : chalk.blue;
        
        console.log(color(`[${timestamp}] ${direction}`));
        console.log('  ' + JSON.stringify(message, null, 2));
        console.log();
    }
    
    start(port = 3001) {
        this.app.listen(port, () => {
            console.log(chalk.yellow(`🔗 MCP HTTP调试器启动: http://localhost:${port}`));
            console.log(chalk.yellow(`📡 目标MCP服务器: ${this.targetUrl}`));
        });
    }
}

// 使用方式
const debugger = new MCPHTTPDebugger(process.argv[2] || 'http://localhost:3000');
debugger.start(3001);

🧪 测试工具配置 ​

🐍 Python测试环境 ​

创建pytest.ini:

ini
[tool:pytest]
testpaths = tests
python_files = test_*.py *_test.py
python_classes = Test*
python_functions = test_*
addopts = 
    -v
    --tb=short
    --strict-markers
    --strict-config
    --color=yes
    --durations=10
markers =
    unit: 单元测试
    integration: 集成测试
    slow: 慢速测试
    mcp: MCP相关测试

安装测试依赖:

bash
# 在虚拟环境中
pip install pytest pytest-asyncio pytest-cov pytest-mock
pip install httpx  # 用于 HTTP / Streamable HTTP 测试

创建测试示例:

python
# tests/test_mcp_server.py
import pytest
import asyncio
import json
from unittest.mock import Mock, patch

class TestMCPServer:
    @pytest.fixture
    def mcp_server(self):
        """MCP服务器fixture"""
        from src.server import MCPServer
        return MCPServer()
    
    @pytest.mark.asyncio
    async def test_discover(self, mcp_server):
        """测试能力发现(取代旧版 initialize 握手)"""
        request = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "server/discover",
            "params": {
                "_meta": {
                    "io.modelcontextprotocol/protocolVersion": "2026-07-28",
                    "io.modelcontextprotocol/clientCapabilities": {"elicitation": {}},
                    "io.modelcontextprotocol/clientInfo": {"name": "test", "version": "1.0"}
                }
            }
        }
        
        response = await mcp_server.handle_request(request)
        
        assert response["jsonrpc"] == "2.0"
        assert response["id"] == 1
        assert "result" in response
        assert "2026-07-28" in response["result"]["supportedVersions"]
    
    @pytest.mark.asyncio
    async def test_list_tools(self, mcp_server):
        """测试工具列表"""
        request = {
            "jsonrpc": "2.0",
            "id": 2,
            "method": "tools/list",
            "params": {}
        }
        
        response = await mcp_server.handle_request(request)
        
        assert response["jsonrpc"] == "2.0"
        assert "result" in response
        assert "tools" in response["result"]
    
    @pytest.mark.mcp
    @pytest.mark.integration
    async def test_tool_call_integration(self, mcp_server):
        """集成测试:工具调用"""
        # 先获取工具列表
        list_request = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "tools/list"
        }
        
        list_response = await mcp_server.handle_request(list_request)
        tools = list_response["result"]["tools"]
        
        if tools:
            # 调用第一个工具
            call_request = {
                "jsonrpc": "2.0",
                "id": 2,
                "method": "tools/call",
                "params": {
                    "name": tools[0]["name"],
                    "arguments": {}
                }
            }
            
            call_response = await mcp_server.handle_request(call_request)
            assert "result" in call_response or "error" in call_response

🟨 JavaScript/TypeScript测试环境 ​

安装测试依赖:

bash
npm install --save-dev jest @types/jest ts-jest
npm install --save-dev supertest  # HTTP测试
npm install --save-dev @modelcontextprotocol/sdk  # MCP SDK(stdio / Streamable HTTP)

创建jest.config.js:

javascript
module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'node',
    roots: ['<rootDir>/src', '<rootDir>/tests'],
    testMatch: [
        '**/__tests__/**/*.ts',
        '**/?(*.)+(spec|test).ts'
    ],
    transform: {
        '^.+\\.ts$': 'ts-jest'
    },
    collectCoverageFrom: [
        'src/**/*.ts',
        '!src/**/*.d.ts'
    ],
    coverageDirectory: 'coverage',
    coverageReporters: ['text', 'lcov', 'html'],
    setupFilesAfterEnv: ['<rootDir>/tests/setup.ts']
};

创建测试示例:

typescript
// tests/mcp-server.test.ts
import { MCPServer } from '../src/server';

describe('MCP Server', () => {
    let server: MCPServer;
    
    beforeEach(() => {
        server = new MCPServer();
    });
    
    afterEach(async () => {
        await server.close();
    });
    
    test('should discover capabilities correctly', async () => {
        const request = {
            jsonrpc: '2.0',
            id: 1,
            method: 'server/discover',
            params: {
                _meta: {
                    "io.modelcontextprotocol/protocolVersion": "2026-07-28",
                    "io.modelcontextprotocol/clientCapabilities": { elicitation: {} },
                    "io.modelcontextprotocol/clientInfo": { name: 'test', version: '1.0' }
                }
            }
        };
        
        const response = await server.handleRequest(request);
        
        expect(response.jsonrpc).toBe('2.0');
        expect(response.id).toBe(1);
        expect(response.result).toBeDefined();
        expect(response.result.supportedVersions).toContain('2026-07-28');
    });
    
    test('should list tools', async () => {
        const request = {
            jsonrpc: '2.0',
            id: 2,
            method: 'tools/list',
            params: {}
        };
        
        const response = await server.handleRequest(request);
        
        expect(response.result).toHaveProperty('tools');
        expect(Array.isArray(response.result.tools)).toBe(true);
    });
});

📚 文档工具配置 ​

📖 API文档生成 ​

Python - Sphinx配置:

bash
# 安装Sphinx
pip install sphinx sphinx-rtd-theme sphinx-autodoc-typehints

# 初始化文档
sphinx-quickstart docs

# 配置 docs/conf.py
extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.viewcode',
    'sphinx.ext.napoleon',
    'sphinx_rtd_theme'
]

html_theme = 'sphinx_rtd_theme'

TypeScript - TypeDoc配置:

bash
# 安装TypeDoc
npm install --save-dev typedoc

# 配置 typedoc.json
{
    "entryPoints": ["src/index.ts"],
    "out": "docs",
    "theme": "default",
    "includeVersion": true,
    "exclude": ["**/*.test.ts", "**/*.spec.ts"]
}

🎯 本节小结 ​

通过这一小节,你应该已经掌握了:

✅ 完整工具链:了解MCP开发所需的各种工具
✅ IDE配置:配置VS Code等开发环境
✅ 调试工具:MCP协议专用调试器的使用
✅ 测试环境:Python和TypeScript测试框架配置
✅ 文档工具:API文档生成工具的使用

🔗 配置检查清单 ​

在进入下一小节之前,请确认:

  • [ ] IDE/编辑器配置完成
  • [ ] 调试器可以正常工作
  • [ ] 测试框架安装并配置
  • [ ] 版本控制工具可用
  • [ ] 文档生成工具就绪

开发工具配置完成!接下来进行最终的环境验证。 ✅


👉 下一小节:3.5 环境验证

内容依据 MCP 官方规范整理 · 规范以 官方文档 为准