面试题库
共 328 题,当前筛选 3 题。
课程全部30 天从前端工程师到 Agent 工程师5 天提示词工程零基础Claude 高效使用:从对话到 Claude CodeCodex 与 OpenAI Agents SDK 高效使用7 天 MCP:把工具接进任何 Agent7 天 Agent Skills:把经验做成可复用能力5 天上下文工程14 天 RAG:从检索到可信回答14 天用 Agent 搭一条 AI 短剧生产线
7 天 MCP:把工具接进任何 Agent
D1 为什么需要一个协议:host / client / server 三角、JSON-RPC 消息与三种原语
2026-07-28 这一版把 MCP 改成了无状态协议,删掉了 initialize 握手。这么改的代价是什么?服务端还想保存状态该怎么办?The 2026-07-28 revision made MCP stateless and removed the initialize handshake. What does that cost, and how should a server that still needs state handle it?
国内高频海外高频深入#protocol-versions#statelessness分析过程 · 先想清楚再作答
- 这题的区分度在「知不知道这一版改了什么」。凭旧记忆答握手、会话标识、断流续传的人会当场暴露,因为这三样在这一版全被删了。
- 先说改了什么:没有 initialize 与 notifications/initialized,每条请求在 _meta 里自带协议版本与客户端能力;新增 server/discover 供客户端一次性取回版本、能力与身份,服务端必须实现它。
- 拆代价的角度是「省了什么、贵了什么」。贵的是报文:每条请求都要重复带版本与能力块。省的是三件事——任意副本都能处理请求所以扩容不用粘性路由、一条连接可以穿插无关请求、进程重启后在途请求重发即可。
- 结论:这是一次拿带宽换可伸缩性的交易,对本机 stdio 几乎无感,对多副本的远程部署收益很大。
- 状态怎么办:显式句柄。创建工具返回一个服务端铸造的 id,后续调用把它当普通参数传回来;服务端把状态按这个 key 存在自己的库里,并在工具描述里写清有效期。
- 可预期的追问:句柄安全吗?必须补一句——句柄是名字不是凭证,服务端每次都要重新校验调用者身份,句柄要用安全随机数生成、绑定到已认证的主体、并设过期时间。
How to reason about it · think before answering
- The discriminator is whether you know what this revision changed. Anyone answering from memory about handshakes, session IDs, or stream resumption exposes themselves — all three were removed.
- State the change first: no initialize and no notifications/initialized; every request carries its protocol version and client capabilities in _meta, and a new server/discover method, which servers MUST implement, returns versions, capabilities, and identity in one call.
- Weigh it as saved versus paid. You pay in payload size, repeating the version and capability block on every request. You save three things: any replica can serve any request so scaling needs no sticky routing, unrelated requests can interleave on one connection, and after a restart in-flight requests simply get resent.
- Conclusion: it trades bandwidth for scalability — near-invisible on local stdio, valuable for multi-replica remote deployments.
- For state, use explicit handles: a creation tool returns a server-minted id, and later calls pass it back as an ordinary argument while the server keys its own storage on it and documents the lifetime in the tool description.
- Likely follow-up: is a handle safe? Say it unprompted — a handle is a name, not a credential. Re-authorize the caller on every call, generate handles with a secure random source, bind them to the authenticated principal, and expire them.
答题要点
- 这一版删掉了 initialize 握手、协议级会话、GET 长连接与断流续传,改为每条请求自带版本与能力
- 新增 server/discover,服务端必须实现,客户端可在任何请求前一次性取回版本、能力与身份
- 代价是报文变胖,收益是无粘性路由的横向扩容、连接上可穿插无关请求、重启后重发即可
- 跨调用状态改用服务端铸造的显式句柄,作为普通工具参数传递,并且句柄不等于身份认证
Key points
- The revision removed the initialize handshake, protocol-level sessions, the GET stream, and stream resumption; each request now carries version and capabilities
- It added server/discover, which servers must implement, letting clients fetch versions, capabilities, and identity up front
- The cost is larger payloads; the payoff is sticky-free horizontal scaling, interleaved unrelated requests, and cheap retry after restarts
- Cross-call state moves to server-minted explicit handles passed as ordinary tool arguments, and a handle is never authentication
D4 远程 MCP:Streamable HTTP 绑定、无状态模型与请求元数据、OAuth 2.1 授权、容器部署
2026-07-28 去掉了协议级会话。那一个需要跨调用保存状态的远程服务端——比如购物车、数据库事务——应该怎么设计?The 2026-07-28 revision removed protocol-level sessions. How should a remote server that needs cross-call state — a shopping cart, a database transaction — be designed?
国内高频海外高频进阶#statelessness#api-design分析过程 · 先想清楚再作答
- 这题在筛「有没有把无状态当成设计约束」。答「用 Mcp-Session-Id 头」的当场出局,那个头这一版已经删了;答「存在服务端内存里按连接查」的同样出局,因为客户端根本不保证复用连接。
- 先给结构:状态必须由客户端携带,服务端只认请求里带来的东西。落地成两种形态——一是服务端铸造的显式句柄,创建工具返回一个 id,后续调用把它当普通工具参数传回来;二是签过名的不透明状态串,比如多轮请求里的 requestState,服务端把上下文签进去,重试时原样收回。
- 两者的差别在于「谁存数据」:句柄背后的购物车内容还是存在服务端的库里,句柄只是主键;requestState 是把上下文本身编码进字符串,服务端零存储。前者适合长期存在的业务对象,后者适合一次交互内的续接。
- 结论:不管哪种,服务端内存里都不为某个客户端留东西,所以任何副本都能处理任何请求,扩容不需要粘性路由——这正是这次改动想换来的东西。
- 安全是必须主动补的一句:句柄是名字不是凭证。要用安全随机数生成、绑定到已认证的主体(按 user_id 加 handle 做键)、设过期时间,并且每次调用重新校验调用者身份。规范明确写了服务端不得把持有句柄当成身份认证。requestState 同理,它经客户端转手,是攻击者可控输入,必须 HMAC 或 AEAD 验签,并把主体、原请求标识、短过期签进去。
- 可预期的追问:多副本时 requestState 怎么办?答案是所有副本共享签名密钥即可,这仍然是无状态的——状态在客户端手里,副本只负责验签。追问二可能是「怎么保证一次性」,答案是签名只能缩小重放窗口,真要单次消费得自己在服务端加一层消费记录。
How to reason about it · think before answering
- The screen is whether you treat statelessness as a design constraint. Answering 'use Mcp-Session-Id' fails immediately — that header was removed. So does 'keep it in server memory keyed by connection', since clients are not required to reuse connections.
- Give the structure first: state must travel with the client, and the server trusts only what arrives in the request. Two concrete shapes — a server-minted explicit handle returned by a creation tool and passed back as an ordinary tool argument, or a signed opaque blob like the requestState used by multi round-trip requests.
- The difference is who stores the data. A handle is just a primary key into server-side storage; a requestState encodes the context itself, so the server stores nothing. Handles suit long-lived business objects, requestState suits continuing a single interaction.
- Conclusion: either way the server keeps nothing per client in memory, so any replica can serve any request and scaling needs no sticky routing — which is exactly what the change was buying.
- Volunteer the security half: a handle is a name, not a credential. Generate it from a secure random source, bind it server-side to the authenticated principal (key storage as user id plus handle), expire it, and re-authorize on every call — the spec says possession of a handle must not be treated as authentication. requestState passes through the client, so it is attacker-controlled input and must be integrity-protected with HMAC or AEAD, carrying the principal, an originating-request identifier, and a short expiry.
- Likely follow-up: what about requestState across replicas? Share the signing key; it is still stateless because the state lives with the client and replicas only verify. A second follow-up is single use — signing bounds the replay window but does not guarantee one-time consumption, which needs a server-side redemption record.
答题要点
- 状态必须由客户端携带:服务端铸造显式句柄,作为普通工具参数在后续调用里传回
- 一次交互内的续接可以用签名的不透明状态串,服务端零存储,多副本共享签名密钥即可
- 句柄不是凭证:安全随机生成、绑定已认证主体、设过期,每次调用重新鉴权
- 收益是任何副本能处理任何请求,扩容不需要粘性路由,重启后重发即可
Key points
- State travels with the client: the server mints an explicit handle that later calls pass back as an ordinary tool argument
- Within one interaction, a signed opaque blob works with zero server storage; replicas just share the signing key
- A handle is not a credential: securely random, bound to the authenticated principal, expiring, re-authorized on every call
- The payoff is that any replica serves any request, so scaling needs no sticky routing and retries are cheap
D6 安全与治理:工具描述里的提示注入、混淆代理、最小权限、审计日志与工具白名单
2026-07-28 之后协议是无状态的,服务端要保存状态就得铸一个句柄让客户端带回来。这会带来什么新的攻击面?怎么防?Since the protocol is stateless, a server that needs state mints a handle for the client to carry back. What attack surface does that create, and how do you close it?
国内高频海外高频进阶#statelessness#security分析过程 · 先想清楚再作答
- 这题在考「换了机制之后有没有重新想过威胁模型」。上一版的会话劫持大家都熟,这一版会话没了,很多人就默认问题跟着消失了——其实只是换了个名字叫状态句柄劫持。
- 先描述攻击,四步很短:服务端为已认证用户铸一个句柄并放在工具结果里返回;攻击者拿到或猜到这个句柄;攻击者把它当成普通工具参数发过来;服务端没检查这个句柄属不属于调用者,于是操作了原用户的状态。
- 拆「拿到或猜到」这一层很关键,因为它决定了防线该架在哪。猜到,说明句柄可预测(自增 id、时间戳、短随机数);拿到,路径就多了——它出现在工具结果里,而工具结果会进模型上下文、会进日志、可能被另一个服务端看到,也可能被一次提示注入骗着吐出来。所以「句柄不会泄漏」这个假设不能要。
- 防线按规范分三层答。硬性的:实现了授权的服务端**必须**校验所有入站请求,并且**绝不能**把持有句柄当成身份认证——这是整题的题眼,句柄是名字不是凭证。应当层:用安全随机数生成,避免可预测或连续的标识,并设过期。最管用的一层也是应当:**在服务端把句柄绑定到已认证的主体**,比如存储的键做成「用户 id 加句柄」,用户 id 从校验过的令牌里取而不是客户端传,别的主体拿着同一个句柄来就查不到。这样即使猜中也冒充不了别人。
- 然后主动把 requestState 归到同一类:它是多轮请求里由服务端签发、经客户端转手带回的不透明状态,规范要求把它当成攻击者可控输入,用 HMAC 或 AEAD 做完整性保护、验签用定长比较,并把认证主体、原请求标识、短过期一起签进去,分别挡跨用户、跨请求和超时三种重放。
- 结论一句话:无状态没有消灭状态,只是把状态挪到了客户端手里,于是「谁能出示它」和「谁有权用它」必须被分开对待。
- 可预期的追问一:签名能不能保证一次性?不能,签名只缩小重放窗口,真要单次消费得在服务端加一层消费记录。追问二:多副本部署怎么办?句柄背后的数据本来就在共享存储里,requestState 只需要各副本共享签名密钥——这仍然是无状态的,因为服务端内存里没有为某个客户端留东西。
How to reason about it · think before answering
- This checks whether you re-derived the threat model after the mechanism changed. Everyone knows session hijacking from the previous revision; sessions are gone now, so many assume the problem left with them. It only got renamed to state handle hijacking.
- Describe the attack in four steps: the server mints a handle for an authenticated user and returns it in a tool result; the attacker obtains or guesses it; the attacker sends it back as an ordinary tool argument; the server never checks whether the handle belongs to the caller and operates on the original user's state.
- Unpack 'obtains or guesses', because it decides where the defense goes. Guessing means the handle is predictable, such as a sequential id, a timestamp, or too little entropy. Obtaining has many paths: the handle appears in a tool result, so it enters the model context, the logs, possibly another server's view, and it can be coaxed out by a prompt injection. The assumption that handles stay secret is not available to you.
- Answer the defenses in the spec's tiers. Mandatory: servers implementing authorization MUST verify all inbound requests and MUST NOT treat possession of a handle as authentication. That is the crux, a handle is a name, not a credential. Recommended: generate handles from a secure random source, avoid predictable or sequential identifiers, and expire them. The most effective recommendation is binding: key server-side storage as user id plus handle, with the user id derived from the verified token rather than supplied by the client, and reject a handle presented by any other principal, so guessing it still buys nothing.
- Volunteer that requestState belongs to the same family: a server-signed opaque blob carried back through the client in multi round-trip requests, which the spec requires you to treat as attacker-controlled input, protect with HMAC or AEAD, verify with a constant-time comparison, and bind to the authenticated principal, an originating-request identifier, and a short expiry, covering cross-user, cross-request, and timeout replay.
- One-line conclusion: statelessness did not remove state, it moved it into the client's hands, so 'who can present it' and 'who is allowed to use it' must be judged separately.
- Likely follow-ups: does signing guarantee single use? No, it only bounds the replay window; true one-time consumption needs a server-side redemption record. And what about replicas? The data behind a handle already lives in shared storage, and requestState only needs a shared signing key, which is still stateless because nothing per client sits in a replica's memory.
答题要点
- 新攻击面叫状态句柄劫持:拿到或猜到句柄的人可以操作别人的状态
- 句柄会出现在工具结果、上下文与日志里,不能假设它不泄漏
- 硬性要求:必须校验所有入站请求,绝不能把持有句柄当成身份认证
- 做法:安全随机、设过期、按「主体加句柄」在服务端绑定;requestState 同理,验签并签进主体与短过期
Key points
- The new surface is state handle hijacking: anyone who obtains or guesses a handle can act on another user's state
- Handles surface in tool results, model context and logs, so secrecy is not a safe assumption
- Mandatory: verify every inbound request and never treat possession of a handle as authentication
- Use secure randomness, expiry, and server-side binding keyed by principal plus handle; requestState needs signing bound to principal and a short expiry