Skip to main content

MCP 服务器开发协议

🚀 构建并与世界分享您的 MCP 服务器。 创建出色的 MCP 服务器后,将其提交到 Careti MCP 市场,使其可被数千名开发人员发现并一键安装。

什么是 MCP 服务器?

模型上下文协议(MCP)服务器通过赋予 AI 助手(如 Careti)以下能力来扩展它们:

  • 访问外部 API 和服务
  • 检索实时数据
  • 控制应用程序和本地系统
  • 执行单靠文本提示无法实现的操作

没有 MCP,AI 助手虽然强大但是孤立的。有了 MCP,它们获得了与几乎任何数字系统交互的能力。

开发协议

有效 MCP 服务器开发的核心是遵循结构化协议。该协议通过位于 MCP 工作目录根目录(/Users/your-name/Documents/Careti/MCP)的 .agents/context 文件实现。

使用 .agents/context 文件

.agents/context 文件是 Careti 在其所在目录工作时自动读取的特殊配置。这些文件:

  • 配置 Careti 的行为并强制执行最佳实践
  • Careti 切换到专门的 MCP 开发模式
  • 提供构建服务器的分步协议
  • 实施安全措施,如防止过早完成
  • 引导您完成规划、实施和测试阶段

以下是应放置在 .agents/context 文件中的完整 MCP 服务器开发协议:

# MCP 服务器开发协议

⚠️ 关键:在测试之前不要使用 attempt_completion ⚠️

## 步骤 1:规划(PLAN 模式)

- 此工具解决什么问题?
- 它将使用什么 API/服务?
- 身份验证要求是什么?
□ 标准 API 密钥
□ OAuth(需要单独的设置脚本)
□ 其他凭据

## 步骤 2:实施(ACT 模式)

1. 引导

- 对于 Web 服务、JavaScript 集成或 Node.js 环境:
```bash
npx @modelcontextprotocol/create-server my-server
cd my-server
npm install
```
- 对于数据科学、ML 工作流或 Python 环境:
```bash
pip install mcp
# 或使用 uv(推荐)
uv add "mcp[cli]"
```

2. 核心实施

- 使用 MCP SDK
- 实施全面的日志记录
- TypeScript(用于 Web/JS 项目):
```typescript
console.error("[Setup] Initializing server...")
console.error("[API] Request to endpoint:", endpoint)
console.error("[Error] Failed with:", error)
```
- Python(用于数据科学/ML 项目):
```python
import logging
logging.error('[Setup] Initializing server...')
logging.error(f'[API] Request to endpoint: {endpoint}')
logging.error(f'[Error] Failed with: {str(error)}')
```
- 添加类型定义
- 使用上下文处理错误
- 如果需要,实施速率限制

3. 配置

- 如果需要,从用户获取凭据
- 添加到 MCP 设置:

- 对于 TypeScript 项目:
```json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["path/to/build/index.js"],
"env": {
"API_KEY": "key"
},
"disabled": false,
"autoApprove": []
}
}
}
```
- 对于 Python 项目:

```bash
# 直接使用命令行
mcp install server.py -v API_KEY=key

# 或在 settings.json 中
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"],
"env": {
"API_KEY": "key"
},
"disabled": false,
"autoApprove": []
}
}
}
```

## 步骤 3:测试(阻断器 ⛔️)

<thinking>
在使用 attempt_completion 之前,我必须验证:
□ 我是否测试了每个工具?
□ 我是否确认了每个测试的用户成功?
□ 我是否记录了测试结果?

如果任何答案是"否",我不得使用 attempt_completion。
</thinking>

1. 测试每个工具(必需)
□ 使用有效输入测试每个工具
□ 验证输出格式是否正确
⚠️ 在所有工具测试之前不要继续

## 步骤 4:完成

❗ 停止并验证:
□ 每个工具都已使用有效输入进行测试
□ 每个工具的输出格式都是正确的

只有在所有工具都经过测试后才能使用 attempt_completion。

## 关键要求

- ✓ 必须使用 MCP SDK
- ✓ 必须有全面的日志记录
- ✓ 必须单独测试每个工具
- ✓ 必须优雅地处理错误
- ⛔️ 永远不要在完成前跳过测试

当此 .agents/context 文件存在于您的工作目录中时,Careti 将:

  1. PLAN 模式下启动,在实施之前设计您的服务器
  2. ACT 模式下强制执行适当的实施模式
  3. 在允许完成之前要求测试所有工具
  4. 引导您完成整个开发生命周期

