跳转到内容
Guide

现有 10,000 台 MCP 服务器:这就是区分好服务器的标准

| 9 min read

2026 年 4 月,MCP 生态系统覆盖了 10,000 台服务器。将有用的 MCP 服务器与废弃的服务器区分开来的七种做法,并以包含 49 个工具的生产服务器为例。

Server room with network cables and rack-mounted hardware representing MCP server infrastructure
Photo by Jordan Harrison on Unsplash

2026 年 4 月,MCP 生态系统跨越 10,000 台公共服务器。TypeScript、Python、Java、Kotlin、 C# 和 Swift SDK 的每月下载量合计达到 9700 万次。 OAuth 2.1 和可流式 HTTP 传输 是稳定的。 Linux 基金会负责监督治理。 克劳德桌面,光标,风帆冲浪,Zed,继续, Sourcegraph Cody 和 Taskade Genesis 均附带 MCP 客户端支持。

这 10,000 台服务器中的大多数都是废弃的实验服务器。 工具名称模糊,无输入验证,已转储 API 界面和通用错误消息。 开发人员不断回来分享七个的少数 做法。

这篇文章涵盖了这七种实践以及生产代码 Botoi 的 MCP 服务器,它公开了来自 150 多个 API 端点的 49 个精选工具。 每个 代码示例来自正在运行的服务器 api.botoi.com/mcp

1. 策划工具; 不要转储你的整个 API

最大的一个错误:将每个 API 端点注册为 MCP 工具。 Botoi 拥有 150 多个端点。 如果它们都是 MCP 工具,则工具清单在对话之前将消耗 30,000 多个令牌 开始。 这为用户的实际问题留下了更少的空间,增加了模型选择问题的机会 错误的工具,并减慢每个请求,因为模型必须读取数百个工具 定义。

Botoi 注册 49。选择标准:开发人员在编码会话期间使用的工具(DNS 查找、JWT 解码、哈希生成),生成结构化输出模型的工具可以推理 (JSON 验证、PII 检测)以及保存上下文切换的工具(Base64 编码、URL 元数据) 提取)。

// curated-tools.ts - 49 tools from 150+ endpoints
export const CURATED_TOOLS: Record<string, CuratedTool> = {
  lookup_dns: {
    path: "/v1/dns/lookup",
    method: "post",
    title: "DNS Lookup",
    description:
      "Query DNS records (A, AAAA, MX, TXT, CNAME, NS) for a domain. " +
      "Use when you need to check DNS configuration or troubleshoot domain resolution.",
    annotations: { readOnlyHint: true, openWorldHint: true },
  },
  dev_hash: {
    path: "/v1/hash",
    method: "post",
    title: "Hash Text",
    description:
      "Generate a hash (MD5, SHA-1, SHA-256, SHA-512) of input text. " +
      "Use for checksums, data integrity, or fingerprinting.",
    annotations: { readOnlyHint: true },
  },
  // ... 47 more curated tools
};

未能晋级的工具:具有大负载的批处理操作(从 HTML 生成 PDF)、 返回二进制数据的工具(二维码图像、屏幕截图)以及重叠的工具 功能(三个不同的哈希端点合并为一个)。 您添加的每个工具都需要花费代币。 将您的 MCP 清单视为产品,而不是 API 文档的镜像。

经验法则:如果您有超过 50 个工具,模型会花费更多时间读取工具定义 而不是做有用的工作。 每季度审核您的清单并删除零调用的工具。

2. 编写帮助模型正确选择的工具描述

该模型会读取您的工具描述来决定是否调用它。 诸如“是否 DNS 的东西”迫使模型进行猜测。 充满实现细节的描述会浪费令牌 模型不需要的信息。

有效的模式:一个句子以动词开头,说明该工具的用途,然后是 第二句以“Use when”开头,描述触发条件。

错误的描述

