OpenCode 进阶使用指南(第三章:MCP 集成)

本文档是《OpenCode 进阶使用指南》的第三章专注于 MCP(Model Context Protocol)集成的深入讲解预计阅读时间:30-40 分钟


目录

  1. [什么是 MCP](#什么是 MCP "#%E4%BB%80%E4%B9%88%E6%98%AF-mcp")
  2. [MCP 的核心概念](#MCP 的核心概念 "#mcp-%E7%9A%84%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5")
  3. [MCP 与 Skills 的区别](#MCP 与 Skills 的区别 "#mcp-%E4%B8%8E-skills-%E7%9A%84%E5%8C%BA%E5%88%AB")
  4. [配置你的第一个 MCP](#配置你的第一个 MCP "#%E9%85%8D%E7%BD%AE%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA-mcp")
  5. [常用 MCP 详解](#常用 MCP 详解 "#%E5%B8%B8%E7%94%A8-mcp-%E8%AF%A6%E8%A7%A3")
  6. [开发自定义 MCP](#开发自定义 MCP "#%E5%BC%80%E5%8F%91%E8%87%AA%E5%AE%9A%E4%B9%89-mcp")
  7. [MCP 安全实践](#MCP 安全实践 "#mcp-%E5%AE%89%E5%85%A8%E5%AE%9E%E8%B7%B5")
  8. 实战案例集
  9. 底层原理剖析
  10. 故障排查与优化

什么是 MCP

3.1.1 从一个实际问题说起

想象这样一个场景:你在开发一个电商网站,需要测试购物车功能。测试流程是:

  1. 打开网站首页
  2. 搜索商品
  3. 选择商品加入购物车
  4. 进入购物车查看
  5. 修改数量
  6. 结算

传统的测试方式是:

  • 手动点击(费时费力)
  • 写自动化测试脚本(需要学习 Selenium/Playwright)
  • 找 QA 帮忙(沟通成本高)

如果能让 AI 直接操作浏览器帮你测试,是不是就很方便?

这就是 MCP 要解决的核心问题:让 AI 能操作外部工具和系统

3.1.2 MCP 的定义

MCP(Model Context Protocol) 是一个开放的协议标准,它定义了 AI 模型如何与外部工具、数据源、服务进行交互。

你可以把 MCP 理解为 AI 世界的"USB 接口":

  • 就像 USB 统一了各种外设的连接方式
  • MCP 统一了 AI 与各种工具的连接方式

核心特点

  1. 标准化:统一的接口定义,不同工具遵循相同规范
  2. 安全性:细粒度权限控制,可审计可追溯
  3. 扩展性:支持任意类型的工具和服务
  4. 灵活性:本地和远程服务都能连接

3.1.3 MCP 能解决什么问题

场景一:浏览器自动化

  • 自动测试 Web 应用
  • 截图生成文档
  • 数据抓取

场景二:数据库操作

  • 查询数据
  • 生成报表
  • 数据迁移

场景三:API 集成

  • 调用第三方服务
  • 内部系统集成
  • 自动化工作流

场景四:文件系统

  • 批量文件处理
  • 文档转换
  • 代码生成

场景五:版本控制

  • 自动化 Git 操作
  • PR 审查
  • 发布管理

3.1.4 MCP 的生态系统

官方 MCP

  • Playwright MCP:浏览器自动化
  • GitHub MCP:GitHub 操作
  • Filesystem MCP:文件系统访问
  • SQLite MCP:SQLite 数据库

社区 MCP

  • Figma MCP:设计稿操作
  • Notion MCP:笔记管理
  • Slack MCP:消息通知
  • AWS MCP:云服务操作

企业 MCP

  • 内部 API MCP
  • 数据库 MCP
  • 业务系统 MCP

MCP 的核心概念

3.2.1 MCP 架构

arduino 复制代码
┌─────────────────────────────────────────┐
│              OpenCode                   │
│         ┌──────────────────┐            │
│         │   MCP Client     │            │
│         └────────┬─────────┘            │
└──────────────────┼──────────────────────┘
                   │
          ┌────────┴────────┐
          │   MCP Protocol   │
          │  (stdio / sse)   │
          └────────┬────────┘
                   │
       ┌───────────┼───────────┐
       │           │           │
┌──────┴──────┐ ┌─┴────────┐ ┌┴──────────┐
│ MCP Server  │ │  MCP     │ │  MCP      │
│ (Playwright)│ │  Server  │ │  Server   │
│             │ │ (GitHub) │ │ (Filesystem)
└─────────────┘ └──────────┘ └───────────┘

MCP Client:OpenCode 内置的 MCP 客户端,负责管理 MCP 连接。

MCP Server:独立的进程或服务,实现 MCP 协议,提供具体功能。

传输层:Client 和 Server 之间的通信方式:

  • stdio:标准输入输出(本地进程)
  • sse:Server-Sent Events(远程服务)

3.2.2 资源(Resources)

什么是资源:资源是 MCP 中的数据对象,可以是文件、数据库记录、API 响应等。

资源标识:每个资源都有唯一的 URI:

ruby 复制代码
file:///home/user/project/README.md
database://localhost:5432/mydb/users/123
github://repos/owner/repo/issues/456
browser://page/current-url

资源操作

  • resources/list:列出可用资源
  • resources/read:读取资源内容
  • resources/subscribe:订阅资源变化

3.2.3 工具(Tools)

什么是工具:工具是 MCP 提供的功能接口,可以被 AI 调用执行操作。

工具定义:每个工具都有明确的输入输出定义:

json 复制代码
{
  "name": "browser_navigate",
  "description": "导航到指定 URL",
  "inputSchema": {
    "type": "object",
    "properties": {
      "url": {
        "type": "string",
        "description": "目标 URL"
      }
    },
    "required": ["url"]
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "success": { "type": "boolean" },
      "title": { "type": "string" },
      "url": { "type": "string" }
    }
  }
}

工具调用

json 复制代码
{
  "tool": "browser_navigate",
  "params": {
    "url": "https://example.com"
  }
}

3.2.4 提示词(Prompts)

什么是提示词: MCP Server 可以预定义一些提示词模板,供 AI 使用。

示例

json 复制代码
{
  "name": "analyze_page",
  "description": "分析当前网页的性能和可访问性",
  "template": "请分析当前页面的以下方面:\n1. 加载性能\n2. SEO 优化\n3. 可访问性\n4. 最佳实践"
}

MCP 与 Skills 的区别

3.3.1 核心区别

维度 MCP Skills
定位 外部工具连接 内部知识封装
作用 扩展 AI 能力 规范 AI 行为
实现 独立进程/服务 Markdown 文件
范围 跨项目通用 项目/团队特定
权限 需要显式授权 默认允许

3.3.2 协作关系

MCP 和 Skills 不是竞争关系,而是互补关系

arduino 复制代码
┌─────────────────────────────────┐
│           用户请求               │
└──────────────┬──────────────────┘
               │
        ┌──────┴──────┐
        │   Skills    │ ← 决定"做什么"
        └──────┬──────┘
               │
        ┌──────┴──────┐
        │    MCP      │ ← 决定"用什么做"
        └──────┬──────┘
               │
        ┌──────┴──────┐
        │  外部工具    │
        └─────────────┘

示例流程

  1. 用户说"测试登录功能"
  2. Skills 系统匹配到"e2e-testing" Skill
  3. Skill 指导 AI 使用 Playwright MCP
  4. Playwright MCP 操作浏览器执行测试

3.3.3 选择指南

使用 MCP 的场景

  • 需要操作外部系统(浏览器、数据库、API)
  • 需要访问外部数据
  • 需要执行特定领域的专业工具

使用 Skills 的场景

  • 定义团队规范和流程
  • 封装重复性的开发任务
  • 沉淀领域知识和最佳实践

组合使用的场景

  • 用 Skills 定义测试流程,用 MCP 执行浏览器测试
  • 用 Skills 定义代码规范,用 MCP 操作 Git
  • 用 Skills 定义数据迁移流程,用 MCP 操作数据库

配置你的第一个 MCP

3.4.1 查看可用 MCP

bash 复制代码
# 列出已配置的 MCP
opencode mcp list

# 输出示例:
已配置的 MCP Servers:
1. playwright (enabled)
   - 浏览器自动化测试
   - 状态: 运行中

2. github (disabled)
   - GitHub 操作
   - 状态: 未启用

3.4.2 添加 MCP

方式一:交互式添加

bash 复制代码
opencode mcp add

# 交互提示:
? 选择 MCP 类型:
  ▸ Playwright (浏览器自动化)
    GitHub (GitHub 操作)
    Filesystem (文件系统)
    SQLite (SQLite 数据库)
    Custom (自定义)

? Playwright MCP 配置:
  可执行文件路径: /usr/local/bin/npx
  启动参数: @anthropic-ai/playwright-mcp-server

? 是否启用: Yes

✓ Playwright MCP 已添加并启动

方式二:配置文件添加

编辑 ~/.config/opencode/mcp.json

json 复制代码
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@anthropic-ai/playwright-mcp-server"],
      "env": {
        "DISPLAY": ":1"
      }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/github-mcp-server"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

3.4.3 配置参数详解

基本参数

参数 类型 说明 示例
command string 启动命令 "npx", "node", "python"
args array 命令参数 ["@anthropic-ai/playwright-mcp-server"]
env object 环境变量 {"TOKEN": "xxx"}
cwd string 工作目录 "/path/to/project"

高级参数

参数 类型 说明 示例
timeout number 超时时间(毫秒) 30000
restartOnError boolean 出错时重启 true
allowedTools array 允许的工具列表 ["browser_navigate"]
deniedTools array 禁止的工具列表 ["browser_evaluate"]

3.4.4 测试 MCP

添加 MCP 后,测试是否正常工作:

bash 复制代码
# 查看 MCP 状态
opencode mcp status playwright

# 输出:
Playwright MCP 状态:
- 状态: 运行中
- PID: 12345
- 运行时间: 5 分钟
- 可用工具: 12 个
  - browser_navigate
  - browser_click
  - browser_screenshot
  ...

# 测试工具调用
opencode mcp test playwright browser_navigate '{"url": "https://example.com"}'

# 输出:
✓ 工具调用成功
结果: {
  "success": true,
  "title": "Example Domain",
  "url": "https://example.com"
}

3.4.5 在 OpenCode 中使用 MCP

配置好 MCP 后,在对话中直接使用:

bash 复制代码
> 使用 Playwright 打开百度并搜索"OpenCode"

AI:[调用 playwright MCP]
     - browser_navigate: https://www.baidu.com
     - browser_click: [搜索框]
     - browser_type: OpenCode
     - browser_click: [百度一下按钮]
     - browser_screenshot: 保存结果

AI:已完成操作,截图保存在 /tmp/baidu_search.png

常用 MCP 详解

3.5.1 Playwright MCP(浏览器自动化)

功能概述:基于 Playwright 框架,提供完整的浏览器自动化能力。

主要工具

工具名 功能 示例
browser_navigate 导航到 URL 打开网页
browser_click 点击元素 点击按钮
browser_type 输入文本 填写表单
browser_screenshot 截图 保存页面截图
browser_evaluate 执行 JS 获取页面数据
browser_go_back 后退 返回上一页
browser_go_forward 前进 前进一页

实战示例

bash 复制代码
> 帮我测试登录功能:
> 1. 打开 http://localhost:3000/login
> 2. 填写用户名"admin"、密码"123456"
> 3. 点击登录按钮
> 4. 验证是否跳转到首页
> 5. 截图保存

AI 执行过程

javascript 复制代码
// 伪代码
async function testLogin() {
  // 1. 打开页面
  await browser_navigate({ url: 'http://localhost:3000/login' });

  // 2. 填写表单
  await browser_type({
    selector: 'input[name="username"]',
    text: 'admin',
  });
  await browser_type({
    selector: 'input[name="password"]',
    text: '123456',
  });

  // 3. 点击登录
  await browser_click({ selector: 'button[type="submit"]' });

  // 4. 等待跳转并验证
  await browser_wait_for_selector({ selector: '.dashboard' });
  const url = await browser_evaluate({
    script: 'window.location.href',
  });

  // 5. 截图
  await browser_screenshot({ path: '/tmp/login_result.png' });

  return { success: url.includes('/dashboard') };
}

3.5.2 GitHub MCP(GitHub 操作)

功能概述:提供 GitHub API 的封装,可以操作仓库、Issue、PR 等。

主要工具

工具名 功能 示例
github_create_issue 创建 Issue 提交 bug 报告
github_create_pull_request 创建 PR 提交代码变更
github_list_issues 列出 Issues 查看待办事项
github_get_file_contents 获取文件内容 读取代码
github_create_or_update_file 创建/更新文件 提交修改

实战示例

bash 复制代码
> 帮我创建一个 Issue:
> 标题:修复登录页面的响应式布局问题
> 内容:在移动端 375px 宽度下,登录按钮被截断
> 标签:bug, ui
> 分配给张三

AI 执行过程

javascript 复制代码
await github_create_issue({
  owner: 'mycompany',
  repo: 'my-project',
  title: '修复登录页面的响应式布局问题',
  body: `## 问题描述
在移动端 375px 宽度下,登录按钮被截断。

## 复现步骤
1. 打开登录页面
2. 使用 Chrome DevTools 切换到 iPhone SE 视图
3. 可以看到登录按钮右侧被截断

## 期望结果
登录按钮应该完整显示

## 实际结果
登录按钮右侧被截断约 20px

## 环境
- 浏览器:Chrome 120
- 设备:iPhone SE (375x667)`,
  labels: ['bug', 'ui'],
  assignees: ['zhangsan'],
});

3.5.3 Filesystem MCP(文件系统)

功能概述:提供安全的文件系统访问,可以读取、写入、搜索文件。

主要工具

工具名 功能 示例
read_file 读取文件 查看代码
write_file 写入文件 保存修改
list_directory 列出目录 浏览文件
search_files 搜索文件 查找代码
get_file_info 获取文件信息 查看元数据

安全配置

json 复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/filesystem-mcp-server"],
      "env": {
        "ALLOWED_PATHS": "/home/user/projects:/tmp/workspace"
      }
    }
  }
}

权限控制

  • 只能访问 ALLOWED_PATHS 指定的目录
  • 默认禁止访问 ~/.ssh, ~/.config 等敏感目录
  • 可以配置只读或读写权限

3.5.4 SQLite MCP(SQLite 数据库)

功能概述:提供 SQLite 数据库的查询和操作能力。

主要工具

工具名 功能 示例
sqlite_query 执行查询 SELECT * FROM users
sqlite_execute 执行语句 INSERT, UPDATE, DELETE
sqlite_list_tables 列出表 查看数据库结构
sqlite_get_schema 获取表结构 查看字段定义

实战示例

bash 复制代码
> 查询过去 7 天注册的用户数量,按天分组

AI 执行

sql 复制代码
SELECT
  date(created_at) as date,
  COUNT(*) as user_count
FROM users
WHERE created_at >= date('now', '-7 days')
GROUP BY date(created_at)
ORDER BY date;

开发自定义 MCP

3.6.1 MCP 开发基础

技术栈选择

语言 适用场景 示例
TypeScript/Node.js 大多数场景 官方 MCP 多为此
Python 数据科学、AI 机器学习相关
Go 高性能服务 企业级部署
Rust 系统级工具 性能敏感场景

官方 SDK

bash 复制代码
# TypeScript SDK
npm install @modelcontextprotocol/sdk

# Python SDK
pip install mcp

3.6.2 最小 MCP Server 示例

TypeScript 版本

typescript 复制代码
// server.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';

// 创建服务器
const server = new Server(
  {
    name: 'my-custom-mcp',
    version: '1.0.0',
  },
  {
    capabilities: {
      tools: {},
    },
  },
);

// 定义可用工具
const tools = [
  {
    name: 'hello',
    description: 'Say hello to someone',
    inputSchema: {
      type: 'object',
      properties: {
        name: {
          type: 'string',
          description: 'Name of the person to greet',
        },
      },
      required: ['name'],
    },
  },
];

// 处理工具列表请求
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return { tools };
});

// 处理工具调用请求
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (name === 'hello') {
    const greeting = `Hello, ${args.name}!`;
    return {
      content: [
        {
          type: 'text',
          text: greeting,
        },
      ],
    };
  }

  throw new Error(`Unknown tool: ${name}`);
});

