Lab · Intermediate · 90 min
Build an MCP Server Whose Idle Schema Stays Small
Wrap an internal API as an MCP server with three well-designed tools instead of fifteen thin ones, measure the idle token cost, and connect it to two clients.
Cursor · Claude Code · OpenAI Codex · LangChain / LangGraph
Show all 4 stepsHide list
Step 1 of 4
Lab brief
Goal
A stdio MCP server with ≤ 3 tools, compact schemas, paginated results, isError handling, and a measured idle schema size.
Failure mode
Auto-generated server exposes every REST endpoint as a tool; the agent burns thousands of tokens on schemas and keeps picking the wrong list_* call.
Staff move
Design tools around user intents, not endpoints; measure the schema cost; and allowlist tools per client.
Step 2 of 4
1. Design tools around intents
| Instead of | Expose |
|---|---|
| list_tickets, get_ticket, list_comments, get_user | search_tickets(query, status?, limit?) → compact rows |
| get_ticket + get_comments + get_links | get_ticket(id, include?: ['comments','links']) |
| update_status, update_assignee, update_priority | update_ticket(id, patch) — marked destructive, needs approval |
Step 3 of 4
2. Build and measure
- Implement with the official TypeScript or Python MCP SDK over stdio
- Keep each description to one or two sentences; use enums and required fields in schemas
- Return compact JSON with a next_cursor for pagination; cap default limits
- On failure, return a tool result with isError: true and a message the model can act on
- Dump the tools/list response and count its tokens — that is your idle cost per session
Step 4 of 4
3. Connect and restrict
- Cursor: add to .cursor/mcp.json for this project only
- Codex: [mcp_servers.tickets] with enabled_tools = ["search_tickets", "get_ticket"] for read-only sessions
- Run the same 3 tasks with the old endpoint-style server and yours; compare tool-call count and success
Stretch
Expose it over Streamable HTTP behind OAuth and load it into a LangGraph agent through an MCP adapter.