逐日AI

面试题库

共 328 题,当前筛选 2 题。

7 天 MCP:把工具接进任何 Agent

D2 写第一个 MCP server:stdio 传输、官方 SDK、参数 schema、工具注解与 Inspector 调试

  • 一个 stdio 的 MCP 服务端最常见的翻车原因是什么?你会在代码和流程上分别怎么堵住它?What is the most common way a stdio MCP server breaks, and how do you prevent it in code and in process?
    国内高频海外高频深入#stdio-transport#debugging

    分析过程 · 先想清楚再作答

    1. 这题在验有没有真跑过。没实际接过的人会答「进程没起来」「路径不对」这类泛泛的,真踩过的人第一句就会说标准输出被污染。
    2. 拆法:先复述 stdio 的硬规矩——消息是一行一条换行分隔的 JSON、内部不许有裸换行,服务端不得往标准输出写任何不是 MCP 消息的东西,日志一律走标准错误。规矩一说完,翻车原因就自明了。
    3. 现场特征值得单独说,因为它是这题的区分点:客户端只会报一句 JSON 解析失败,指不到你哪一行 console.log;而且污染源常常不是你自己的代码,而是某个第三方库在启动时打的横幅或弃用警告。
    4. 结论分两层。代码上:封一个只写标准错误的日志函数并全局禁用直接打印,接第三方库之前先确认它不往标准输出写东西,把 JSON 序列化后确保不含裸换行。流程上:加一个自测入口,用内存传输在同一个进程里把客户端和服务端接起来跑断言,有明确退出码,进持续集成——这样污染一出现就会在合并前被拦下。
    5. 再补一条相关的:优雅停机。规范说客户端关掉输入流、服务端读到文件结束就应尽快退出,这是主要且唯一可移植的停机信号;不处理它就会留下孤儿进程,本机开发时表现为端口和文件锁莫名被占。
    6. 可预期的追问:既然这么脆,为什么还用 stdio?因为它零配置、零网络攻击面、进程隔离天生就有,本机场景收益远大于代价;要给团队共享或多副本才需要换成远程传输。

    How to reason about it · think before answering

    1. This checks whether you have actually run one. People who have not will say 'the process did not start' or 'wrong path'; anyone who has been bitten leads with stdout contamination.
    2. Restate the hard rules first: messages are newline-delimited JSON, one per line, with no embedded newlines, and the server must not write anything to stdout that is not an MCP message. Logging goes to stderr. Once the rules are stated the failure mode is obvious.
    3. Call out the symptom, because that is the discriminator: the client only reports a JSON parse failure and cannot point at your console.log, and the polluter is often a third-party library printing a banner or deprecation warning at import time rather than your own code.
    4. Conclusion in two layers. In code: wrap a stderr-only logger, ban direct printing, vet third-party libraries for stdout writes, and ensure serialized JSON carries no raw newlines. In process: add a self-test entry point that links a client and server over an in-memory transport in one process, asserts, and exits with a real status code, then run it in CI so contamination is caught before merge.
    5. Add the adjacent one: graceful shutdown. The spec makes closing stdin and exiting on EOF the primary and only portable shutdown signal; ignoring it leaves orphan processes that show up locally as mysteriously held ports and file locks.
    6. Likely follow-up: if it is this fragile, why use stdio? Zero configuration, zero network attack surface, and process isolation for free — the tradeoff is clearly worth it locally. You switch transports when you need team sharing or multiple replicas.

    答题要点

    • 最常见的是标准输出被污染:stdio 规定 stdout 只能有 MCP 消息,一行 console.log 就让客户端解析失败
    • 现场只报 JSON 解析失败,指不到具体行,污染源常常是第三方库启动时打的横幅或警告
    • 代码上封一个只写标准错误的日志函数并禁用直接打印,接库之前先验它不写 stdout
    • 流程上加一个用内存传输的自测入口,有明确退出码并进持续集成;同时处理 stdin 关闭时的优雅退出

    Key points

    • Stdout contamination: stdio reserves stdout for MCP messages, so a single console.log breaks the client's parser
    • The symptom is only a JSON parse failure with no line number, and the culprit is often a third-party library's startup banner
    • In code, use a stderr-only logger, ban direct printing, and vet dependencies for stdout writes
    • In process, add an in-memory-transport self-test with a real exit code in CI, and exit promptly on stdin EOF to avoid orphan processes