// 启动服务器
const transport = new StdioServerTransport();
server.connect(transport);

console.error('Custom MCP Server running on stdio');

运行 MCP

bash 复制代码
# 编译 TypeScript
npx tsc server.ts

# 添加到 OpenCode 配置

mcp.json 中添加:

json 复制代码
{
  "mcpServers": {
    "my-custom": {
      "command": "node",
      "args": ["/path/to/server.js"]
    }
  }
}

3.6.3 MCP 协议详解

消息格式

MCP 使用 JSON-RPC 2.0 协议通信。

请求消息

json 复制代码
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "hello",
    "arguments": {
      "name": "World"
    }
  }
}

响应消息

json 复制代码
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Hello, World!"
      }
    ]
  }
}

错误消息

json 复制代码
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": {
      "details": "Missing required parameter: name"
    }
  }
}

3.6.4 实战:开发公司内部 API MCP

场景:公司有一套内部 API,想让 AI 能调用这些 API。

Step 1:定义 API 接口

typescript 复制代码
// 公司内部 API 定义
interface InternalAPI {
  // 获取用户信息
  getUser(userId: string): Promise<User>;

  // 创建工单
  createTicket(data: CreateTicketRequest): Promise<Ticket>;

  // 查询订单
  listOrders(params: ListOrdersParams): Promise<Order[]>;