// Bad: vague, no trigger condition
{
  name: "dns",
  description: "Does DNS stuff"
}

// Bad: too long, includes implementation details
{
  name: "dns_lookup_tool",
  description: "This tool uses the DNS-over-HTTPS protocol to query Cloudflare's 1.1.1.1 resolver via a GET request to https://cloudflare-dns.com/dns-query with an Accept header of application/dns-json. It supports A, AAAA, MX, TXT, CNAME, and NS record types and returns the raw DNS response parsed into JSON format."
}

好的描述

// Good: verb-first, one sentence what + one sentence when
{
  name: "lookup_dns",
  description:
    "Query DNS records (A, AAAA, MX, TXT, CNAME, NS) for a domain. " +
    "Use when you need to check DNS configuration or troubleshoot domain resolution."
}

// Good: specific about capabilities and trigger condition
{
  name: "security_pii_detect",
  description:
    "Scan text for personal identifiable information (emails, phones, SSNs, credit cards). " +
    "Use when you need to audit user input or log output for sensitive data before storage."
}

第一句话是工具选择:它告诉模型该工具做什么以及输入什么 accepts. 第二句话是为了消除歧义:当两个工具可以匹配时,“使用何时”子句 帮助模型选择正确的一个。

Botoi 的 MCP 服务器中的所有 49 个工具都遵循此模式。 结果:模型始终选择 即使多个工具具有重叠的功能(例如, lookup_emaillookup_dns 用于检查 MX 记录)。

3.使用工具注释

MCP 规范定义了四种注释提示: readOnlyHint, destructiveHint, idempotentHint, 和 openWorldHint。 大多数服务器都会忽略它们。 型号和 尊重这些提示的客户会做出更安全的决定:如果没有,他们不会调用破坏性工具 确认后,他们会在失败时重试幂等工具,并且会在使用工具之前警告用户 联系外部服务。

// Annotations from Botoi's curated-tools.ts
lookup_dns: {
  path: "/v1/dns/lookup",
  annotations: {
    readOnlyHint: true,    // reads data, changes nothing
    openWorldHint: true,   // contacts external DNS servers
  },
},

storage_paste_create: {
  path: "/v1/paste/create",
  annotations: {
    destructiveHint: true,   // creates new data
    idempotentHint: false,   // each call creates a new paste
  },
},

dev_hash: {
  path: "/v1/hash",
  annotations: {
    readOnlyHint: true,      // pure computation
    idempotentHint: true,    // same input = same output
  },
},
注解 意义 例子
readOnlyHint: true 读取数据,不改变任何内容 DNS 查找、SSL 检查、IP 地理定位
destructiveHint: true 创建、更新或删除数据 创建粘贴,生成短URL
idempotentHint: true 使用相同的输入可以安全地多次调用 哈希生成、JSON 格式化
openWorldHint: true 联系外部服务 DNS over HTTPS、WHOIS、URL 元数据

就清单大小而言,注释几乎不需要花费任何成本,但它们为客户和模型提供了 他们需要安全地规划多步骤工作流程的元数据。 将它们设置在每个工具上。

4. 使用 Streamable HTTP 实现无状态

MCP 规范中已弃用 SSE(服务器发送事件)传输。 需要坚持不懈 连接、会话管理和重新连接逻辑。 Streamable HTTP 将其替换为标准 携带 JSON-RPC 2.0 负载的 HTTP POST 请求。 没有持久连接。 无会话状态。 作品 每个 HTTP 基础设施:CDN、负载均衡器、边缘运行时、无服务器平台。

Botoi 的 MCP 服务器在 Cloudflare Workers 上运行。 每个请求都会创建一个新的 McpServer 实例,注册所有 49 个工具,处理请求,然后返回。 无会话 ID,无法重连 处理程序,请求之间没有可管理的状态。

// MCP server on Cloudflare Workers with Streamable HTTP
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import {
  WebStandardStreamableHTTPServerTransport
} from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";

