·

Postman MCP With Gemini CLI

Set up Postman MCP in Gemini CLI so your AI agent can run and manage API collections and test suites right from your editor.

Contract testing — verifying that an API's actual responses still match what consumers were promised — is a good fit for Gemini CLI's strengths: long context for ingesting a full API doc set, and a terminal-native workflow that pairs naturally with newman and CI logs. This topic covers connecting Postman MCP to Gemini CLI, generating contract tests from documentation, catching a breaking change before it ships, and an honest comparison of output quality against Claude Code for the same task.


Installing and Connecting Postman MCP to Gemini CLI

Gemini CLI reads MCP server definitions from ~/.gemini/settings.json (global) or .gemini/settings.json (project-local), under the mcpServers key — the same shape Claude Desktop popularized, which most MCP servers document against by default:

{
  "mcpServers": {
    "postman": {
      "command": "npx",
      "args": ["-y", "@postman/postman-mcp-server", "--full"],
      "env": {
        "POSTMAN_API_KEY": "$POSTMAN_API_KEY"
      }
    }
  }
}

Gemini CLI expands $POSTMAN_API_KEY from the shell environment it's launched in, so export the variable before starting the CLI rather than writing the literal key into settings.json:

export POSTMAN_API_KEY="PMAK-xxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
gemini

Inside a session, run /mcp to list connected servers and confirm postman shows as connected with its tool count — a mismatch here (zero tools, or a connection error) is almost always the API key not resolving correctly rather than a problem with the server itself. Test with a read-only call first:

> List my Postman workspaces and the collections in each.

If you're working across both a project-local and global settings.json, note that Gemini CLI merges them, with project-local taking precedence on key collisions — useful if you want a shared personal Postman key globally but override the workspace-scoped key for one specific client project.

Tips
- Confirm the connection with /mcp before starting real work — a silently-zero tool count wastes a session's worth of failed tool calls before you notice.
- Keep the project-local .gitignore covering .gemini/settings.json if you ever put a literal key in it during a quick test — the $POSTMAN_API_KEY interpolation pattern above is the one worth keeping for anything checked in.
- --full is worth it here specifically if your contract-testing workflow touches mock servers to simulate a not-yet-built dependency — that's a full-only tool category.


Generating Contract Tests from API Documentation in Gemini CLI

Gemini CLI's larger context window is a genuine advantage for this specific job: point it at a full docs directory — OpenAPI spec, a changelog, and any hand-written API guide markdown — and ask for contract assertions that check the promises, not just "did it return 200."

Read ./docs/api/openapi.yaml and ./docs/api/CHANGELOG.md in full.
For the Orders API's public endpoints, create a Postman collection
"Orders API — Contract Tests" with one request per endpoint and
assertions that verify:
- Every field marked required in the schema is present and non-null
- Every field's type matches the schema (string/integer/boolean/array)
- Enum fields only contain documented enum values
- Deprecated fields (per the changelog) are still present if the
  deprecation window hasn't closed yet
pm.test("Contract: status field only uses documented enum values", function () {
    const body = pm.response.json();
    const documentedStatuses = ["pending", "paid", "shipped", "cancelled", "refunded"];
    pm.expect(documentedStatuses).to.include(body.status);
});

pm.test("Contract: deprecated 'legacyId' field still present (sunset 2026-12-01)", function () {
    const body = pm.response.json();
    pm.expect(body).to.have.property("legacyId");
});

That second test is the kind contract testing is actually for — it fails loudly the moment someone removes a deprecated field ahead of its published sunset date, which is exactly the class of accidental breaking change that slips through normal endpoint testing because the endpoint itself still "works."

Ask explicitly for schema validation blocks over long property-by-property chains when the response shape is large — it's both shorter to write and easier to keep current when a field gets added:

const orderSchema = {
    type: "object",
    required: ["id", "status", "totalCents", "legacyId"],
    properties: {
        id: { type: "string", format: "uuid" },
        status: { type: "string", enum: ["pending", "paid", "shipped", "cancelled", "refunded"] },
        totalCents: { type: "integer", minimum: 0 },
        legacyId: { type: ["string", "null"] }
    },
    additionalProperties: true
};

pm.test("Response conforms to published Order schema", function () {
    pm.response.to.have.jsonSchema(orderSchema);
});

Note additionalProperties: true there deliberately — a contract test should fail when a documented guarantee breaks, not when the API adds a new field nobody promised wouldn't appear. Setting additionalProperties: false turns your contract suite into an accidental "no one may ever add a field" gate, which is almost never the intent.

Tips
- Feed the full doc set (spec + changelog + hand-written guides), not just the OpenAPI file — deprecation windows and documented-but-not-yet-enforced rules usually live in the changelog, and Gemini CLI's context headroom makes this cheap to do.
- Default additionalProperties: true in generated schemas unless the contract explicitly forbids extra fields — the point is catching broken promises, not blocking additive, backward-compatible changes.
- Re-run contract test generation after every changelog update, not just when the spec's schema changes — a deprecation-window test is only useful if it exists before the sunset date arrives.