  // 发送通知
  sendNotification(userId: string, message: string): Promise<void>;
}

Step 2:实现 MCP Server

typescript 复制代码
// internal-api-mcp.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';

// 公司内部 API 客户端
class InternalAPIClient {
  private baseURL: string;
  private token: string;

  constructor(baseURL: string, token: string) {
    this.baseURL = baseURL;
    this.token = token;
  }

  async getUser(userId: string) {
    const response = await fetch(`${this.baseURL}/users/${userId}`, {
      headers: { Authorization: `Bearer ${this.token}` },
    });
    return response.json();
  }

  async createTicket(data: any) {
    const response = await fetch(`${this.baseURL}/tickets`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${this.token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    });
    return response.json();
  }

  // ... 其他方法
}

// 创建 MCP Server
const apiClient = new InternalAPIClient(
  process.env.INTERNAL_API_URL!,
  process.env.INTERNAL_API_TOKEN!,
);

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

// 定义工具
const tools = [
  {
    name: 'get_user',
    description: '获取用户信息',
    inputSchema: {
      type: 'object',
      properties: {
        userId: { type: 'string', description: '用户 ID' },
      },
      required: ['userId'],
    },
  },
  {
    name: 'create_ticket',
    description: '创建工单',
    inputSchema: {
      type: 'object',
      properties: {
        title: { type: 'string', description: '工单标题' },
        description: { type: 'string', description: '工单描述' },
        priority: {
          type: 'string',
          enum: ['low', 'medium', 'high'],
          description: '优先级',
        },
      },
      required: ['title', 'description'],
    },
  },
];

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return { tools };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    switch (name) {
      case 'get_user': {
        const user = await apiClient.getUser(args.userId);
        return {
          content: [{ type: 'text', text: JSON.stringify(user, null, 2) }],
        };
      }

      case 'create_ticket': {
        const ticket = await apiClient.createTicket(args);
        return {
          content: [
            {
              type: 'text',
              text: `工单创建成功!\n工单号: ${ticket.id}\n标题: ${ticket.title}`,
            },
          ],
        };
      }

      default:
        throw new Error(`未知工具: ${name}`);
    }
  } catch (error) {
    return {
      content: [{ type: 'text', text: `错误: ${error.message}` }],
      isError: true,
    };
  }
});