app.all("/mcp", async (c) => {
  const apiKey =
    c.req.header("X-API-Key") ||
    c.req.header("Authorization")?.replace("Bearer ", "");

  const server = createMcpServer(apiKey, c.env);
  const transport = new WebStandardStreamableHTTPServerTransport();
  await server.connect(transport);
  return transport.handleRequest(c.req.raw);
});

WebStandardStreamableHTTPServerTransport 来自 MCP SDK 的适用于任何运行时 支持 Web 标准 Request/Response API:Cloudflare 工作人员, Deno Deploy、Bun、Vercel Edge Functions 和 Node.js 18+。 如果您要在以下位置启动新的 MCP 服务器 2026 年,使用 Streamable HTTP。 如果您正在运行 SSE 服务器,请在客户端放弃支持之前进行迁移。

无状态服务器可以水平扩展,无需协调。 Botoi 的 MCP 端点在 Cloudflare 上运行 边缘网络; 请求路由到最近的数据中心。 仅计算工具(散列、Base64、 JSON 格式)在 50 毫秒内响应。

5. 使用模式验证输入

MCP 工具从模型接收任意 JSON。 模型可以发 在您需要字符串的地方,包含未知字段或省略必需的参数。 验证输入 在执行之前尽早捕获这些错误并返回模型可用于的结构化反馈 自我纠正。

Botoi 的方法: schema-builder.ts 模块读取 OpenAPI 路径定义 注册时间并将每个属性转换为 Zod 类型。 MCP SDK 验证输入 工具处理程序运行之前的 Zod 架构。

// schema-builder.ts - OpenAPI to Zod conversion
import { z } from "zod";
import { paths } from "../../openapi-paths";

function mapPropertyToZod(
  prop: OpenApiProperty,
  isRequired: boolean
): z.ZodTypeAny {
  let schema: z.ZodTypeAny;

  if (prop.enum && prop.enum.length > 0) {
    schema = z.enum(prop.enum as [string, ...string[]]);
  } else {
    switch (prop.type) {
      case "number":
      case "integer":
        schema = z.number(); break;
      case "boolean":
        schema = z.boolean(); break;
      default:
        schema = z.string(); break;
    }
  }

  if (!isRequired) schema = schema.optional();
  return schema;
}

export function buildZodSchema(
  apiPath: string,
  method: "get" | "post"
): Record<string, z.ZodTypeAny> {
  const operation = getOperation(apiPath, method);
  if (!operation) return {};

  const schema = operation.requestBody?.content?.["application/json"]?.schema;
  if (!schema?.properties) return {};

  const required = new Set(schema.required ?? []);
  const result: Record<string, z.ZodTypeAny> = {};

  for (const [key, prop] of Object.entries(schema.properties)) {
    result[key] = mapPropertyToZod(prop, required.has(key));
  }

  return result;
}

注册循环将生成的模式传递为 inputSchema 对于每个工具:

// server.ts - register tools with Zod schemas
for (const [toolName, tool] of Object.entries(CURATED_TOOLS)) {
  const zodSchema = buildZodSchema(tool.path, tool.method);

  server.registerTool(toolName, {
    title: tool.title,
    description: tool.description,
    inputSchema: zodSchema,
    annotations: tool.annotations,
  }, async (args: Record<string, unknown>) => {
    return callApi(tool.path, tool.method, args, apiKey, env);
  });
}

这意味着每个工具都可以免费获得输入验证。 如果模型发送一个整数,其中一个字符串 预计,MCP SDK 在处理程序代码运行之前返回结构化错误。 模型看到 错误,更正输入,然后重试。

6. 返回模型可以推理的结构化错误

当工具发生故障时,模型需要足够的信息来恢复。 “出了点问题”是没有用的。 字段名称、预期内容和收到内容的结构化错误为模型提供了 清除路径以使用更正的输入重试。