Practical Example: Detecting a Breaking API Change Before Release

The clearest demonstration of contract testing's value is catching a change that passes every functional test but breaks a downstream consumer's assumption. Walk through a realistic case: a backend PR changes totalCents (integer, cents) to total (decimal, dollars) without updating the spec first.

> I have a PR that changes the Orders API response. Here's the diff
> to the controller. Run the "Orders API — Contract Tests" collection
> against the PR's preview environment and tell me if this breaks
> any documented contract.
$ newman run "Orders API — Contract Tests.postman_collection.json" \
    -e preview-pr-482.postman_environment.json --reporters cli

❯ Orders
  → Get order by id
    GET {{baseUrl}}/orders/:orderId [200 OK, 88ms]
    ✗  Response conforms to published Order schema
       AssertionError: totalCents is required, got undefined

  1 failing

Feed that failure straight back:

> The contract test failed — totalCents is missing, replaced with
> a "total" field in dollars. Is this a breaking change for the
> published contract, or does the spec need updating first?

Gemini CLI, having read the OpenAPI spec earlier in the session, correctly identifies this as a breaking change against the published contract regardless of whether the new shape is arguably better — the point of contract testing isn't judging API design taste, it's catching undocumented breakage before a consumer does. The right fix path is either version the endpoint (/v2/orders/{id} with the new shape) or update the spec and coordinate a deprecation window for totalCents, not silently ship the rename.

This is the workflow that pays for itself: a contract suite that would take a human reviewer real effort to notice — "wait, did the field type change?" — catches it mechanically, every time, before merge.

Tips
- Run contract tests against a PR's preview/staging deployment, not just main, so breaking changes surface before merge rather than after deploy.
- When a contract test fails, ask the agent to classify it (breaking vs. additive vs. spec-needs-updating) rather than just reporting the failure — that classification is what turns a red test into an actual decision.
- A field rename or type change should always fail a contract test, even if the new shape is objectively better — resolve the tension by versioning or a coordinated deprecation, not by loosening the test.


Comparing Postman MCP Output Between Gemini CLI and Claude Code

Running the same "generate contract tests from this spec + changelog" prompt through both clients on the same Orders API surfaced a few consistent differences worth knowing before you pick one for this task:

Context ingestion. Gemini CLI handled the full doc set (spec, changelog, and three markdown guides, roughly 40K tokens combined) in one pass without needing them chunked or summarized first. Claude Code handled the same set fine too, but needed the changelog pointed to explicitly in a follow-up turn when the initial prompt only named the spec file — a smaller practical difference than context-window numbers alone would suggest, but real.

Schema literalism. Claude Code's generated jsonSchema blocks tracked the OpenAPI spec's required and type fields more literally, including edge cases like nullable: true fields correctly rendered as type: ["string", "null"]. Gemini CLI's first pass on the same spec occasionally flattened a nullable field to just "string", missing the null case — worth a specific spot-check on any field the spec marks nullable, regardless of which client generated it.

Tool-call verbosity. Gemini CLI tends to narrate more of its intermediate MCP tool calls in the terminal output by default, which is genuinely useful for auditing what changed in a collection but adds noise if you just want the final result. Claude Code's default is terser, showing tool calls more compactly.

Deprecation-window reasoning. Both clients correctly reasoned about the changelog-only deprecation test once explicitly asked, but Claude Code got there from a shorter prompt on the same task — Gemini CLI's first attempt needed a follow-up clarifying that "still present" meant "present with a non-null value," not merely "present in the schema."

None of these differences are large enough to make one client categorically better at contract testing with Postman MCP — they're the kind of gaps you close with a slightly more explicit prompt either way. The practical takeaway: whichever client you standardize on, spot-check nullable fields in generated schemas by hand at least once, and decide up front how much intermediate tool-call narration you want in your terminal.

Tips
- Spot-check every nullable: true field in a generated JSON schema by hand regardless of client — this was the one systematic gap observed, and it's an easy one to automate a check for.
- If Gemini CLI's default tool-call narration is too noisy for your terminal workflow, ask it explicitly to summarize tool activity rather than streaming each call — most sessions don't need the full trace.
- Point either client at the changelog explicitly by filename in the initial prompt, not just the spec — deprecation and versioning context lives there, and neither client reliably goes looking for it unprompted.


Tips

Tips
- Use $VAR-style interpolation in settings.json and confirm the connection with /mcp before trusting a session's output.
- Lean on Gemini CLI's larger context window specifically for ingesting full doc sets (spec + changelog + guides) in one pass for contract-test generation.
- Default generated schemas to additionalProperties: true — contract tests should catch broken promises, not additive changes.
- Spot-check nullable fields and deprecation-window logic by hand once per collection, regardless of which client generated the tests.