const transport = new StdioServerTransport();
server.connect(transport);

Step 3:配置到 OpenCode

json 复制代码
{
  "mcpServers": {
    "internal-api": {
      "command": "node",
      "args": ["/path/to/internal-api-mcp.js"],
      "env": {
        "INTERNAL_API_URL": "https://api.company.com",
        "INTERNAL_API_TOKEN": "${INTERNAL_API_TOKEN}"
      }
    }
  }
}

Step 4:使用

bash 复制代码
> 查询用户 ID 为 12345 的信息

AI:[调用 internal-api MCP]
     - get_user: { userId: "12345" }

AI:用户信息:
   - 姓名:张三
   - 部门:技术部
   - 邮箱:zhangsan@company.com
   - 入职时间:2023-06-01

> 为他创建一个工单,标题是"申请显示器",高优先级

AI:[调用 internal-api MCP]
     - create_ticket: {
         title: "申请显示器",
         description: "申请一台 27 寸 4K 显示器",
         priority: "high"
       }

AI:工单创建成功!
   - 工单号:TICKET-2026-001234
   - 标题:申请显示器

MCP 安全实践

3.7.1 权限控制

工具级权限

json 复制代码
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@anthropic-ai/playwright-mcp-server"],
      "allowedTools": [
        "browser_navigate",
        "browser_click",
        "browser_screenshot"
      ],
      "deniedTools": [
        "browser_evaluate", // 禁止执行任意 JavaScript
        "browser_download" // 禁止下载文件
      ]
    }
  }
}