入门

创建 MCP 服务器只需要几个简单的步骤即可开始:

1. 创建 .agents/context 文件(🚨 重要)

首先,使用上述协议将 .agents/context 文件添加到 MCP 工作目录的根目录。此文件配置 Careti 在此文件夹中工作时使用 MCP 开发协议。

2. 从清晰的描述开始聊天

通过清晰地描述您想要构建的内容来开始您的 Careti 聊天。具体说明:

  • MCP 服务器的目的
  • 您想要集成的 API 或服务
  • 您需要的任何特定工具或功能

例如:

我想为 AlphaAdvantage 金融 API 构建一个 MCP 服务器。
它应该允许我获取实时股票数据、进行技术分析
并检索公司财务信息。

3. 完成协议

Careti 将自动在 PLAN 模式下启动,引导您完成规划过程:

  • 讨论问题范围
  • 审查 API 文档
  • 规划身份验证方法
  • 设计工具接口

准备好后,使用聊天底部的切换开关切换到 ACT 模式以开始实施。

4. 尽早提供 API 文档

帮助 Careti 构建 MCP 服务器的最有效方法之一是在开始时就分享官方 API 文档:

这是该服务的 API 文档:
[在此粘贴 API 文档]

提供全面的 API 详细信息(端点、身份验证、数据结构)显著提高了 Careti 实现有效 MCP 服务器的能力。

理解两种模式

PLAN 模式

在此协作阶段,您与 Careti 一起设计 MCP 服务器:

  • 定义问题范围
  • 选择适当的 API
  • 规划身份验证方法
  • 设计工具接口
  • 确定数据格式

ACT 模式

规划完成后,Careti 帮助实施服务器:

  • 设置项目结构
  • 编写实施代码
  • 配置设置
  • 彻底测试每个组件
  • 完成文档

案例研究:AlphaAdvantage 股票分析服务器

让我们详细了解 AlphaAdvantage MCP 服务器的开发过程,该服务器提供股票数据分析和报告功能。

规划阶段

规划阶段演示

在规划阶段,我们:

  1. 定义了问题:用户需要通过其 AI 助手直接访问金融数据、股票分析和市场见解
  2. 选择了 API:AlphaAdvantage API 用于金融市场数据
    • 标准 API 密钥身份验证
    • 速率限制为每分钟 5 个请求(免费层)
    • 不同金融数据类型的各种端点
  3. 设计了所需的工具
    • 股票概览信息(当前价格、公司详细信息)
    • 带指标的技术分析(RSI、MACD 等)
    • 基本面分析(财务报表、比率)
    • 收益报告数据
    • 新闻和情绪分析
  4. 规划了数据格式
    • 干净、格式良好的 markdown 输出
    • 结构化数据的表格
    • 趋势的视觉指标(↑/↓)
    • 适当的财务数字格式

实施

构建 MCP 插件演示

我们从引导项目开始:

npx @modelcontextprotocol/create-server alphaadvantage-mcp
cd alphaadvantage-mcp
npm install axios node-cache

接下来,我们使用以下结构构建项目:

src/
├── api/
│ └── alphaAdvantageClient.ts # 具有速率限制和缓存的 API 客户端
├── formatters/
│ └── markdownFormatter.ts # 用于干净 markdown 的输出格式化程序
└── index.ts # 主 MCP 服务器实施

API 客户端实施

API 客户端实施包括:

  • 速率限制:强制执行每分钟 5 个请求的限制
  • 缓存:通过战略缓存减少 API 调用
  • 错误处理:强大的错误检测和报告
  • 类型化接口:所有数据的清晰 TypeScript 类型

关键实施详细信息:

/**
* 根据免费层管理速率限制(每分钟 5 次调用)
*/
private async enforceRateLimit() {
if (this.requestsThisMinute >= 5) {
console.error("[Rate Limit] Rate limit reached. Waiting for next minute...");
return new Promise<void>((resolve) => {
const remainingMs = 60 * 1000 - (Date.now() % (60 * 1000));
setTimeout(resolve, remainingMs + 100); // 添加 100ms 缓冲
});
}

this.requestsThisMinute++;
return Promise.resolve();
}

Markdown 格式化

我们实施了格式化程序以精美地显示金融数据:

