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+

相关资源

(第三章完)

相关推荐
楚国的小隐士3 小时前
在生产环境中和AI协作编程
ai·大模型·编程·软件工程·ai编程·软件架构
benbenAItalk4 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
wangruofeng4 小时前
一个 Markdown 文件攒下 37k 星,i-have-adhd 给 AI 输出立了 10 条规矩
github·aigc·ai编程
2601_962885724 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
西瓜太郎12345 小时前
Claude Code、Codex CLI、Gemini CLI 能否共用一枚 Key?先看协议选择矩阵
前端·api 网关·claude code·gemini cli·codex cli
全栈弄潮儿7 小时前
需求不清时,如何让 AI 帮你补全问题,而不是瞎写代码
aigc·openai·ai编程
一航jason7 小时前
Android平台推理框架及试用场景模型对比
android·人工智能·ai·架构·ai编程·llama
陈随易7 小时前
在Finch用了62亿词元,我认为这是新一代Agent工具之神
前端·人工智能·后端
一航jason7 小时前
Android 端侧大模型推理框架对比
android·人工智能·ai·ai编程·llama·ai-native
水域安全老周7 小时前
水趣钓鱼救生衣专利拆解:两级锁紧如何解决落水人衣分离
java·前端·网络