资源级权限

json 复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["@anthropic-ai/filesystem-mcp-server"],
      "env": {
        "ALLOWED_PATHS": "/home/user/projects",
        "DENIED_PATHS": "/home/user/projects/secret",
        "ALLOW_OPERATIONS": "read,list", // 只允许读取和列出
        "DENY_OPERATIONS": "write,delete" // 禁止写入和删除
      }
    }
  }
}

3.7.2 凭证管理

环境变量

bash 复制代码
# 不要将凭证硬编码在配置文件中
# 使用环境变量

export GITHUB_TOKEN="ghp_xxxxxxxx"
export DATABASE_PASSWORD="secret"

# 然后在 mcp.json 中引用
json 复制代码
{
  "mcpServers": {
    "github": {
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

密钥管理服务

企业环境建议使用专业的密钥管理:

json 复制代码
{
  "mcpServers": {
    "database": {
      "command": "node",
      "args": ["db-mcp-server.js"],
      "env": {
        "DB_PASSWORD_CMD": "aws secretsmanager get-secret-value --secret-id db-password"
      }
    }
  }
}

3.7.3 审计日志

启用审计

json 复制代码
{
  "mcp": {
    "audit": {
      "enabled": true,
      "logPath": "~/.opencode/logs/mcp-audit.log",
      "logLevel": "info" // debug, info, warn, error
    }
  }
}

日志格式

json 复制代码
{
  "timestamp": "2026-01-15T10:30:00Z",
  "server": "playwright",
  "tool": "browser_navigate",
  "params": {
    "url": "https://example.com"
  },
  "result": "success",
  "duration": 1200,
  "user": "developer@company.com"
}

3.7.4 网络安全

传输加密

  • 远程 MCP 服务必须使用 HTTPS
  • 本地 stdio 传输无需加密(进程间通信)

网络隔离

json 复制代码
{
  "mcpServers": {
    "internal-api": {
      "command": "node",
      "args": ["internal-mcp.js"],
      "network": {
        "allowedHosts": ["api.company.com"],
        "blockedHosts": ["*"],
        "proxy": "http://proxy.company.com:8080"
      }
    }
  }
}

实战案例集

3.8.1 案例一:自动化端到端测试

场景:电商网站的完整购物流程测试。

涉及 MCP

  • Playwright MCP:浏览器操作
  • SQLite MCP:验证数据库状态

测试流程

bash 复制代码
> 执行完整的购物流程测试:
> 1. 访问首页,验证页面加载
> 2. 搜索商品"iPhone",选择第一个结果
> 3. 加入购物车
> 4. 进入购物车,修改数量为 2
> 5. 结算,填写收货信息
> 6. 选择支付方式,完成支付
> 7. 验证订单在数据库中
> 8. 截图每个关键步骤

AI 执行过程

javascript 复制代码
// 步骤 1: 访问首页
await browser_navigate({ url: 'https://shop.example.com' });
await browser_wait_for_selector({ selector: '.product-list' });
await browser_screenshot({ path: '/tmp/test/step1_home.png' });

// 步骤 2: 搜索商品
await browser_type({
  selector: '[data-testid="search-input"]',
  text: 'iPhone',
});
await browser_click({ selector: '[data-testid="search-button"]' });
await browser_wait_for_selector({ selector: '.search-results' });
await browser_click({ selector: '.product-item:first-child' });
await browser_screenshot({ path: '/tmp/test/step2_product.png' });

// 步骤 3: 加入购物车
await browser_click({ selector: '[data-testid="add-to-cart"]' });
await browser_wait_for_selector({ selector: '.cart-notification' });

// 步骤 4: 进入购物车
await browser_click({ selector: '[data-testid="cart-icon"]' });
await browser_clear({ selector: '[data-testid="quantity-input"]' });
await browser_type({ selector: '[data-testid="quantity-input"]', text: '2' });
await browser_click({ selector: '[data-testid="update-cart"]' });
await browser_screenshot({ path: '/tmp/test/step4_cart.png' });

// 步骤 5: 结算
await browser_click({ selector: '[data-testid="checkout"]' });
await browser_type({ selector: '#name', text: '张三' });
await browser_type({ selector: '#phone', text: '13800138000' });
await browser_type({ selector: '#address', text: '北京市朝阳区xxx' });
await browser_screenshot({ path: '/tmp/test/step5_checkout.png' });

// 步骤 6: 支付
await browser_click({ selector: '[data-testid="payment-alipay"]' });
await browser_click({ selector: '[data-testid="place-order"]' });
await browser_wait_for_selector({ selector: '.order-success' });
await browser_screenshot({ path: '/tmp/test/step6_payment.png' });

// 步骤 7: 验证数据库
const orderResult = await sqlite_query({
  query: `
    SELECT * FROM orders 
    WHERE customer_name = '张三' 
    ORDER BY created_at DESC 
    LIMIT 1
  `,
});

// 验证
assert(orderResult.quantity === 2);
assert(orderResult.status === 'paid');

3.8.2 案例二:自动化文档生成

场景:根据代码自动生成 API 文档。

涉及 MCP

  • Filesystem MCP:读取代码文件
  • GitHub MCP:发布到 GitHub Pages

工作流程

bash 复制代码
> 帮我生成 API 文档:
> 1. 扫描 src/api 目录下的所有接口文件
> 2. 解析 JSDoc 注释
> 3. 生成 Markdown 格式的 API 文档
> 4. 创建 GitHub Pages 分支
> 5. 部署文档

3.8.3 案例三:智能运维助手

场景:自动排查服务器问题。

涉及 MCP

  • SSH MCP:连接服务器
  • Filesystem MCP:读取日志
  • Slack MCP:发送通知

工作流程

bash 复制代码
> 服务器报警了,帮我排查一下:
> 1. 连接到生产服务器
> 2. 查看最近 1 小时的错误日志
> 3. 检查 CPU、内存、磁盘使用情况
> 4. 如果发现问题,尝试自动修复
> 5. 发送报告到 Slack #ops 频道

底层原理剖析

3.9.1 MCP 协议栈

scss 复制代码
┌─────────────────────────────────┐
│         应用层 (AI)              │
│    调用工具、处理结果            │
├─────────────────────────────────┤
│         MCP 协议层               │
│    JSON-RPC、资源定义、工具定义  │
├─────────────────────────────────┤
│         传输层                   │
│    stdio / SSE / WebSocket       │
├─────────────────────────────────┤
│         实现层 (MCP Server)      │
│    Playwright / GitHub / Custom  │
└─────────────────────────────────┘

3.9.2 连接管理

stdio 传输

scss 复制代码
OpenCode (MCP Client)          MCP Server
        |                           |
        |--- fork() --------------->|
        |                           |
        |<-- stdout (JSON-RPC) -----|
        |--- stdin (JSON-RPC) ----->|
        |                           |

特点

  • 适用于本地 MCP Server
  • 进程间通信,安全可靠
  • 自动管理进程生命周期

SSE 传输

lua 复制代码
OpenCode (MCP Client)          MCP Server (Remote)
        |                           |
        |--- HTTP GET /events ----->|
        |<-- SSE stream ------------|
        |                           |
        |--- HTTP POST /invoke ---->|
        |<-- JSON response ---------|
        |                           |

特点

  • 适用于远程 MCP Server
  • 支持跨网络通信
  • 需要处理连接稳定性

3.9.3 工具发现与调用

发现流程

javascript 复制代码
// 1. Client 发送 tools/list 请求
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}

// 2. Server 返回可用工具列表
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "browser_navigate",
        "description": "Navigate to a URL",
        "inputSchema": { ... }
      }
    ]
  }
}

