MCP 工具是給只按字面理解的實習生使用的 API
Your MCP Tools Are an API for a Very Literal Intern
Magnus Williams 分享 MCP 工具設計方法,建議以清晰命名、明確描述和結構化參數限制,減少智能體選錯工具或提交不合適輸入。描述應交代輸入、回傳值及後續工具,錯誤訊息則要指出問題、預期格式和下一步。對有副作用的操作,應分開準備與執行,並在執行前取得用戶批准;他亦建議精簡工具集,並用簡單提示詞測試不同模型的工具選擇和參數。
Picture a tool called save that takes a content string. You ask an agent to save a 12-page document. It saves a 40 word summary, cheerfully reports success and moves on. Technically correct. Completely useless.
That's rarely the model's fault. It's usually the tool's. An agent reads your tool definitions the way a very literal intern reads a sticky note on their first day. It has no hallway context, no memory of last week's standup and no idea what you were thinking when you named something save.
Here are the rules we follow when designing tools that agents use well. None of them are clever. All of them save time.
1. Name tools as noun_verb, and be boring about it
Agents choose tools mostly by name and description. A vague name invites guessing.
We settled on a noun_verb pattern across the whole server:
goals_list
goals_add
goals_complete
documents_list
document_read
document_save
reminder_add
reminders_list
Grouping by noun means related tools sit together when the client lists them. Plural nouns for collections and singular nouns for one item tells the agent whether it is about to get one thing or many. It looks pedantic. It also heads off a whole category of "I listed when I meant to read" mistakes.
2. Write descriptions for someone who will take them literally
The description is the only documentation the agent reliably reads. So write it like a contract.
Bad:
{
"name": "document_save",
"description": "Saves a document."
}
Better:
{
"name": "document_save",
"description": "Save the FULL text of a document to the user's files. Do not summarize or shorten the content. Returns the saved document's id. Use document_read to fetch it later."
}
The second version answers the questions the agent would ask if it could: what exactly goes in, what comes back and which tool comes next. The capital letters are not decoration. "FULL" is the word that stops the 40-word summary.
3. Make bad arguments impossible, not just unlikely
Free text arguments are where agents get creative, and you do not want creativity in a date field.
Use enums, formats and bounds wherever you can:
{
"type": "object",
"properties": {
"title": { "type": "string", "minLength": 3, "maxLength": 120 },
"due": { "type": "string", "format": "date", "description": "YYYY-MM-DD in the user's timezone" },
"priority": { "type": "string", "enum": ["low", "normal", "high"] }
},
"required": ["title"]
}
Every constraint in the schema is one less instruction you need in the prompt. It is also one less thing that breaks when you switch models, because the schema means the same thing to all of them.
4. Error messages are instructions
When a tool call fails, the error message goes straight back to the agent. Most of the time, it will try again based on what you told it.
So "400 Bad Request" is a wasted turn. This is better:
due must be a date in YYYY-MM-DD format. You sent "next Friday".
Resolve relative dates first, then call reminder_add again.
Treat every error string as a tiny prompt. Say what was wrong, what was expected and what to do next. Agents recover far more often when they're told how.
5. Separate "prepare" from "do" for anything with side effects
If a tool sends an email, spends money or deletes something, split it in two. One tool prepares the action and returns a summary. A second tool executes it only after the user approves.
In our server that is a pending action plus action_approve and action_cancel. The agent can be as eager as it likes. Nothing irreversible happens without a human click. I wrote about this pattern in more detail here, so I'll keep it short.
6. Keep the toolset small
It is tempting to expose every endpoint you have. Resist it. Each extra tool is another option the agent has to consider on every turn, and similar-looking tools get confused with each other.
A good test: if two tools would have nearly the same description, merge them or rename them until the difference is obvious from the name alone.
7. Test with the dumbest prompt you can think of
The best test cases are lazy user requests. "Remind me about the thing." "Save this." "What are my goals" with no question mark and no context.
Run those against your server with a couple of different models. Watch which tool gets picked and what arguments come back. You will find the ambiguous names and missing constraints very quickly, usually in a way that makes you laugh and then sigh.
The short version
- Boring, consistent
noun_verbnames. - Descriptions written as contracts.
- Schemas that make bad input impossible.
- Error messages that tell the agent what to do next.
- Prepare and approve for anything with side effects.
- Fewer tools than you think you need.
The models will keep getting smarter. Your tools will still be read by a very literal intern. Design for the intern and everyone wins.
I'm Head of SI Agents at Magnus, where we run an MCP server that connects any MCP client to a user's goals, documents and reminders. This post was drafted with help from an SI writing assistant and edited by me.
來源:DEV Community · dev.to
