Giving Agents the API Spec Only (OpenAPI)

When an agent drives an HTTP client, the most common failure is inventing paths, methods, or fields that are not in the contract. A short chat note (“the API is roughly like this”) is weaker than handing it one OpenAPI (Swagger) document and requiring it to use only declared paths and components.

This post covers only where to put the spec · how to give response examples · how to reduce hallucinations. mcp-tool-schema is MCP tool JSON Schema wording; mcp-resource-vs-tool is resource vs tool selection. Here the axis is feeding OpenAPI alone into agent context. No pricing, plans, tokens, or affiliate links.

Grounded in OpenAPI Specification v3.1.0 (Paths, Media Type, Response, Example Object) and the usual workflow of attaching a read-only contract file to the agent.

Where should the spec file live?

One-line answer: Keep a single source of truth (OpenAPI YAML/JSON) in the repo and point the agent at that path or URI. Do not paste the full document into every prompt.

Practical layout:

LocationRoleHow the agent gets it
openapi.yaml / openapi.json (root, docs/, or specs/)Contract source of truthFix the relative path in Rule / AGENTS.md
CI-generated snapshotSchema extracted from codeReference only the committed artifact path
MCP resource URIHost-pulled read-only contextSupply the spec via resources/read
Internal HTML docs siteHuman narrativePrefer the raw OpenAPI as agent input

Suggested prompt line:

API contract: only <repo>/docs/openapi.yaml
Allowed: paths + components declared there.
Forbidden: invent endpoints, fields, status codes, or auth schemes.

Avoid:

  • Pasting a memo of paths without schemas → field names and types hallucinate immediately.
  • Giving only README curl samples and hiding OpenAPI → when samples drift, the agent treats the sample as truth.
  • Loading openapi-v1.yaml and openapi-v2.yaml together → name one allowed version in the Rule.

If the document is huge, do not inject the whole file every turn. Have the agent read a path-prefix slice or a generated partial with resolved $refs—and still keep the canonical file path in the brief.

How should response examples be supplied?

One-line answer: Put examples on the OpenAPI Media Type Object as example or examples, alongside schema. Do not drop bare JSON into chat as the contract.

In OpenAPI 3.1, request and response body examples live on the Media Type Object. example and examples are mutually exclusive; Media Type values override any example on the schema. A Response Object’s content map is media-type key → Media Type Object.

Minimal shape (conceptual):

responses:
  "200":
    description: OK
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/Item"
        examples:
          sample:
            summary: typical item
            value:
              id: "item_1"
              name: "widget"
  "404":
    description: Not found
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/Error"
        example:
          code: "not_found"
          message: "Item not found"

Rules when briefing the agent:

  1. Include success and failure — 200 alone invites invented error bodies. Declare 4xx/5xx schemas and examples.
  2. Field names match the schema — keys that appear only in examples look like undocumented fields.
  3. Use the examples map for variants — name cases like empty_list or with_cursor.
  4. External samples — Example Object may use externalValue, but if the agent cannot fetch the network, prefer inline value.
  5. Same for request bodies — Media Type example/examples on the request body cuts payload hallucination.

Short chat helper:

Prefer response examples from the OpenAPI Media Type Object.
Do not treat README curl snippets as the contract if they diverge.

How do you reduce hallucinations?

One-line answer: Lock a forbid rule—“if it is not in the spec, do not call or write it”—and require a pre-call check of path · method · required against the document.

Checklist:

[ ] Single OpenAPI path in Rule / brief (one file, one version)
[ ] Agent may only use operationId or method+path listed under paths
[ ] required parameters / requestBody fields must come from the spec
[ ] Status codes and error bodies must match declared responses
[ ] If unsure: stop and ask / open a ticket — do not invent
[ ] After edit: regenerate or validate OpenAPI (spectral, openapi-cli, etc.)

Typical failure modes:

SymptomCauseMitigation
Invented path like /v2/widgetsNatural-language-only briefAllow only paths keys
Mixed camelCase / snake_caseExample vs schema driftAlign examples with schema
Random headers or query paramsMissing Parameter ObjectsDeclare parameters and required
Assumes only 200 bodiesNo error responsesDefine 4xx / default
Old endpoints reappearMixed old versions in contextOne version, one file

If you have tooling, parse the spec into an allow-list before HTTP calls—stronger than chat reminders. Even without tools, put “every called path exists under openapi paths” in the Done definition so human review is cheap.

Adjacent posts: whether to attach the spec as an MCP resource belongs in mcp-resource-vs-tool; tool-argument wording belongs in mcp-tool-schema.

One-line wrap-up: One OpenAPI path → Media Type examples for success/failure → forbid calls outside paths. Do not send an agent out on prose-only API descriptions.

FAQ

Does OpenAPI 2.0 (Swagger) work the same way?

The principle—hand a contract file and forbid anything outside paths—is the same. This post uses 3.x Media Type Object placement for examples. If your team is on 2.0, follow that document’s examples / definitions rules.

Can we use an agent before a spec exists?

Commit a minimal OpenAPI (paths, methods, schemas, a couple of examples) first, then attach the agent. Generating code with no contract usually costs more when you reconcile later.

What if README and OpenAPI disagree?

Agent rules should prefer OpenAPI. Keep README as human narrative; fix the spec or the README—do not tell the agent to “merge them somehow.”

The full spec is too large for context?

Narrow the task scope with a path prefix, tags, or operationId list, and read only those Path Items plus related $refs. Keep the forbid rule: do not invent paths outside the list.

Sources