// 3. Client 缓存工具列表
// 4. AI 调用时,Client 发送 tools/call
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "browser_navigate",
    "arguments": {
      "url": "https://example.com"
    }
  }
}

3.9.4 错误处理机制

错误分类

  1. 连接错误:无法连接到 MCP Server
  2. 协议错误:JSON-RPC 格式错误
  3. 工具错误:工具不存在或参数错误
  4. 执行错误:工具执行失败

错误处理策略

javascript 复制代码
// Client 端错误处理
try {
  const result = await callTool(server, toolName, params);
} catch (error) {
  if (error.code === -32000) {
    // 服务器错误,尝试重启
    await restartServer(server);
  } else if (error.code === -32602) {
    // 参数错误,修正参数重试
    const correctedParams = fixParams(params, error.data);
    return await callTool(server, toolName, correctedParams);
  } else {
    // 其他错误,向上抛出
    throw error;
  }
}

故障排查与优化

3.10.1 常见问题

问题 1:MCP Server 启动失败

症状

vbnet 复制代码
Error: Failed to start MCP server 'playwright'
Error: spawn npx ENOENT

解决

  1. 检查 Node.js 是否安装:node --version
  2. 检查 npx 是否可用:npx --version
  3. 安装 MCP Server:npm install -g @anthropic-ai/playwright-mcp-server

