Here are some patterns that worked and didn't work in production:
What didn't work:
1. Fine-grained CRUD endpoints. I started with the obvious get_request, update_request_status, update_request_assignee, add_comment, etc. The agent would frequently call the wrong one or chain them in the wrong order. Too many similar tools = confusion.
2. Generic parameter names. A field called "id" meant nothing to the agent without context. It would hallucinate IDs or pass the wrong entity's ID.
3. Sparse error messages. Returning "404 Not Found" gave the agent nothing to work with. It would retry the same bad call indefinitely.
What worked:
1. Fewer, wider tools. Instead of 8 CRUD endpoints, I collapsed them into 3: search_requests, get_request_detail, update_request. The agent made far fewer mistakes with a smaller tool set.
2. Descriptive schemas with examples. Adding "description" fields with example values in the JSON schema dramatically improved accuracy. The schema IS the prompt.
3. Rich error responses. Instead of "404", returning "No request found with ID 'abc'. Did you mean to search first? Available tool: search_requests" actually got the agent to self-correct.
4. Read-before-write pattern. Structuring tools so the agent naturally fetches context before making changes reduced destructive mistakes significantly.
5. Confirmation fields for dangerous operations. Adding a required "confirm: true" parameter for deletes/bulk updates acts as a speed bump that makes the agent think twice.
The mental model shift: you're not designing an API for a developer reading docs. You're designing an interface for a reasoning engine that only sees the schema and the last few messages. Every field name, description, and error message is a prompt.
Curious if others building MCP servers have found similar patterns or discovered different approaches.