Rohan Sharma

Designing an MCP server that spends few tokens

2 min read

Lessons from building a Flipkart seller MCP server: fewer tools, summaries by default, capped lists, and why the tool schema is the first thing to shrink.

An agent that talks to an API through the Model Context Protocol pays for it in context twice. It pays once to carry the description of every tool, on every turn, and again for every payload a tool returns. When I built flipkart-seller-mcp, a server for Flipkart's Seller v3 API, I treated both as the design problem.

Shrink the tool schema first

The Seller API covers shipments, listings, inventory, returns, ads and financials. Mapping each endpoint to its own tool gives more than thirty tools, and an agent has to carry all their names, descriptions and argument schemas on every turn whether or not it uses them.

The server exposes five domain tools instead: flipkart_manage_shipments, flipkart_manage_inventory, flipkart_manage_returns, flipkart_manage_ads and flipkart_manage_financials. Each takes an action argument.

flipkart_manage_shipments(action="search", state="APPROVED")
flipkart_manage_shipments(action="inspect", shipment_ids=["SHIP_ID"])
flipkart_manage_shipments(action="mark_rtd", shipment_ids=["SHIP_ID"])

That cut the schema an agent carries from about 4,000 tokens to about 500.

Return summaries, not payloads

A raw order or listing response can run past 5,000 tokens for a single call, and most of it is fields the agent will never look at. Every tool defaults to detail_level="summary", which returns a compact Markdown table of the columns that matter for the decision at hand, roughly 100 to 300 tokens. detail_level="full" returns the untouched JSON when the agent genuinely needs it.

The default matters more than the option. An agent that has to ask for the big payload only pays for it when it decides to.

Cap every list

Lists are capped at ten items a page by default. An agent that wants more asks for the next page. Without a cap, one unlucky search returns hundreds of rows and the conversation is over before the agent has acted.

Keep the descriptions terse

Tool and field descriptions get sent every turn too. They are written as short as they can be while still telling the model what to do, and the argument models are Pydantic classes with concise annotations so the schema stays small.

Auth should not cost a turn

The server uses OAuth2 client credentials and refreshes the token five minutes before it expires, so an agent never spends a turn on an expired-token error. When credentials are missing it falls back to a mock mode, which makes the server usable in a demo or a test without a seller account.

The trade-offs

Consolidating tools is not free.

  • An action argument pushes complexity into the description. The model has to pick the right action from a list, and a wrong pick is a worse failure than picking the wrong tool, so the docstrings spell out the supported actions.
  • Five wide tools are harder to permission than thirty narrow ones. If you need per-action access control, enforce it in the server and not in the schema.
  • The numbers above are for this API. Count your own schema with a tokenizer before and after, and measure with real conversations, because the best shape depends on what your agents actually do.

The rule I keep from it: treat context as a budget, spend it where the agent decides something, and make the cheap path the default.

Questions or corrections? Email me.