问题 2:工具调用超时

症状

vbnet 复制代码
Error: Tool call timeout after 30000ms

解决

json 复制代码
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@anthropic-ai/playwright-mcp-server"],
      "timeout": 60000 // 增加超时时间
    }
  }
}

问题 3:权限拒绝

症状

vbnet 复制代码
Error: Access denied to /etc/passwd

解决

  • 检查 ALLOWED_PATHS 配置
  • 确认操作权限
  • 使用 sudo(不推荐)

3.10.2 性能优化

优化 1:连接池

对于频繁使用的 MCP,保持长连接:

json 复制代码
{
  "mcpServers": {
    "database": {
      "command": "node",
      "args": ["db-mcp.js"],
      "keepAlive": true, // 保持连接
      "maxIdleTime": 300000 // 5 分钟空闲超时
    }
  }
}

优化 2:并行调用

javascript 复制代码
// 并行调用多个工具
const results = await Promise.all([
  callTool(server1, 'tool1', params1),
  callTool(server2, 'tool2', params2),
  callTool(server3, 'tool3', params3),
]);

优化 3:缓存结果

javascript 复制代码
// 缓存工具列表
const toolCache = new Map();

async function getTools(server) {
  if (toolCache.has(server)) {
    return toolCache.get(server);
  }

  const tools = await listTools(server);
  toolCache.set(server, tools);
  return tools;
}