D7 生产化与复盘:给工具写评估、版本化、发布到 npm 与 registry、可观测与综合项目

  • 线上有人反馈某个 MCP 工具「总是调不对」。你按什么顺序排查?A user reports that one of your MCP tools is 'always getting it wrong' in production. In what order do you investigate?
    国内高频海外高频进阶#observability#debugging

    分析过程 · 先想清楚再作答

    1. 这题考的是排查的**顺序**,不是知识点的多少。上来就贴日志和堆栈的人会被追问「你怎么知道问题在服务端」。
    2. 第零步是把「调不对」翻译成三种互斥的现象,这一步不做后面全是猜:一是**没被调**(模型压根没选这个工具);二是**调了但参数错**;三是**调了参数也对,但结果不对**。问一句「那次它是没动,还是动了但做错了」,或者直接去日志里看有没有这条调用记录,就能分开。
    3. 对应三条不同的路。没被调,问题在**描述**:去跑评估集,看正例还是边界掉了;正例掉说明描述写糊,边界掉说明缺了区分相似工具的那句话。参数错,问题在 **schema**:看字段名是不是有歧义、描述里有没有写清格式、必填项是不是标对了;这类问题的信号是错误率里工具执行错误持续偏高——那通常不是模型笨,是 schema 没说清。结果不对才是代码问题,这时候才轮到单元测试和日志。
    4. 指标层面的顺序也说一下:**先看错误率,再看选中率**。错误率正常但用户说不好用,八成是选不中;错误率飙了才去看代码和上游。耗时看 P95 不看平均值,远程服务端上一个工具从 200 毫秒退化到 8 秒,平均值可能只动一点点。
    5. 还有两条容易被忽略但很常见的原因,要主动提。一是**聚合冲突**:客户端连了多个服务端,两个工具重名,模型选中的是另一个服务端的那个——这时候「你的工具」根本没被调,查你的服务端永远查不出来。二是**版本或缓存**:列表结果带 ttlMs 缓存提示,客户端可能拿着旧的工具清单;工具清单变了要靠 listChanged 通知才会重新拉。
    6. 结论:这条链上有四个环节——描述、schema、聚合与缓存、实现。**按模型看得见的顺序从前往后查**,因为越靠前的环节越不产生错误日志,也就越容易被跳过。
    7. 可预期的追问:怎么留证据?每次调用记一条结构化日志,字段里要有工具名、参数摘要与字段名、是否 isError、耗时、以及这次调用有没有经过人工确认;最后那一栏是事后区分「用户授意」和「模型自作主张」的唯一依据。

    How to reason about it · think before answering

    1. This tests ordering, not breadth. Anyone who opens with logs and stack traces gets asked how they know the problem is server-side at all.
    2. Step zero is translating 'getting it wrong' into three mutually exclusive symptoms, without which everything after is guesswork: it was never called, it was called with wrong arguments, or it was called correctly and returned the wrong thing. Asking whether it did nothing or did the wrong thing, or simply checking whether a call was logged, separates them.
    3. Each symptom has its own path. Never called means the description is at fault: run the eval set and see whether happy paths or edges dropped, since happy-path drops mean a vague description and edge drops mean the sentence distinguishing similar tools is missing. Wrong arguments means the schema is at fault: ambiguous field names, unstated formats, wrong required markers. The signal is a persistently high tool-execution error rate, which usually means the schema is unclear rather than the model being dumb. Only a wrong result is a code problem, and only then do unit tests and logs matter.
    4. State the metric ordering too: error rate first, selection accuracy second. A normal error rate with unhappy users almost always means the tool is not being chosen; a spiking error rate sends you to the code and upstream. Watch P95, not the mean, because a remote tool degrading from 200 milliseconds to 8 seconds barely moves an average.
    5. Volunteer two commonly missed causes. Aggregation collisions: the client is connected to several servers, two tools share a name, and the model picked the other one, so your server was never called and investigating it will never find anything. And version or caching: list results carry ttlMs cache hints, so the client may hold a stale tool list, and refresh depends on a listChanged notification.
    6. Conclusion: the chain has four links, description, schema, aggregation and caching, and implementation. Walk it in the order the model sees it, because the earliest links produce no error logs and are therefore the ones people skip.
    7. Likely follow-up: how do you keep evidence? Emit one structured log per call with tool name, an argument digest plus field names, the isError flag, duration, and whether a human confirmed the call, that last column being the only way to distinguish user intent from the model acting on its own.

    答题要点

    • 先把「调不对」分成没被调、参数错、结果错三种互斥现象,再决定查哪里
    • 没被调查描述并跑评估集;参数错查 schema;结果错才轮到代码与日志
    • 指标顺序是先错误率再选中率;耗时看 P95 不看平均值
    • 别漏掉聚合重名(选中的是别的服务端的同名工具)和工具清单缓存这两类原因

    Key points

    • First split 'getting it wrong' into never called, wrong arguments, or wrong result; the split decides where to look
    • Never called points at the description and the eval set; wrong arguments at the schema; only a wrong result at the code
    • Check error rate before selection accuracy, and read P95 rather than the mean
    • Do not miss aggregation collisions, where another server's same-named tool was chosen, or a stale cached tool list