面试表达
面试时怎么讲
一句话:我围绕「MCP / ACP 协议与工具生态」做过从问题拆解、方案设计、工程落地到效果验证的闭环。
追问重点:为什么这么设计、指标怎么验证、失败案例如何定位、上线后怎么观测和回滚。
证据建议:准备 README、架构图、关键代码片段、评测表和 2 个坏例复盘。
把“知道协议名”变成“会集成、会排障、会讲价值”的实战能力。
本地学习进度
只保存在当前浏览器,不上传服务器。
学习产出
实战交付,P2。阅读时尽量把知识点转成可演示项目、面试回答和简历证据。
能回答
课程目标 / 概念对齐 / 10 天学习路径
能交付
整理一页项目笔记,记录问题、方案、指标和取舍
下一步
把本篇总结成 90 秒面试讲述
面试表达
一句话:我围绕「MCP / ACP 协议与工具生态」做过从问题拆解、方案设计、工程落地到效果验证的闭环。
追问重点:为什么这么设计、指标怎么验证、失败案例如何定位、上线后怎么观测和回滚。
证据建议:准备 README、架构图、关键代码片段、评测表和 2 个坏例复盘。
简历表达
围绕 MCP / ACP 协议与工具生态 场景,完成「把“知道协议名”变成“会集成、会排障、会讲价值”的实战能力。」相关能力建设,沉淀可复用工程方案、测试样本和面试表达材料。
| 概念 | 你要能一句话解释 |
|---|---|
| Tool | 模型可调用的能力,带 schema |
| Resource | 可读上下文(文件、URI) |
| Transport | stdio / Streamable HTTP(旧 HTTP+SSE 已弃用) |
| 治理 | 白名单、审计、敏感操作二次确认 |
llmops-observability-evaluation 字段对齐。mcp-integration-notes.md + 排障 checklist面试里能说"我做过一个 MCP Server 并接入 Claude Desktop / Cursor"比"我知道 MCP"值 2 倍薪水。以下是把协议知识升级为生产级 Server 的完整工程栈。
2026 年 7 月 28 日,MCP 2026-07-28 正式规范发布。它相对 2025-11-25 含有破坏性变化;新实现应以最终 changelog 与所用 SDK 的兼容说明为准,而不是继续照搬 RC 或旧握手示例:
initialize / initialized 握手和 Mcp-Session-Id。客户端可先调用 server/discover,每个请求携带协议版本、客户端信息与能力;Streamable HTTP 请求使用 Mcp-Method / Mcp-Name,便于普通网关路由和无粘性会话的水平扩展。tools/call 返回 task handle,Client 使用 tasks/get、tasks/update、tasks/cancel 驱动生命周期;tasks/list 因无会话条件下难以安全划分范围而被移除。ttlMs / cacheScope,并约定 W3C Trace Context 在 _meta 中的传播方式。iss 若存在必须与已记录 issuer 严格比较;新实现优先使用 Client ID Metadata Documents。Roots、Sampling、Logging 和旧 HTTP+SSE 已进入弃用生命周期,但不是在本版本中立即删除。| 抽象 | 含义 | 典型例子 | 误用 |
|---|---|---|---|
| Tool | 模型可调用的"动作",有副作用或强计算 | create_order / run_sql / send_email | 把"只读查询"也包成 Tool(浪费轮次) |
| Resource | 可 URI 定位的"可读上下文" | file://... / git://repo/path / kb://doc-123 | 把"搜索"做成 Resource(搜索是动作,应做 Tool) |
| Prompt | 预置工作流模板 | /review-pr / /daily-standup | 把动态参数塞进 Prompt 却不做校验 |
裁决口诀:"取数据用 Resource,做事用 Tool,固定流程用 Prompt"。
HTTP 传输的 MCP Authorization 基于 OAuth 2.1 及一组既有 RFC;stdio 通常从环境获取凭据,不直接照搬浏览器授权流程。务必掌握:
aud=mcp-server-id,防止跨 server token 重放。tools:read / tools:execute:low / tools:execute:high 分级;不要一个 mcp:all。iss 时必须做严格字符串比较,声明支持却缺失时拒绝。def verify_token(raw: str) -> Principal:
claims = jwt.decode(raw, JWKS, audience="mcp://orders-server",
issuer="https://auth.acme.com")
if claims["scope"].split().count("tools:execute:high") == 0:
raise HttpError(403, "insufficient scope")
return Principal(sub=claims["sub"], tid=claims["tid"], scopes=claims["scope"].split())面试陷阱:"Bearer token 够用吗?" —— 不够。要 aud 绑定 + scope 分级 + 敏感工具二次挑战(step-up auth)。
{
"name": "create_refund",
"title": "创建退款单",
"description": "对指定订单发起退款。需要订单 ID 与金额;金额必须小于等于订单实付金额。",
"inputSchema": {
"type": "object",
"required": ["order_id", "amount", "reason"],
"properties": {
"order_id": {"type": "string", "pattern": "^ORD-[0-9]{10}$"},
"amount": {"type": "number", "exclusiveMinimum": 0, "maximum": 100000},
"reason": {"type": "string", "minLength": 5, "maxLength": 500}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": false,
"openWorldHint": false
}
}要点:
destructiveHint=true 的工具客户端会默认要求人审。v1.0.0 初版
v1.1.0 新增可选字段 currency ← 兼容
v1.2.0 annotations 更新描述 ← 兼容
v2.0.0 reason 由 optional 变 required ← 破坏策略:
minor bump,客户端自动适配。create_refund_v1 + create_refund_v2,并行 30-90 天再下线。serverInfo 里带 protocolVersion 与 tools[].version。所有错误走 JSON-RPC 标准:
| Code | 含义 | 典型场景 |
|---|---|---|
| -32600 | Invalid Request | 协议层畸形 |
| -32601 | Method not found | 工具不存在 |
| -32602 | Invalid params | schema 校验不通过 |
| -32000 ~ -32019 | 实现自定义区段 | 业务错(细分,现有 SDK 用法保留) |
| -32020 ~ -32099 | MCP 规范保留 | 不要分配给业务错误 |
业务层自定义:
{"code": -32010, "message": "order.not_found", "data": {"orderId": "ORD-..."}}
{"code": -32011, "message": "permission.denied", "data": {"requiredScope": "tools:execute:high"}}
{"code": -32012, "message": "rate.limited", "data": {"retryAfterMs": 1500}}Timeout:每个 Tool 在 schema 里声明 x-timeout-ms(非标准但常用),客户端据此显示 loading;Server 侧硬超时。
principal.sub + tool.name 双维度限流:令牌桶。Retry-After;客户端应指数退避。@tool(
name="create_refund",
annotations=Annotations(destructive=True),
)
def create_refund(order_id: str, amount: float, reason: str, ctx: Ctx):
if amount > ctx.principal.auto_approve_limit:
return require_approval(
approver=ctx.principal.manager_id,
payload={"order_id": order_id, "amount": amount},
)
return do_refund(order_id, amount, reason)# 伪代码:具体方法名以所用 SDK 的 2026-07-28 迁移文档为准
@pytest.fixture
def mcp_client():
server = subprocess.Popen(["python", "-m", "myserver"], stdin=PIPE, stdout=PIPE)
client = StdioMCPClient(server)
discovery = client.discover(
protocol_version="2026-07-28",
client_info={"name": "contract-tests", "version": "1.0.0"},
)
assert "2026-07-28" in discovery.supported_protocol_versions
yield client
server.terminate()
def test_create_refund_requires_scope(mcp_client, token_readonly):
mcp_client.authenticate(token_readonly)
resp = mcp_client.call_tool("create_refund", {"order_id": "ORD-1", "amount": 1, "reason": "test"})
assert resp.error.code == -32011
def test_schema_rejects_negative_amount(mcp_client, token_admin):
mcp_client.authenticate(token_admin)
resp = mcp_client.call_tool("create_refund", {"order_id": "ORD-1", "amount": -1, "reason": "bug"})
assert resp.error.code == -32602jsonschema 校验每个 Tool 的 request/response。pip install mcp-server-orders;Node npx mcp-server-orders。mcp.json,Claude Desktop / Cursor / Continue 可一键安装。每次工具调用写 trace:
{
"trace_id": "...", "span_id": "...",
"server": "orders-mcp", "tool": "create_refund",
"principal": "u-123", "tenant": "acme",
"scope_used": "tools:execute:high",
"input_hash": "sha256:...", "output_truncated": false,
"latency_ms": 420, "status": "ok",
"approval_id": "appr-456"
}read/write × low/medium/high。aud 绑定 + 短有效期 + refresh rotation。与 ai-application-security、agent-state-persistence-hitl、middleware-for-ai-backend、llmops-observability-evaluation 联动。