/**
* 将公司概览格式化为 markdown
*/
export function formatStockOverview(overviewData: any, quoteData: any): string {
// 提取数据
const overview = overviewData
const quote = quoteData["Global Quote"]

// 计算价格变化
const currentPrice = parseFloat(quote["05. price"] || "0")
const priceChange = parseFloat(quote["09. change"] || "0")
const changePercent = parseFloat(quote["10. change percent"]?.replace("%", "") || "0")

// 格式化 markdown
let markdown = `# ${overview.Symbol} (${overview.Name}) - ${formatCurrency(currentPrice)} ${addTrendIndicator(priceChange)}${changePercent > 0 ? "+" : ""}${changePercent.toFixed(2)}%\n\n`

// 添加更多详细信息...

return markdown
}

工具实施

我们定义了五个具有清晰接口的工具:

server.setRequestHandler(ListToolsRequestSchema, async () => {
console.error("[Setup] Listing available tools")

return {
tools: [
{
name: "get_stock_overview",
description: "获取股票代码的基本公司信息和当前报价",
inputSchema: {
type: "object",
properties: {
symbol: {
type: "string",
description: "股票代码(例如,'AAPL')",
},
market: {
type: "string",
description: "可选市场(例如,'US')",
default: "US",
},
},
required: ["symbol"],
},
},
// 在此定义其他工具...
],
}
})

每个工具的处理程序包括:

  • 输入验证
  • 带错误处理的 API 客户端调用
  • 响应的 Markdown 格式化
  • 全面的日志记录

测试阶段

此关键阶段涉及系统地测试每个工具:

  1. 首先,我们在设置中配置了 MCP 服务器:
{
"mcpServers": {
"alphaadvantage-mcp": {
"command": "node",
"args": ["/path/to/alphaadvantage-mcp/build/index.js"],
"env": {
"ALPHAVANTAGE_API_KEY": "YOUR_API_KEY"
},
"disabled": false,
"autoApprove": []
}
}
}
  1. 然后我们单独测试每个工具:
  • get_stock_overview:检索 AAPL 股票概览信息

    # AAPL (Apple Inc) - $241.84 ↑+1.91%

    **行业:** 技术
    **产业:** 电子计算机
    **市值:** 3.63T
    **市盈率:** 38.26
    ...
  • get_technical_analysis:获取价格行为和 RSI 数据

    # 技术分析:AAPL

    ## 日价格行为

    当前价格:$241.84(↑$4.54,+1.91%)

    ### 最近的每日价格

    | 日期 | 开盘 | 最高 | 最低 | 收盘 | 成交量 |
    | ---------- | ------- | ------- | ------- | ------- | ------ |
    | 2025-02-28 | $236.95 | $242.09 | $230.20 | $241.84 | 56.83M |

    ...
  • get_earnings_report:检索 MSFT 收益历史和格式化报告

    # 收益报告:MSFT(微软公司)

    **行业:** 技术
    **产业:** 服务-预打包软件
    **当前每股收益:** $12.43

    ## 最近的季度收益

    | 季度 | 日期 | 每股收益预估 | 实际每股收益 | 惊喜 % |
    | ---------- | ---------- | ------------ | ------------ | ------ |
    | 2024-12-31 | 2025-01-29 | $3.11 | $3.23 | ↑4.01% |

    ...

挑战和解决方案

在开发过程中,我们遇到了几个挑战:

  1. API 速率限制
    • 挑战:免费层限制为每分钟 5 次调用
    • 解决方案:实施了队列、强制执行速率限制并添加了全面的缓存
  2. 数据格式化
    • 挑战:原始 API 数据不够用户友好
    • 解决方案:创建了格式化实用程序以一致地显示金融数据
  3. 超时问题
    • 挑战:进行多个 API 调用的复杂工具可能会超时
    • 解决方案:建议将复杂工具分解为更小的部分,优化缓存

经验教训

我们的 AlphaAdvantage 实施教会了我们几个关键教训:

  1. 规划 API 限制:从一开始就理解并围绕 API 速率限制进行设计
  2. 战略缓存:识别高价值缓存机会以提高性能
  3. 格式化可读性:投资于良好的数据格式化以改善用户体验
  4. 测试每条路径:在完成之前单独测试所有工具
  5. 处理 API 复杂性:对于需要多次调用的 API,设计具有更简单范围的工具

核心实施最佳实践

全面的日志记录

有效的日志记录对于调试 MCP 服务器至关重要:

// 启动日志记录
console.error("[Setup] Initializing AlphaAdvantage MCP server...")

// API 请求日志记录
console.error(`[API] Getting stock overview for ${symbol}`)