3.10.3 调试技巧

启用调试日志

bash 复制代码
# 设置环境变量
export MCP_DEBUG=true
export MCP_LOG_LEVEL=debug

# 启动 OpenCode
opencode --agent

使用 MCP Inspector

bash 复制代码
# 安装 Inspector
npm install -g @anthropic-ai/mcp-inspector

# 测试 MCP Server
mcp-inspector --server "npx @anthropic-ai/playwright-mcp-server"

查看原始通信

bash 复制代码
# 使用 socat 查看 stdio 通信
socat -v EXEC:"npx @anthropic-ai/playwright-mcp-server" STDIO

总结与展望

本章要点

  1. MCP 是什么:AI 与外部工具连接的标准协议
  2. 核心概念:Resources、Tools、Prompts
  3. 配置使用:添加 MCP、测试连接、权限控制
  4. 开发 MCP:使用 SDK 开发自定义 MCP Server
  5. 安全实践:权限管理、凭证保护、审计日志
  6. 实战应用:自动化测试、文档生成、运维助手

MCP 生态系统展望

短期(1-2 年)

  • 更多官方 MCP(数据库、云服务、开发工具)
  • MCP 市场/商店
  • 标准化认证体系

中期(3-5 年)

  • 企业级 MCP 管理平台
  • 跨平台 MCP 互操作
  • 可视化 MCP 编排

长期(5 年+)

  • MCP 成为 AI 应用基础设施
  • 自主 MCP 发现与组合
  • AI 自主开发 MCP

下一步学习

学完 MCP 后,建议继续学习:

  • 第五章:最佳实践 - 掌握综合使用技巧

文档信息

  • 字数:约 8,500 字
  • 适用版本:OpenCode 0.1.40+

相关资源

(第三章完)

相关推荐
摸鱼的春哥1 小时前
你适合养龙虾🦞吗?4类人不适合2类适合
前端·javascript·后端
Moment2 小时前
Agent 开发本质上就是高级点的 CRUD
前端·后端·面试
恋猫de小郭2 小时前
OpenAI 亲自教你如何构建可靠 AI 代码,从古法编程转向 Agnet 编程,或者 PUA 你的 AI
前端·人工智能·ai编程
程序员爱钓鱼3 小时前
Go错误处理全解析:errors包实战与最佳实践
前端·后端·go
Goboy11 小时前
OpenClaw 卸载教程,一篇讲透
ai编程
清汤饺子11 小时前
OpenClaw 本地部署教程 - 从 0 到 1 跑通你的第一只龙虾
前端·javascript·vibecoding
刀法如飞13 小时前
AI时代,程序员都应该是需求描述工程师
程序员·aigc·ai编程·需求文档
爱吃的小肥羊14 小时前
比 Claude Code 便宜一半!Codex 国内部署使用教程,三种方法任选一!
前端