作者:互联网 时间: 2026-07-18 08:18:55
三个 MCP Server 靠记忆管理。二十个需要系统。

企业内 MCP Server 数量增加后出现的典型问题:
search_jira 工具(v1.x)而不是新的 search_issues(v2.x)Registry 解决发现,路由解决分发,可观测性解决定位。
Registry 是企业内 MCP Server 的目录,记录每个 Server 的位置、版本、能力和责任人。
复制代码# mcp-registry.yaml
servers:
- id: jira-tools
name: Jira 工具集
description: "Jira 工单的搜索、创建、更新操作"
version: "2.1.0"
domain: engineering # 按领域分类
owner: "@team-platform"
status: active # active / deprecated / experimental
transport: stdio
command: python
args: ["/opt/mcp/jira/server.py"]
capabilities:
tools: [search_issues, create_issue, update_issue]
resources: [jira://projects, jira://sprint/current]
metrics:
monthly_calls: 4521
avg_latency_ms: 180
error_rate: 0.2% - id: github-tools
name: GitHub 工具集
version: "1.5.0"
domain: engineering
owner: "@team-platform"
status: active
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
capabilities:
tools: [create_pull_request, search_repositories, get_file_contents] - id: postgres-readonly
name: PostgreSQL 只读查询
version: "1.0.0"
domain: data
owner: "@team-data"
status: active
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL}"]
capabilities:
tools: [query]
resources: ["postgres://analytics/schema"] - id: jira-tools-legacy
name: Jira 工具集(旧版)
version: "1.2.0"
domain: engineering
status: deprecated
deprecation:
reason: "已被 jira-tools v2.x 取代,search_jira 更名为 search_issues"
migration_guide: "将 search_jira 替换为 search_issues,参数结构不变"
removal_date: "2026-10-01"
capabilities:
tools: [search_jira, create_jira_ticket]
Registry 解决三个问题:
Agent 需要"搜索 Jira 工单"时,如何自动找到正确的 Server?四种策略:
在 Agent 的 settings.json 里直接声明所有 Server:
复制代码{
"mcpServers": {
"jira": {
"command": "python",
"args": ["/opt/mcp/jira/server.py"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"]
}
}
}
优点:简单、可预测。缺点:新增 Server 需要手动更新每个 Agent 的配置文件。
Agent 启动时根据任务类型加载对应 Server,不一次性加载所有:
复制代码DOMAIN_SERVERS = {
"engineering": ["jira-tools", "github-tools", "gitlab-tools"],
"data": ["postgres-readonly", "bigquery-tools"],
"communication": ["slack-tools", "email-tools"],
}def load_servers_for_task(task_type: str) -> list[dict]:
"""根据任务领域加载相关 Server,避免加载不必要的服务"""
domain = classify_task_domain(task_type)
server_ids = DOMAIN_SERVERS.get(domain, []) registry = load_registry()
return [
s for s in registry["servers"]
if s["id"] in server_ids and s["status"] == "active"
]
优点:减少不必要的 Server 启动开销,每个 Agent 只加载需要的工具。
和 Skill 系列第 06 篇的做法一样——把 Server 描述向量化,用户请求也向量化,找最近邻:
复制代码def route_to_server(user_input: str, registry: list[dict]) -> list[str]:
"""返回与用户请求语义最匹配的 Server ID 列表"""
query_embedding = embedder.embed(user_input)
scored = []
for server in registry:
desc_embedding = get_cached_embedding(server["id"], server["description"])
score = cosine_similarity(query_embedding, desc_embedding)
scored.append((server["id"], score)) # 取相似度最高的前 3 个
scored.sort(key=lambda x: x[1], reverse=True)
return [s[0] for s in scored[:3] if s[1] > 0.6]
适合 Server 数量多(> 20 个)且经常新增 Server 的场景。同样的问题——同领域 Server 描述相似,容易混淆——需要在描述里加负面示例(见 Skill 系列第 06 篇的讨论)。
先按 domain 粗过滤,再在 domain 内用 Embedding 精选:
复制代码def hierarchical_route(user_input: str, registry: list[dict]) -> list[str]:
# 第一层:LLM 快速分类 domain
domain = llm_classify_domain(user_input) # "engineering" / "data" / ... # 第二层:在 domain 内 Embedding 匹配
domain_servers = [s for s in registry if s.get("domain") == domain]
return embedding_route(user_input, domain_servers)
没有 Trace,MCP 工具调用是黑盒——失败了不知道原因,慢了不知道哪里慢,Token 贵了不知道贵在哪个工具。
复制代码from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_contextlangfuse = Langfuse()@observe(name="mcp_tool_call")
async def traced_tool_call(
server_id: str,
tool_name: str,
arguments: dict,
call_fn # 实际调用 MCP Server 的函数
) -> dict:
# 记录调用上下文
langfuse_context.update_current_observation(
input={"tool": tool_name, "arguments": arguments},
metadata={
"server_id": server_id,
"server_version": get_server_version(server_id),
}
) t0 = time.perf_counter()
try:
result = await call_fn(tool_name, arguments)
latency_ms = (time.perf_counter() - t0) * 1000 langfuse_context.update_current_observation(
output=result,
metadata={"latency_ms": round(latency_ms, 2), "success": True}
)
return result except Exception as exc:
latency_ms = (time.perf_counter() - t0) * 1000
langfuse_context.update_current_observation(
output={"error": str(exc)},
metadata={"latency_ms": round(latency_ms, 2), "success": False},
level="ERROR"
)
raise
复制代码@observe(name="agent_session")
async def run_agent_session(user_input: str, session_id: str):
langfuse_context.update_current_trace(
session_id=session_id,
user_id="user:alice",
metadata={"task_type": "jira_query"}
) # Agent 运行时,每次工具调用都自动关联到这个 Trace
result = await agent.run(user_input) langfuse_context.update_current_observation(output={"result": result})
return result
复制代码哪个工具调用最慢?
→ 按 latency_ms 排序 Span哪个 Server 错误率最高?
→ 按 server_id 分组,统计 success=False 的比例Token 消耗集中在哪里?
→ LLM Span 里的 usage 字段,按 tool_name 分组某次 Agent 失败的根因是什么?
→ 在 Langfuse 搜 session_id,展开完整的 Trace 树
把关键指标接入告警系统(Grafana / Prometheus / 内部监控):
复制代码# 告警规则模板(Prometheus alerting rules 格式)
groups:
- name: mcp_server_alerts
rules:
# Server 可用率告警
- alert: MCPServerHighErrorRate
expr: mcp_tool_call_error_rate_5m > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "MCP Server {{ $labels.server_id }} error rate {{ $value | humanizePercentage }}" # 工具调用延迟告警
- alert: MCPToolHighLatency
expr: mcp_tool_call_p90_latency_ms > 5000
for: 3m
labels:
severity: warning
annotations:
summary: "Tool {{ $labels.tool_name }} P90 latency {{ $value }}ms" # Server 版本仍在使用废弃工具
- alert: DeprecatedToolInUse
expr: mcp_deprecated_tool_calls_total > 0
for: 0m
labels:
severity: info
annotations:
summary: "Deprecated tool {{ $labels.tool_name }} called {{ $value }} times today"
Level 1 — 个人/小团队(立即可做):
Level 2 — 团队共享(1-2 周):
Level 3 — 企业治理(持续建设):
欢迎访问 PrimeSkills —— 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。
更多实用知识和有趣产品,欢迎访问我的个人主页