[Agentica] 为什么你的 MCP 服务器会失败(如何打造 100% 成功的 MCP 服务器)
概括
MCP(模型上下文协议)给人工智能生态系统带来了一股新浪潮,但最近对其稳定性和有效性提出了许多批评。
但是,如果您将 MCP 转换为函数单元,并使用以下三种策略实现函数调用,则可以创建一个始终有效(100%)的 AI 代理。将函数调用与 MCP 和 Agentica 结合使用。
不要直接将 MCP 服务器添加到
mcp_servers列表中,而是使用函数调用与 MCP 进行交互。这种方法可以确保 MCP 服务器成功运行。
- 特吉卡
- GitHub 仓库:https://github.com/wrtnlabs/agentica
- 指南文档:https://wrtnlabs.io/agentica
- Agentica 的函数调用策略
- JSON Schema 规范:不同 LLM 供应商的规范各不相同。
- 验证反馈:纠正人工智能在论证构成方面的错误
- 选择器代理:筛选候选函数以减少上下文
1. 前言
Claude Desktop 上的 Github MCP 崩溃太多
近年来,MCP(模型上下文协议)在人工智能代理生态系统中越来越受欢迎。
然而,与此同时,人工智能的早期采用者们常常对MCP的不稳定性表示不满。我经常浏览LinkedIn上的帖子,毫不夸张地说,我每天至少会看到3条类似下面这样的帖子,这表明MCP还为时尚早:
人们把MCP吹捧得好像万能灵药,但它极其不稳定。它经常崩溃、故障,而且代币成本也高得令人望而却步。它根本不适用于企业环境。
或许当更便宜、更大、更智能的车型出现时,MCP的愿景才能实现。但就目前而言,MCP还为时尚早,且被过度炒作。
令人惊讶的是,通过分解 MCP 服务器的功能并自行实现 AI 函数调用,您可以将 AI 应用程序的稳定性提升至 100%。即使是像 8b 这样可以在个人笔记本电脑上运行的小型模型,它也能完美运行。
Agentica建议使用 MCP 进行函数调用,因为您可以高效地调用 MCP 服务器提供的函数,避免出现幻觉,并使用以下策略安全地管理它们:
- JSON Schema 规范:不同 LLM 供应商的规范各不相同。
- 验证反馈:纠正人工智能在论证构成方面的错误
- 选择器代理:筛选候选函数以减少上下文
如果你想创建一个每次都能 100% 成功的 AI 应用程序——不仅仅是像 Github MCP 那样仅限于单个服务器、只有 30 个函数调用的玩具型 AI 应用程序,而是包含多个服务器和数百个函数的应用程序——你应该实施文档驱动开发。
下面是一个拥有 289 个功能的电商平台 AI 代理,正如您所见,它运行完美,没有任何错误。让我们使用Agentica ,通过 MCP 函数调用和文档驱动开发,创建一个 100% 成功的 AI 应用。
100% 可用的电子商务代理,具备 289 项功能,并配备 8b 迷你模型
2. 函数调用
2.1. JSON Schema 规范
- 文件
- JSON Schema 规范
IChatGptSchema.tsOpenAI ChatGPTIClaudeSchema.ts:人本主义克劳德IDeepSeekSchema.ts:高飞深潜IGeminiSchema.ts谷歌双子座ILlamaSchema.ts:Meta Llama
MCP 中定义的 JSON 模式必须转换为符合目标 AI 供应商规范的格式。
您知道吗?不同的人工智能厂商使用的 JSON 模式规范各不相同。OpenAI、Anthropic Claude 和 Google Gemini 使用的 JSON 模式规范就各不相同。
然而,模型上下文协议对 JSON 模式规范没有任何限制。原则上,它可以使用所有现有的 JSON 模式版本。但实际上,每个人工智能厂商都有自己的一套 JSON 模式规范。
问题就出在这里。
{
name: "divide",
inputSchema: {
x: {
type: "number",
},
y: {
anyOf: [ // not supported in Gemini
{
type: "number",
exclusiveMaximum: 0, // not supported in OpenAI and Gemini
},
{
type: "number",
exclusiveMinimum: 0, // not supported in OpenAI and Gemini
},
],
},
},
description: "Calculate x / y",
}
我的 MCP 服务器与 Claude 配合良好,但与 OpenAI 配合不佳。
- 这是因为您使用了 OpenAI 不支持的 JSON 模式功能。
{ type: "string", format: "uuid" }{ type: "integer", minimum: 0 }为什么我的 MCP 服务器可以与 OpenAI 和 Claude 配合使用,但不能与 Gemini 配合使用?
- 因为您使用了 Gemini 不支持的 JSON 模式功能。
{ anyOf: [ { type: "boolean" }, { type: "integer" } ] }{ $ref: "#/$defs/Recursive" }
Claude 支持最新的 JSON Schema 规范,即 2020-12 草案版本。然而,该规范包含大量冗余、歧义和模糊的表达式,必须进行修正才能正确使用。
OpenAI 和 Gemini 拥有各自独特的 JSON Schema 规范。它们没有遵循标准,而是创建了自己的 JSON Schema 规范。遗憾的是,它们非但没有增强 JSON Schema 规范的表达能力,反而大幅削减了标准 JSON Schema 规范中的许多功能。
更令人困惑的是 Anthropic Claude 为 创建的服务器 SDK model-context-protocol。该服务器 SDK(通过zod-to-schema)基于已有 10 年历史的 v7 草案版本生成 JSON 模式。
现在你明白为什么你的 MCP 服务器在启动之前就会失败了吗?
只有将 MCP 服务器分解为功能单元,将其 JSON 模式转换为与目标 AI 供应商匹配的模式,并进行修正,才能创建一个功能完善的 AI 应用程序。
我们的Agentica通过以下 JSON 模式转换流程进行转换@samchon/openapi。当基于 MCP 创建 AI 应用程序时,您也必须经历类似的 JSON 模式转换流程:
- 将输入的 JSON 模式转换为 2020-12 草案版本
- 内部称为 OpenAPI v3.1 修订版
OpenApi.IJsonSchema
- 删除所有冗余/含糊/模棱两可的表达方式以进行更正。
- 转换为适合目标 AI 供应商的 JSON 模式模型
import { Agentica, assertMcpController } from "@agentica/core";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const client = new Client({
name: "shopping",
version: "1.0.0",
});
await client.connect(new StdioClientTransport({
command: "npx",
args: ["-y", "@wrtnlabs/shopping-mcp"],
}));
const agent = new Agentica({
model: "chatgpt",
vendor: {
api: new OpenAI({ apiKey: "********" }),
model: "gpt-4o-mini",
},
controllers: [
await assertMcpController({
name: "shopping",
model: "chatgpt",
client,
}),
],
});
await agent.conversate("I wanna buy a Macbook");
2.2 验证反馈
| 姓名 | 地位 |
|---|---|
ObjectConstraint |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
ObjectFunctionSchema |
2️⃣2️⃣4️⃣2️⃣2️⃣2️⃣2️⃣2️⃣5️⃣2️⃣ |
ObjectHierarchical |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣2️⃣1️⃣1️⃣2️⃣ |
ObjectJsonSchema |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
ObjectSimple |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
ObjectUnionExplicit |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
ObjectUnionImplicit |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
ShoppingCartCommodity |
1️⃣2️⃣2️⃣3️⃣1️⃣1️⃣4️⃣2️⃣1️⃣2️⃣ |
ShoppingOrderCreate |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
ShoppingOrderPublish |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣❌1️⃣1️⃣1️⃣ |
ShoppingSaleDetail |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
ShoppingSalePage |
1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣1️⃣ |
https://wrtnlabs.io/agentica/docs/concepts/function-calling/#orchestration-strategy
验证反馈可以纠正人工智能生成的论证中的错误。
MCP 和 AI 函数调用经常会组合类型错误的参数(参数值)。这是导致 MCP 服务器和 AI 应用程序崩溃的另一个主要原因。
为了解决这个问题,当 AI 代理为特定函数组合错误类型的参数时,你需要提供有关哪里出错以及如何出错的具体详细信息,然后请求 AI 代理重建参数值。
Agentica将此称为验证反馈策略,它是提高函数调用成功率的核心策略之一。上表显示了在 OpenAIo3-mini模型上,AI 在每种场景下成功组合参数所需的尝试次数。除 1 以外的任何数字都表示执行了相应的验证反馈次数。
以上示例ObjectFunctionSchema代表ShoppingCartCommodity了相当复杂的类型,我们可以看出,如果没有验证反馈,成功的可能性很小。MCP 服务器失败的第二个原因可能是缺少这种验证反馈策略。
export interface IMcpLlmFunction<Model extends ILlmSchema.Model> {
name: string;
description?: string | undefined;
parameters: ILlmSchema.IParameters<Model>;
validate: (args: unknown) => IValidation<unknown>;
}
2.3 选择器代理
https://wrtnlabs.io/agentica/docs/concepts/function-calling/#validation-feedback
选择候选函数以减少上下文信息。
查看 OpenAI 或 Claude API 时,你会注意到一个名为 `<field_name>` 的字段,mcp_servers它旨在接收整个 MCP 服务器的信息。当你一次性将整个 MCP 服务器文档输入到 AI 代理时,上下文和标记的数量会变得非常庞大。
这就是为什么即使使用只有 30 个功能的 GitHub MCP 服务器,Claude Desktop 也经常崩溃或出现幻觉,甚至还没完成任何操作。如果功能从 30 个增加到 300 个,文档大小将达到约 8 MB,代码量将达到 21 万行。这样的配置根本无法处理。
agent=Agent(
name="Assistant",
instructions="Use the tools to achieve the task",
mcp_servers=[mcp_server_1, mcp_server_2]
)
为了解决这个问题,Agentica内部使用了一个选择器代理来筛选待调用的候选函数。该选择器代理收集每个函数的名称和描述IMcpLlmFunction.description,并执行 RAG(检索增强生成)搜索,以检查用户的语句是否暗示调用特定函数。如果暗示调用,则将该函数添加到候选列表中。
这样,调用代理通常只有 0-2 个目标函数,很少超过 4-5 个,这大大减少了上下文和令牌的消耗。它避免了将整个 MCP 服务器全部投入使用时,因大量上下文消耗而导致的幻觉mcp_servers。
使用选择器代理来筛选候选函数并节省上下文消耗是使 MCP 服务器 100% 成功的第三种策略。
3. 文档驱动开发
@Controller(`shoppings/customers/sales`)
export class ShoppingCustomerSaleController {
/**
* List up every summarized sales.
*
* List up every {@link IShoppingSale.ISummary summarized sales}.
*
* As you can see, returned sales are summarized, not detailed. It does not
* contain the SKU (Stock Keeping Unit) information represented by the
* {@link IShoppingSaleUnitOption} and {@link IShoppingSaleUnitStock} types.
* If you want to get such detailed information of a sale, use
* `GET /shoppings/customers/sales/{id}` operation for each sale.
*
* > If you're an A.I. chatbot, and the user wants to buy or compose
* > {@link IShoppingCartCommodity shopping cart} from a sale, please
* > call the `GET /shoppings/customers/sales/{id}` operation at least once
* > to the target sale to get detailed SKU information about the sale.
* > It needs to be run at least once for the next steps.
*
* @param input Request info of pagination, searching and sorting
* @returns Paginated sales with summarized information
* @tag Sale
*
* @author Samchon
*/
@TypedRoute.Patch()
public index(
@ShoppingCustomerAuth() customer: IShoppingCustomer,
@TypedBody() input: IShoppingSale.IRequest,
): Promise<IPage<IShoppingSale.ISummary>>;
/**
* Get a sale with detailed information.
*
* Get a {@link IShoppingSale sale} with detailed information including
* the SKU (Stock Keeping Unit) information represented by the
* {@link IShoppingSaleUnitOption} and {@link IShoppingSaleUnitStock} types.
*
* > If you're an A.I. chatbot, and the user wants to buy or compose a
* > {@link IShoppingCartCommodity shopping cart} from a sale, please call
* > this operation at least once to the target sale to get detailed SKU
* > information about the sale.
* >
* > It needs to be run at least once for the next steps. In other words,
* > if you A.I. agent has called this operation to a specific sale, you
* > don't need to call this operation again for the same sale.
* >
* > Additionally, please do not summarize the SKU information. Just show
* > the every options and stocks in the sale with detailed information.
*
* @param id Target sale's {@link IShoppingSale.id}
* @returns Detailed sale information
* @tag Sale
*
* @author Samchon
*/
@TypedRoute.Get(":id")
public at(
@props.AuthGuard() actor: Actor,
@TypedParam("id") id: string & tags.Format<"uuid">,
): Promise<IShoppingSale>;
}
https://github.com/samchon/shopping-backend
函数和类型的文档完善程度决定了您的人工智能应用程序的质量。
如果你想使用 MCP 创建一个企业级 AI 应用,而不仅仅是一个玩具项目——一个由 MCP 服务器提供数百个功能的 AI 应用——你需要认真记录每个功能。
请考虑选择器代理应如何确定在哪些情况下调用哪个函数,并详细说明每个函数的用途。如果函数之间存在执行前提条件,请将其包含在内IMcpLlmFunction.description。AI 代理将自行按正确的顺序执行这些函数。
此外,请详细记录每种 DTO 类型及其属性。仅仅定义类型是不够的。您的文档应该解释 AI 代理如何根据用户的语音构建每个属性。
@samchon/shopping-backend这是一个拥有 289 个函数的 API 服务器,可能比你见过的任何服务器都多。它还展示了 AI 应用开发文档的最佳实践,函数调用成功率接近 100%。
与其按照 MCP 理念构建工作流代理,不如列出适合您 AI 应用用途的功能。重点在于为每个功能和类型编写详尽的文档。这样,您的 AI 应用将变得可扩展、灵活且高效。
import { tags } from "typia";
/**
* Restriction information of the coupon.
*
* @author Samchon
*/
export interface IShoppingCouponRestriction {
/**
* Access level of coupon.
*
* - public: possible to find from public API
* - private: unable to find from public API
* - arbitrarily assigned by the seller or administrator
* - issued from one-time link
*/
access: "public" | "private";
/**
* Exclusivity or not.
*
* An exclusive discount coupon refers to a discount coupon that has an
* exclusive relationship with other discount coupons and can only be
* used alone. That is, when an exclusive discount coupon is used, no
* other discount coupon can be used for the same
* {@link IShoppingOrder order} or {@link IShoppingOrderGood good}.
*
* Please note that this exclusive attribute is a very different concept
* from multiplicative, which means whether the same coupon can be
* multiplied and applied to multiple coupons of the same order, so
* please do not confuse them.
*/
exclusive: boolean;
/**
* Limited quantity issued.
*
* If there is a limit to the quantity issued, it becomes impossible
* to issue tickets exceeding this value.
*
* In other words, the concept of N coupons being issued on
* a first-come, first-served basis is created.
*/
volume: null | (number & tags.Type<"uint32">);
/**
* Limited quantity issued per person.
*
* As a limit to the total amount of issuance per person, it is
* common to assign 1 to limit duplicate issuance to the same citizen,
* or to use the NULL value to set no limit.
*
* Of course, by assigning a value of N, the total amount issued
* to the same citizen can be limited.
*/
volume_per_citizen: null | (number & tags.Type<"uint32">);
/**
* Expiration day(s) value.
*
* The concept of expiring N days after a discount coupon ticket is issued.
*
* Therefore, customers must use the ticket within N days, if possible,
* from the time it is issued.
*/
expired_in: null | (number & tags.Type<"uint32">);
/**
* Expiration date.
*
* A concept that expires after YYYY-MM-DD after a discount coupon ticket
* is issued.
*
* Double restrictions are possible with expired_in, of which the one
* with the shorter expiration date is used.
*/
expired_at: null | (string & tags.Format<"date-time">);
}
4. TypeScript 类函数调用
import { Agentica } from "@agentica/core";
import OpenAI from "openai";
import typia from "typia";
import { BbsArticleService } from "./services/BbsArticleService";
const agent = new Agentica({
vendor: {
model: "gpt-4o-mini",
api: new OpenAI({ apiKey: "********" }),
},
controllers: [
{
protocol: "class",
application: typia.llm.application<BbsArticleService, "chatgpt">(),
execute: new BbsArticleService(),
},
],
});
await agent.conversate("I want to write an article.");
不一定要用 MCP。直接调用 TypeScript 类的函数即可。
您已经了解了Agentica为确保 MCP 100% 成功而采用的策略。但Agentica支持的协议不仅限于 MCP,还包括TypeScript Class。
如果您想为 AI 应用程序提供的功能不需要服务器,并且只需使用 TypeScript 类即可实现,那就去做吧。
您的 TypeScript 类类型将在编译级别进行分析typia,以便自动生成匹配的 AI 函数调用模式。
5. OpenAPI 函数调用
import { Agentica } from "@agentica/core";
import { HttpLlm, OpenApi } from "@samchon/openapi";
import typia from "typia";
const agent = new Agentica({
model: "chatgpt",
vendor: {
api: new OpenAI({ apiKey: "*****" }),
model: "gpt-4o-mini",
},
controllers: [
{
protocol: "http",
name: "shopping",
application: HttpLlm.application({
model: "chatgpt",
document: await fetch(
"https://shopping-be.wrtn.ai/editor/swagger.json",
).then((r) => r.json()),
}),
connection: {
host: "https://shopping-be.wrtn.ai",
headers: {
Authorization: "Bearer *****",
},
},
},
],
});
await agent.conversate("I want to buy a MacBook Pro");
不要不必要地迁移到MCP。OpenAPI目前运行良好。
您已经了解了Agentica为确保 MCP 100% 成功而采用的策略。但Agentica也支持Swagger/OpenAPI协议。
如果您正在考虑迁移到 MCP 以基于现有后端服务器开发 AI 应用程序,则无需这样做。只需使用后端服务器的 OpenAPI 文档(swagger.json)。
您的 OpenAPI 文档将被转换为匹配的 AI 函数调用模式,绕过转换逻辑。@samchon/openapi
6. Agentica
- GitHub 仓库:https://github.com/wrtnlabs/agentica
- 指南文档:https://wrtnlabs.io/agentica
Agentica 是一个专门用于函数调用的 TypeScript AI 代理框架。
它包含了本单元讨论的所有 MCP 增强策略,并且还支持 TypeScript 类和 OpenAPI 的函数调用。
它可能是目前最简单、最可靠的人工智能框架,请务必了解一下。





