Function Calling 是模型表达“我想调用什么”的格式,MCP 是工具能力如何被发现、描述和接入的协议。MCP 不会替模型做决策,也不会自动解决权限问题。
面试中最容易出现的错误是把 MCP 和 Function Calling 当作竞争关系:
MCP Server 暴露工具
↓
MCP Client 获取工具定义
↓
Agent Runtime 把候选工具交给模型
↓
模型输出 Function Call
↓
Runtime 通过 MCP Client 调用 MCP Server
↓
结果回到模型上下文
本文重点回答三个问题:
- MCP 到底解决了什么集成问题?
- Agent 如何使用 MCP 暴露的 Tools、Resources 和 Prompts?
- 企业接入多个 MCP Server 时,如何处理权限、安全和治理?
一、面试官:Function Calling 和 MCP 有什么区别?
1.1 推荐回答
Function Calling 解决的是模型与宿主程序之间的调用表达。模型根据上下文输出工具名和结构化参数,宿主程序负责验证和执行。
MCP 解决的是客户端与工具服务之间的能力发现和连接标准化。MCP Server 可以声明自己提供哪些 Tools、Resources 和 Prompts,MCP Client 可以通过统一协议发现和调用它们。
两者属于上下游关系:
| 层次 | 解决的问题 | 典型对象 |
|---|---|---|
| 模型决策层 | 下一步想调用哪个能力、参数是什么 | Function Calling / Tool Call |
| Agent Runtime | 校验、鉴权、预算、重试和执行控制 | Tool Executor |
| 能力接入层 | 能力如何发现、描述、连接和调用 | MCP Client / MCP Server |
| 业务系统层 | 真正的数据和副作用 | 数据库、Git、订单、支付系统 |
因此,使用 MCP 并不意味着不需要 Function Calling。Runtime 仍然需要把 MCP Server 的工具描述转换成模型能理解的 Tool Schema。
1.2 MCP 解决的 M×N 问题
没有统一协议时,假设有 5 个 Agent 宿主和 20 个内部系统:
5 个 Agent × 20 个系统 = 100 组适配逻辑
如果每个系统都提供 MCP Server,每个宿主只需实现 MCP Client:
5 个 MCP Client + 20 个 MCP Server = 25 个协议适配点
这不是简单的数量计算,实际收益还包括:
- 工具描述格式统一;
- 能力发现不再依赖硬编码;
- Server 可以独立升级;
- Client 可以统一做权限和审计;
- 一个 Server 能被多个 Agent 使用。
MCP 没有消灭业务适配工作。订单系统仍需要编写订单查询 Server,区别是接入边界和调用方式统一了。
1.3 MCP 不负责什么?
面试时主动说出边界会更完整:
- MCP 不负责判断用户意图;
- MCP 不保证模型选对工具;
- MCP 不替代业务权限系统;
- MCP 不保证工具执行一定成功;
- MCP 不自动提供幂等、事务和重试;
- MCP Server 返回的数据仍可能包含不可信内容。
二、MCP 的完整调用链是什么?
2.1 启动与能力发现
一个简化的启动过程如下:
client = MCPClient(transport=transport)
await client.initialize({
"client_name": "support-agent",
"client_version": "1.0.0",
})
capabilities = await client.list_tools()
返回的工具定义可能是:
{
"tools": [
{
"name": "get_order_by_id",
"description": "根据订单号查询当前用户的订单详情。只读。",
"inputSchema": {
"type": "object",
"properties": {
"order_id": {"type": "string"}
},
"required": ["order_id"],
"additionalProperties": false
}
}
]
}
Agent Runtime 不应直接把所有 Server 的工具无条件交给模型,而应先做归一化和过滤:
def build_model_tools(user, task, mcp_clients):
all_tools = []
for client in mcp_clients:
for tool in client.cached_tools:
if not policy.can_discover(user, tool):
continue
if not tool.is_available_for(task.state):
continue
all_tools.append(normalize_tool(tool, client.server_name))
return semantic_recall(task.message, all_tools, top_k=8)
这里至少做三件事:
- 给工具加上来源 Server,避免名称冲突;
- 按用户权限和任务状态过滤;
- 只把相关候选工具交给模型。
2.2 模型选择工具
模型看到的仍然是 Tool Schema,因此选择机制和上一篇 Function Calling 相同:
{
"name": "get_order_by_id",
"arguments": "{\"order_id\":\"ORD-001\"}"
}
Runtime 收到调用后,根据工具来源路由到对应 MCP Client:
async def dispatch_tool_call(call, registry):
tool = registry.resolve(call.name)
args = parse_and_validate(call.arguments, tool.input_schema)
await authorize(tool, args)
result = await tool.client.call_tool(tool.remote_name, args)
return sanitize_tool_result(result)
2.3 MCP Server 执行并返回结果
Server 负责把协议请求转换成具体业务调用:
@server.tool(
name="get_order_by_id",
description="根据订单号查询当前用户的订单详情。"
)
async def get_order_by_id(order_id: str, context: RequestContext):
if not order_id.startswith("ORD-"):
raise InvalidArgument("订单号格式不正确")
order = await order_service.get_for_user(
user_id=context.user_id,
order_id=order_id,
)
return {
"ok": True,
"data": {
"order_id": order.id,
"status": order.status,
"updated_at": order.updated_at.isoformat(),
},
}
注意这里的 context.user_id 应来自受信任的认证上下文,而不是模型参数。
三、MCP 的三种核心原语分别是什么?
3.1 Tools:可执行能力
Tools 是模型或 Agent Runtime 可以调用的动作,例如:
- 查询订单;
- 搜索代码仓库;
- 创建工单;
- 执行数据库只读查询;
- 获取监控指标。
Tool 具有输入参数,通常可能产生外部副作用。生产环境要额外声明:
name: create_ticket
risk_level: medium
side_effect: true
idempotent: true
required_permission: support.ticket.create
timeout_seconds: 10
3.2 Resources:可读取的数据资源
Resources 更接近可读取的上下文或数据对象,例如:
- 文件;
- 文档;
- 数据库表说明;
- Git 仓库内容;
- 监控面板数据。
资源读取不一定需要模型自由选择 Tool。Runtime 可以根据任务状态按需加载,也可以让模型请求资源 URI:
resource://repo/payment-service/src/refund.py
资源内容仍然需要做权限过滤、大小限制和敏感信息脱敏。
3.3 Prompts:可复用的提示模板
Prompts 用于暴露可复用的任务模板,例如:
review_pr(pr_url, focus="security")
diagnose_incident(service, time_range)
它不是强制执行的 Workflow,也不是安全策略。Prompt 只能提供建议和上下文,真正的权限、步骤和风险控制仍由 Runtime 负责。
3.4 三种原语如何组合?
例如一个代码审查 Agent:
Prompt:review_pr
↓
Resource:读取 Pull Request 和相关文件
↓
Tool:运行静态检查和测试
↓
Resource:读取测试结果
↓
Tool:创建审查评论
面试时不要把三种原语说成完全互斥的产品形态。它们描述的是不同类型的能力。
四、MCP 使用什么传输方式?
4.1 stdio:本地进程
stdio 适合本地工具或桌面 Agent:
MCP Client ──stdin/stdout── MCP Server 子进程
优点:
- 部署简单;
- 不需要开放网络端口;
- 本地文件和开发工具接入方便。
风险:
- 子进程隔离和资源限制;
- 凭据如何注入;
- 标准输出不能混入调试日志;
- Server 生命周期由 Client 管理。
4.2 HTTP:远程服务
HTTP 适合企业内部共享服务或跨主机部署:
Agent Runtime ──HTTP── MCP Gateway ──HTTP/RPC── MCP Server
生产环境需要考虑:
- TLS 和服务身份认证;
- 请求超时和连接池;
- 服务发现和负载均衡;
- 限流、熔断和重试;
- 多租户上下文传播;
- 审计日志和 trace 透传。
传输方式不是“本地一定 stdio、生产一定 HTTP”的绝对规则,而是根据隔离边界、部署方式、延迟和安全要求选择。
五、企业接入 20 个内部系统,选 MCP 还是自研工具层?
5.1 推荐回答
我会先区分两个问题:
- 是否需要标准化能力发现和跨宿主复用?
- 企业内部是否已经有统一的权限、审计和服务治理层?
如果多个 Agent、IDE 或自动化客户端都需要接入同一批系统,MCP 适合作为能力接入协议。对于企业核心交易系统,我不会让 MCP Server 直接暴露数据库或高风险 API,而是在中间增加企业工具治理层:
模型
↓
Agent Runtime
↓ 统一鉴权、策略、预算、审计
MCP Gateway
↓
领域 MCP Server
↓
订单 / 财务 / 工单 / 数据平台
如果公司已经有成熟的内部 Tool Registry 或 API Gateway,也不必为了“使用 MCP”重写所有系统。可以让现有工具层作为 MCP Server 的后端,先统一外部能力描述,再逐步迁移。
5.2 六项生产治理
认证与身份传播
MCP Client 需要确认 Server 身份,Server 需要知道请求来自哪个用户、租户和任务:
trace_id
user_id
tenant_id
agent_id
task_id
身份不能只放在模型生成的参数中,而应通过受信任的请求上下文传播。
权限与工具可见性
权限控制应至少有两层:
- 工具是否对当前用户可见;
- 实际调用时参数是否仍然有权限。
只在模型提示词中写“不要调用管理员工具”是不够的。模型看不到的工具更安全,但最终执行时仍要再次鉴权。
审计
每次调用至少记录:
{
"trace_id": "tr_001",
"user_id": "u_123",
"server": "order-server",
"tool": "cancel_unpaid_order",
"arguments_hash": "sha256:...",
"risk_level": "high",
"result": "success",
"latency_ms": 142
}
敏感参数应脱敏或只记录哈希,不能把完整支付信息写进普通日志。
限流与预算
要同时限制用户、租户、Agent、Server 和 Tool 的调用量:
单用户每分钟查询上限
单租户并发任务上限
单任务 Tool 调用次数
单个 Server 的 QPS
错误语义
Server 不应只返回一段异常文本,应区分:
{
"ok": false,
"error": {
"code": "ORDER_NOT_FOUND",
"message": "订单不存在或当前用户无权访问",
"retryable": false,
"user_action": "ask_for_order_id"
}
}
Runtime 才能据此决定重试、换工具、追问用户还是直接结束。
版本与兼容性
工具 Schema 是模型依赖的接口。修改字段名、必填字段或语义都可能改变模型行为,应支持:
- 工具版本;
- 向后兼容字段;
- 废弃周期;
- Schema 回归测试;
- 灰度发布和快速回滚。
六、MCP Server 返回内容会污染模型吗?
会。MCP Server 返回的文档、网页、工单或代码都属于外部数据,其中可能包含“忽略系统规则”的恶意文本。
不要把工具结果和系统指令混成同一个可信层级:
observation = {
"source": "mcp:knowledge-server",
"trust": "untrusted_data",
"content": sanitize(result.content),
}
运行时应:
- 标记数据来源和信任等级;
- 限制返回大小和嵌套深度;
- 对 HTML、脚本和敏感字段做清洗;
- 将读取能力与写操作隔离;
- 写操作重新鉴权并要求确认;
- 不因为文档内容要求调用高风险 Tool 就自动执行。
MCP 提供连接标准,不能替代 Prompt Injection 防护和应用安全边界。
七、MCP、OpenAPI 和自研 Tool Registry 怎么选?
| 方案 | 强项 | 适合场景 | 注意事项 |
|---|---|---|---|
| MCP | 面向 Agent 的能力发现与交互 | 多客户端共享工具和资源 | 仍需企业治理层 |
| OpenAPI | HTTP API 契约和文档 | 已有 REST 服务、代码生成 | 不直接定义 Agent 上下文管理 |
| 自研 Tool Registry | 可完全按内部流程定制 | 单一平台、强控制场景 | 维护成本和生态复用较高 |
实际工程可以组合:
已有 OpenAPI 服务
↓ 适配层
MCP Server
↓
Agent Runtime
不建议为了协议统一,把成熟的内部服务全部重写成另一种实现。先确定复用边界、治理边界和迁移收益。
八、MCP 工具如何与 Skill、Sub-agent 区分?
可以按职责划分:
- Tool:一个可执行动作,例如查询订单;
- Resource:一个可读取对象,例如仓库文件;
- Skill:完成一类任务的知识、流程和工具使用约定;
- Sub-agent:拥有独立上下文和目标的执行单元;
- Workflow:由代码或状态机确定的步骤和分支。
例如“排查线上支付故障”:
Skill:故障排查方法和判断顺序
↓
Sub-agent:支付故障分析上下文
↓
MCP Resource:读取日志和指标
↓
MCP Tool:执行只读诊断查询
↓
Workflow:人工确认后执行回滚
协议只解决能力接入,不能替代这些上层编排设计。
九、面试追问速答
MCP 与 Function Calling 是替代关系吗?
不是。Function Calling 是模型表达调用意图,MCP 是工具能力的发现与接入协议,通常由 Runtime 把 MCP 工具转换为模型可用的 Tool Schema。
为什么不能直接把 MCP Server 全部工具给模型?
会增加上下文和选择成本,也扩大权限暴露面。应按领域、用户权限、任务状态和语义相关性筛选候选工具。
MCP Server 是否可信?
Server 本身需要认证和授权,但返回的数据仍可能是外部不可信内容。Runtime 要做来源标记、清洗和高风险操作隔离。
stdio 和 HTTP 怎么选?
本地单机工具通常适合 stdio;跨主机共享和企业服务通常使用 HTTP。最终根据隔离、认证、延迟、治理和部署边界决定。
MCP 能解决权限问题吗?
不能。MCP 可以描述能力,但用户、租户、资源和参数级权限仍需由 Gateway、Server 和业务系统共同执行。
为什么还需要自研 Gateway?
统一做身份传播、工具筛选、审计、限流、预算、版本和风险策略。MCP Server 不应该各自实现一套不一致的治理逻辑。
MCP 和 OpenAPI 的区别?
OpenAPI 主要描述 HTTP API 契约,MCP 面向 Agent 场景提供工具、资源和提示的发现与交互。已有 OpenAPI 服务可以通过适配层暴露为 MCP Server。
