Designing a Good MCP Tool Schema for Search

A technical look at shaping query parameters, pagination, and result output for a search tool exposed over MCP.

Start with the input schema

An MCP tool declares its inputs as a JSON Schema object, and for a search tool that schema is what determines whether the model can actually use it well. At minimum you need a required query string. Beyond that, the parameters worth exposing are the ones a model can reasonably decide on its own — a count/limit, maybe a freshness or recency filter, maybe a domain include/exclude list — kept optional with sensible defaults so the model isn't forced to specify things it has no basis for guessing.

{
  "name": "search",
  "description": "Search the web and return a ranked list of results.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "description": "The search query." },
      "max_results": { "type": "integer", "default": 5, "minimum": 1, "maximum": 20 },
      "freshness": { "type": "string", "enum": ["day", "week", "month", "year", "any"], "default": "any" },
      "include_domains": { "type": "array", "items": { "type": "string" } },
      "exclude_domains": { "type": "array", "items": { "type": "string" } }
    },
    "required": ["query"]
  }
}

Pagination: usually skip it

Traditional REST search APIs expose page tokens or offsets, but in an agent tool it's often better to avoid exposing pagination directly and instead let the model issue a new, refined query if the first batch of results wasn't enough — that keeps the schema simpler and tends to produce better results than a model mechanically paging through the same query. If you do need pagination (for a use case with a human reviewing many results, say), a simple opaque next_page_token field returned in the response and accepted as an optional input works better than raw numeric offsets.

Shaping the output

Keep each result to the fields a model actually needs to reason and cite: title, URL, and a short snippet, plus optionally a published date if freshness matters for the task. Resist the temptation to return everything the underlying API gives you — extra fields cost context tokens and give the model more surface area to latch onto irrelevant details.

{
  "results": [
    { "title": "...", "url": "https://...", "snippet": "...", "published": "2026-05-01" }
  ]
}

Errors as data, not exceptions

Return failures (timeout, rate limit, zero results) as a structured field in the tool response rather than letting the call fail silently or crash the MCP server — a model can reason about "the search returned zero results, I should try a different query" far better than it can recover from an opaque error.