// 带上下文的错误处理
console.error(`[Error] Tool execution failed: ${error.message}`)

// 缓存操作
console.error(`[Cache] Using cached data for: ${cacheKey}`)

强类型

类型定义防止错误并提高可维护性:

export interface AlphaAdvantageConfig {
apiKey: string
cacheTTL?: Partial<typeof DEFAULT_CACHE_TTL>
baseURL?: string
}

/**
* 验证是否提供了股票代码并且看起来有效
*/
function validateSymbol(symbol: unknown): asserts symbol is string {
if (typeof symbol !== "string" || symbol.trim() === "") {
throw new McpError(ErrorCode.InvalidParams, "A valid stock symbol is required")
}

// 基本符号验证(字母、数字、点)
const symbolRegex = /^[A-Za-z0-9.]+$/
if (!symbolRegex.test(symbol)) {
throw new McpError(ErrorCode.InvalidParams, `Invalid stock symbol: ${symbol}`)
}
}

智能缓存

减少 API 调用并提高性能:

// 默认缓存 TTL(秒)
const DEFAULT_CACHE_TTL = {
STOCK_OVERVIEW: 60 * 60, // 1 小时
TECHNICAL_ANALYSIS: 60 * 30, // 30 分钟
FUNDAMENTAL_ANALYSIS: 60 * 60 * 24, // 24 小时
EARNINGS_REPORT: 60 * 60 * 24, // 24 小时
NEWS: 60 * 15, // 15 分钟
}

// 首先检查缓存
const cachedData = this.cache.get<T>(cacheKey)
if (cachedData) {
console.error(`[Cache] Using cached data for: ${cacheKey}`)
return cachedData
}

// 缓存成功的响应
this.cache.set(cacheKey, response.data, cacheTTL)

优雅的错误处理

实施保持良好用户体验的强大错误处理:

try {
switch (request.params.name) {
case "get_stock_overview": {
// 实施...
}

// 其他情况...

default:
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`)
}
} catch (error) {
console.error(`[Error] Tool execution failed: ${error instanceof Error ? error.message : String(error)}`)

if (error instanceof McpError) {
throw error
}

return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
}
}

MCP 资源

资源让您的 MCP 服务器在不执行代码的情况下向 Careti 公开数据。它们非常适合提供上下文,如文件、API 响应或 Careti 在对话期间可以引用的数据库记录。

向 MCP 服务器添加资源

  1. 定义资源您的服务器将公开:
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "file:///project/readme.md",
name: "Project README",
mimeType: "text/markdown",
},
],
}
})
  1. 实施读取处理程序以传递内容:
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
if (request.params.uri === "file:///project/readme.md") {
const content = await fs.promises.readFile("/path/to/readme.md", "utf-8")
return {
contents: [
{
uri: request.params.uri,
mimeType: "text/markdown",
text: content,
},
],
}
}

throw new Error("Resource not found")
})

资源使您的 MCP 服务器更具上下文感知能力,允许 Careti 访问特定信息而无需您复制/粘贴。有关更多信息,请参阅官方文档

常见挑战和解决方案

API 身份验证复杂性

挑战:API 通常有不同的身份验证方法。

解决方案

  • 对于 API 密钥,在 MCP 配置中使用环境变量
  • 对于 OAuth,创建单独的脚本以获取刷新令牌
  • 安全地存储敏感令牌
// 使用环境中的 API 密钥进行身份验证
const API_KEY = process.env.ALPHAVANTAGE_API_KEY
if (!API_KEY) {
console.error("[Error] Missing ALPHAVANTAGE_API_KEY environment variable")
process.exit(1)
}

// 初始化 API 客户端
const apiClient = new AlphaAdvantageClient({
apiKey: API_KEY,
})

缺失或有限的 API 功能

挑战:API 可能不提供您需要的所有功能。

解决方案

  • 使用可用端点实施回退
  • 在必要时创建模拟功能
  • 转换 API 数据以满足您的需求

API 速率限制

挑战:大多数 API 都有可能导致失败的速率限制。

解决方案

  • 实施适当的速率限制
  • 添加智能缓存
  • 提供优雅降级
  • 添加关于速率限制的透明错误
if (this.requestsThisMinute >= 5) {
console.error("[Rate Limit] Rate limit reached. Waiting for next minute...")
return new Promise<void>((resolve) => {
const remainingMs = 60 * 1000 - (Date.now() % (60 * 1000))
setTimeout(resolve, remainingMs + 100) // 添加 100ms 缓冲
})
}

其他资源