错误响应错误

// Bad: the model can't fix this
{
  "content": [{ "type": "text", "text": "Something went wrong" }],
  "isError": true
}

良好的错误响应

// Structured error the model can reason about
{
  "content": [
    {
      "type": "text",
      "text": "{\\n  \\"error\\": \\"validation_error\\",\\n  \\"message\\": \\"Invalid record type\\",\\n  \\"field\\": \\"type\\",\\n  \\"expected\\": [\\"A\\", \\"AAAA\\", \\"MX\\", \\"TXT\\", \\"CNAME\\", \\"NS\\"],\\n  \\"received\\": \\"INVALID\\"\\n}"
    }
  ],
  "isError": true
}

波托伊的 callApi 包装器从底层 REST API 捕获结构化错误并 将其传递给 MCP 响应 isError: true

// server.ts - API call wrapper with structured errors
async function callApi(
  path: string,
  method: string,
  body: unknown,
  apiKey: string | undefined,
  env: Env
) {
  const headers: Record<string, string> = {
    "Content-Type": "application/json",
  };
  if (apiKey) headers["X-API-Key"] = apiKey;

  const req = new Request(\`http://internal\${path}\`, {
    method: method.toUpperCase(),
    headers,
    body: method === "post" ? JSON.stringify(body) : undefined,
  });

  const res = await appFetcher(req, env);
  const json = await res.json();

  if (!json.success) {
    return {
      content: [{
        type: "text",
        text: JSON.stringify(json.error, null, 2),
      }],
      isError: true,
    };
  }

  return {
    content: [{
      type: "text",
      text: JSON.stringify(json.data, null, 2),
    }],
  };
}

关键细节: isError: true 标志告诉模型工具调用失败。 中的结构化 JSON text 字段告诉它原因。 根据工具使用模式训练的模型 将读取错误,识别问题字段,并使用更正的值重试。 一般错误 字符串迫使模型猜测或放弃。

7.在不破坏开发者体验的情况下添加auth

MCP 服务器需要身份验证。 该规范支持 OAuth 2.1 来实现完整的授权流程,但大多数 开发人员工具与 API 密钥转发配合良好。 开发人员将其密钥添加到 MCP 客户端 配置一次; 服务器从请求标头中提取它并将其传递给每个 API 调用。

以下是带有 API 密钥的 Claude Desktop 客户端配置:

// Client config: Claude Desktop
{
  "mcpServers": {
    "botoi": {
      "type": "streamable-http",
      "url": "https://api.botoi.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}

服务器从以下任意一个中提取密钥 Authorization 标头或 X-API-Key header,然后将其转发到每个内部 API 调用:

// server.ts - extract API key from MCP request headers
app.all("/mcp", async (c) => {
  const apiKey =
    c.req.header("X-API-Key") ||
    c.req.header("Authorization")?.replace("Bearer ", "");

  // Pass the key through to every API call
  const server = createMcpServer(apiKey, c.env);
  const transport = new WebStandardStreamableHTTPServerTransport();
  await server.connect(transport);
  return transport.handleRequest(c.req.raw);
});

没有密钥,服务器仍然可以工作。 Botoi 允许每分钟 5 个请求的匿名访问,并且 每天 100 个,足够在编码期间随意使用。 通过按键,将规模限制为 开发商的计划等级。 这种方法意味着零摩擦入职(无需注册即可尝试) 当使用量增长时有清晰的升级路径。

开发人员的 API 密钥永远不会离开 MCP 服务器。 它从客户端配置到 MCP 内部 API 调用的请求标头。 该模型永远不会在对话上下文中看到它。

好的 MCP 服务器与坏的 MCP 服务器

特征 服务器不好 良好的服务器
刀具数量 转储每个端点(100+) 策划高价值工具(50 岁以下)
工具说明 “DNS 是否有作用”或 200 字墙 动词+它的作用+“何时使用”触发器
注释 所有工具均缺失 在每个工具上设置:只读、破坏性、幂等、openWorld
运输 具有会话管理功能的 SSE 无状态流式 HTTP
输入验证 没有任何; 输入错误时崩溃 根据 OpenAPI 规范生成的 Zod 模式
错误响应 “出了点问题” 包含字段、预期和接收的结构化 JSON
验证 无,或完全阻止匿名使用 具有匿名回退和速率限制的 API 密钥转发

10,000 台服务器的格局

由于协议稳定,MCP 服务器在六个月内从 1,000 台增长到 10,000 台。 OAuth 2.1 取代了临时身份验证模式。 可流式 HTTP 取代了 SSE。 Linux基金会 治理让企业有信心构建生产服务器。 六种语言的 SDK 降低 进入壁垒。

但数量并没有带来质量。 这些服务器中的大多数都是周末实验,从未过去 “注册我的所有端点并看看会发生什么”阶段。 开发者日常使用的服务器 投资于管理、描述、模式、错误处理和验证。 这五个领域占90% 可用性差距的寿命。

如果您要在 2026 年构建 MCP 服务器,那么问题就不是“它是否有效”。 酒吧是“模型吗? 选择正确的工具,在选择错误时了解错误,并在无需人工干预的情况下恢复。” 上述七种做法可以帮助您实现这一目标。

Botoi 的 MCP 服务器已开放测试。 从 Claude Desktop、Claude Code、Cursor、VS Code 连接, 或使用 Windsurf 上的配置 MCP 设置页面。 完整的工具清单是 在 api.botoi.com/v1/mcp/tools.json, 和 API文档 覆盖工具背后的每个端点。

FAQ

2026 年有多少台 MCP 服务器?
MCP 生态系统的公共服务器数量从 2025 年末的约 1,000 台增加到 2026 年 4 月。这一增长是由稳定的 OAuth 2.1 支持、取代 SSE 的 Streamable HTTP 传输以及 Claude Desktop、Cursor、Windsurf、Zed、Continue、Sourcegraph Cody 和 Taskade Genesis 中的客户端集成推动的。
MCP 服务器应该公开多少个工具?
没有硬性限制,但越少越好。 每个工具定义都会消耗模型上下文窗口中的标记。 在对话开始之前,包含 150 个工具的清单可能会花费 30,000 多个代币。 Botoi 从 150 多个 API 端点中精选了 49 种工具。 除非您的用例需要更多工具,否则目标是使用 50 个以下的详细描述的工具。
2026 年我应该使用哪种 MCP 交通工具?
Streamable HTTP 是稳定的、推荐的传输方式。 MCP 规范中不推荐使用 SSE(服务器发送事件)传输。 Streamable HTTP 使用带有 JSON-RPC 2.0 有效负载的标准 HTTP POST,可与任何 HTTP 基础设施(CDN、负载均衡器、边缘运行时)配合使用,并且不需要持久连接。
什么是 MCP 工具注释以及它们为何重要?
工具注释是 MCP 规范中定义的元数据提示:readOnlyHint、 DestructiveHint、idempotencyHint 和 openWorldHint。 它们告诉人工智能模型工具是否读取数据、写入数据、重试是否安全或联系外部服务。 模型使用这些提示来规划更安全的多步骤工作流程,并避免未经用户确认的破坏性调用。
MCP 服务器需要身份验证吗?
是的。 MCP 规范现在包括用于身份验证的 OAuth 2.1。 即使对于更简单的设置,每个请求都需要持有者令牌或 API 密钥。 匿名访问应该有严格的速率限制。 Botoi 允许匿名访问,每分钟 5 个请求,每天 100 个,对经过身份验证的密钥有更高的限制。

开始使用 botoi 构建

150+ 个 API 端点,涵盖查询、文本处理、图片生成和开发者工具。免费套餐,无需信用卡。