<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anton Kirilchuk</title>
    <description>The latest articles on DEV Community by Anton Kirilchuk (@antonkirilchuk).</description>
    <link>https://dev.to/antonkirilchuk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3993909%2F5ba1990e-302d-495e-adc8-d381c9375d76.jpg</url>
      <title>DEV Community: Anton Kirilchuk</title>
      <link>https://dev.to/antonkirilchuk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/antonkirilchuk"/>
    <language>en</language>
    <item>
      <title>How I fuzz my API with one command using Schemathesis (and let Claude triage the bugs)</title>
      <dc:creator>Anton Kirilchuk</dc:creator>
      <pubDate>Sat, 27 Jun 2026 20:09:42 +0000</pubDate>
      <link>https://dev.to/antonkirilchuk/how-i-fuzz-my-api-with-one-command-using-schemathesis-and-let-claude-triage-the-bugs-1mfh</link>
      <guid>https://dev.to/antonkirilchuk/how-i-fuzz-my-api-with-one-command-using-schemathesis-and-let-claude-triage-the-bugs-1mfh</guid>
      <description>&lt;p&gt;Manual API tests check what you expect to happen. The bugs that take down production are the ones nobody thought to write a test for: an empty string where the code assumed a value, a negative number in a field that only ever saw positives, an emoji in a date.&lt;/p&gt;

&lt;p&gt;You can sit and brainstorm broken inputs by hand. You will write ten of them and get bored. The three-hundredth one, the one that actually crashes the server, you will never reach.&lt;/p&gt;

&lt;p&gt;Schemathesis writes those for you. You give it your OpenAPI schema, it generates thousands of requests on its own, and it hammers every endpoint looking for the ones that break. Here is how I run it, what it actually finds, and how I deal with the flood of results it produces.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Schemathesis actually is
&lt;/h2&gt;

&lt;p&gt;Schemathesis is a Python tool built on top of &lt;a href="https://hypothesis.readthedocs.io/" rel="noopener noreferrer"&gt;Hypothesis&lt;/a&gt;, the property-based testing library. Property-based means you do not write example inputs. You describe the shape of valid data, and the engine generates hundreds of cases that fit (and deliberately break) that shape.&lt;/p&gt;

&lt;p&gt;Your OpenAPI schema already describes that shape: every endpoint, every parameter, every type. Schemathesis reads it and turns it into a test generator. No assertions to maintain by hand. When the schema changes, the tests change with it.&lt;/p&gt;

&lt;p&gt;Install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;schemathesis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The first run
&lt;/h2&gt;

&lt;p&gt;One command, pointed at your schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;st run http://localhost:8000/openapi.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. It reads the schema, then fires thousands of requests at every endpoint: valid ones, and ones deliberately malformed. By default it runs in &lt;code&gt;all&lt;/code&gt; mode, mixing valid and invalid data. You can push it harder with negative-only generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;st run &lt;span class="nt"&gt;--mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;negative http://localhost:8000/openapi.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What it catches
&lt;/h2&gt;

&lt;p&gt;Out of the box, Schemathesis runs a set of checks against every response. Three of them find the bugs that matter most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The silent 2xx.&lt;/strong&gt; You send a malformed payload expecting a &lt;code&gt;400 Bad Request&lt;/code&gt;. Instead the server replies &lt;code&gt;200 OK&lt;/code&gt; and quietly accepts the garbage. The bad data either got saved to your database or vanished without a trace. Both are bugs, and neither shows up in a happy-path test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The unexpected 5xx.&lt;/strong&gt; Fuzzing string boundaries (huge Unicode strings, null bytes, integers at the edge of their range) drags raw stack traces and unhandled exceptions out of code that unit tests walk right past.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The contract violation.&lt;/strong&gt; The server returns a status code, or a response body, that its own OpenAPI schema never documented. The &lt;code&gt;status_code_conformance&lt;/code&gt; and &lt;code&gt;response_schema_conformance&lt;/code&gt; checks catch the gap between what the docs promise and what the API does.&lt;/p&gt;

&lt;p&gt;You can run a focused subset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;st run openapi.yaml &lt;span class="nt"&gt;--checks&lt;/span&gt; not_a_server_error,response_schema_conformance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reading a failure
&lt;/h2&gt;

&lt;p&gt;This is the part that makes Schemathesis worth it. Every failure comes with the exact &lt;code&gt;curl&lt;/code&gt; command to reproduce it. No guessing which of the thousand requests broke things.&lt;/p&gt;

&lt;p&gt;A real example from a booking API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Server error

- Undocumented HTTP status code

    Received: 500
    Documented: 200, 422

[500] Internal Server Error

Reproduce with:

    curl -X POST -H 'Content-Type: application/json' \
      -d '{"guest_name": "00", "nights": 1, "room_type": ""}' \
      http://127.0.0.1:8080/bookings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A guest name of &lt;code&gt;"00"&lt;/code&gt; and an empty &lt;code&gt;room_type&lt;/code&gt; crash &lt;code&gt;POST /bookings&lt;/code&gt; with a 500. Copy the command, paste it in a terminal, and the bug reproduces every time. Hand that line straight to the developer who owns the endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The noise problem
&lt;/h2&gt;

&lt;p&gt;Run Schemathesis for the first time and it will surface a hundred findings. Do not panic, and do not trust all of them.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;negative_data_rejection&lt;/code&gt; check is a known source of false positives. Schemathesis sends a malformed request (say, an empty query parameter) and expects a &lt;code&gt;4xx&lt;/code&gt;. But many frameworks, FastAPI among them, simply ignore the empty parameter and return &lt;code&gt;200 OK&lt;/code&gt;. Schemathesis flags that as a failure, even though nothing is actually broken.&lt;/p&gt;

&lt;p&gt;So the first pass is mostly triage: separate the real crashes from the protocol nitpicks. Doing that by hand across a hundred findings is an afternoon gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Letting Claude triage the flood
&lt;/h2&gt;

&lt;p&gt;This is where I plug in an AI layer. I take the full Schemathesis report and hand it to Claude with a simple instruction: group the findings, drop the false positives like the empty-parameter ones, and rank what is left by severity.&lt;/p&gt;

&lt;p&gt;It collapses the duplicates (one root cause often shows up in twenty different request shapes), strips the framework-level noise, and hands back a short list: these three are real server crashes, fix them first; the rest is the &lt;code&gt;negative_data_rejection&lt;/code&gt; pattern, safe to ignore.&lt;/p&gt;

&lt;p&gt;What was an afternoon of manual sorting becomes a couple of minutes. The machine generates the attacks, the AI clears the noise, and I am left fixing actual bugs instead of reading stack traces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring it into CI
&lt;/h2&gt;

&lt;p&gt;A fuzzer in CI is dangerous if you let it stay random. A pipeline that passes today and fails tomorrow, for no reason other than the generator stumbling onto a new case, trains everyone to ignore it.&lt;/p&gt;

&lt;p&gt;Fix the seed so runs are reproducible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvx schemathesis run &lt;span class="nt"&gt;--generation-deterministic&lt;/span&gt; http://localhost:8000/openapi.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;uvx&lt;/code&gt; runs it in an isolated, throwaway environment with no dependency setup, which is exactly what you want in CI. The deterministic flag means the same code gives the same result every time. Save the wild, fully-random run for a nightly cron job, where a new failure is a signal to investigate rather than a broken build.&lt;/p&gt;

&lt;p&gt;Schemathesis also emits JUnit XML, so the results drop straight into the dashboards your team already reads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it fits
&lt;/h2&gt;

&lt;p&gt;If you have used &lt;a href="https://github.com/apiaryio/dredd" rel="noopener noreferrer"&gt;Dredd&lt;/a&gt;, Schemathesis is the step past it. Dredd validates that your API matches the examples in your docs. It does not generate negative tests or fuzz. Schemathesis actively hunts for inputs that break things.&lt;/p&gt;

&lt;p&gt;Compared to writing assertions by hand in pytest or Postman, the trade is clear: those tools make you write and maintain every check. Schemathesis treats the OpenAPI spec as the single source of truth. Update the spec, and the test surface updates with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Manual tests cover the inputs you imagined. Schemathesis covers the ones you did not, generates a reproducible &lt;code&gt;curl&lt;/code&gt; for every bug it finds, and an AI pass turns the noisy output into a clean fix list. One command to find the holes, a deterministic seed to keep CI honest, and a nightly chaos run to keep looking.&lt;/p&gt;

&lt;p&gt;If you test APIs, point it at your schema once and see what falls out. The first run is usually uncomfortable, in a useful way.&lt;/p&gt;

&lt;p&gt;Drop your stack in the comments and I will tell you where to start.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>api</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Mock any API response in Postman (and let AI build the collection)</title>
      <dc:creator>Anton Kirilchuk</dc:creator>
      <pubDate>Sun, 21 Jun 2026 21:06:29 +0000</pubDate>
      <link>https://dev.to/antonkirilchuk/mock-any-api-response-in-postman-and-let-ai-build-the-collection-2le1</link>
      <guid>https://dev.to/antonkirilchuk/mock-any-api-response-in-postman-and-let-ai-build-the-collection-2le1</guid>
      <description>&lt;p&gt;The hardest part of frontend testing isn't writing the test. It's getting the backend to return the exact response you need: a 500, an empty list, a malformed payload, right when you want it. On a live server that's painful, and sometimes impossible.&lt;/p&gt;

&lt;p&gt;Here's the workflow I use instead. I make the app receive &lt;strong&gt;any&lt;/strong&gt; response I want, without touching the backend at all. Postman mock servers do the heavy lifting, and an AI fills them with data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: a fake backend that looks real
&lt;/h2&gt;

&lt;p&gt;Your frontend doesn't know where the JSON comes from. It calls a URL and trusts whatever comes back. So you point it at a &lt;strong&gt;mock server&lt;/strong&gt;: a fake address that returns responses you defined in advance. Same endpoints, same shapes, zero real backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just DevTools or a proxy?
&lt;/h2&gt;

&lt;p&gt;For a quick one-off, browser tools are fine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chrome DevTools, Local Overrides&lt;/strong&gt; rewrite a response right in the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Charles / Requestly / mitmproxy&lt;/strong&gt; intercept and swap responses on the fly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the override dies when you close the tab, it lives only on your machine, and you can't hand it to a teammate or a CI pipeline. For anything beyond a single check, you want a real, persistent stand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: build the collection
&lt;/h2&gt;

&lt;p&gt;In Postman you already (or soon will) have a collection: the same endpoints your real API exposes, with method, URL, body and headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: add example responses
&lt;/h2&gt;

&lt;p&gt;For each request, hit the three dots and pick &lt;strong&gt;Add example&lt;/strong&gt;. An example is a saved response: a status code plus a body. You write it by hand.&lt;/p&gt;

&lt;p&gt;Hang several examples on the same endpoint to cover every case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;200&lt;/code&gt; success&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;404&lt;/code&gt; not found&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[]&lt;/code&gt; empty list&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;500&lt;/code&gt; server error&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: spin up the mock server
&lt;/h2&gt;

&lt;p&gt;Three dots on the collection, then &lt;strong&gt;Mock collection&lt;/strong&gt;. Postman gives you an address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://xxxx.mock.pstmn.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: point the frontend at it
&lt;/h2&gt;

&lt;p&gt;Swap the base URL in your app config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- const API = "https://api.production.com"
&lt;/span&gt;&lt;span class="gi"&gt;+ const API = "https://xxxx.mock.pstmn.io"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Your frontend now talks to the mock and never notices the difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  One endpoint, every scenario
&lt;/h2&gt;

&lt;p&gt;Here's where it gets good. You hung 200, 404 and 500 on the same endpoint. Which one does the mock return? It decides by a request header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;x-mock-response-name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;order not found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send that header from your automated test, and a &lt;strong&gt;single endpoint&lt;/strong&gt; runs through every scenario without touching the server or the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/orders/42`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-mock-response-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// the mock returns your 500 example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Responses don't have to be static
&lt;/h2&gt;

&lt;p&gt;Postman supports dynamic variables right inside the example body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{$randomInt}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{$randomFullName}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{$randomEmail}}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every call comes back with different data instead of one hardcoded blob, so you catch the bugs that only surface on unexpected input.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that saves the most time
&lt;/h2&gt;

&lt;p&gt;Writing dozens of example responses by hand is the boring tax on all of this. So I don't.&lt;/p&gt;

&lt;p&gt;I hand the whole collection to &lt;strong&gt;Claude through the Postman MCP&lt;/strong&gt;, and it generates the example responses for every endpoint (success, edge cases, malformed payloads) and wires up the mock. I'm not asking it to write code. I'm asking it to assemble a working test stand while I drink my coffee.&lt;/p&gt;

&lt;p&gt;That's the shift: AI stopped being "write me this function" and became "build me the tool".&lt;/p&gt;




&lt;p&gt;How do you handle this on your team: Postman mocks, a standalone mock service, or still waiting on the backend?&lt;/p&gt;

</description>
      <category>postman</category>
      <category>testing</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>How I stopped building Postman collections by hand (Claude + Postman MCP)</title>
      <dc:creator>Anton Kirilchuk</dc:creator>
      <pubDate>Sat, 20 Jun 2026 10:30:43 +0000</pubDate>
      <link>https://dev.to/antonkirilchuk/how-i-stopped-building-postman-collections-by-hand-claude-postman-mcp-41f9</link>
      <guid>https://dev.to/antonkirilchuk/how-i-stopped-building-postman-collections-by-hand-claude-postman-mcp-41f9</guid>
      <description>&lt;p&gt;If you test backend services, you know the &lt;br&gt;
 ritual. A new service shows up, you need to poke its endpoints, so you open Postman and start building a collection request by request. Method, URL, headers, auth, request body, fix the folder structure, name everything so future-you can read it. On a service with a few dozen endpoints, that's an hour or two gone before you send a single request.&lt;/p&gt;

&lt;p&gt;I haven't done that in months.&lt;/p&gt;

&lt;p&gt;Now I hand the API definition to Claude, and it builds the whole collection through the Postman MCP server in a few seconds - laid out as a step-by-step runbook, with values already filled in. I just hit Send and read the responses. This post is how I set it up and how I actually use it day to day.&lt;/p&gt;
&lt;h2&gt;
  
  
  The usual way, and why it's a waste
&lt;/h2&gt;

&lt;p&gt;The information about an API lives in different places depending on the team. Sometimes it's a clean Swagger / OpenAPI page. Sometimes it's a description in a Jira ticket. Sometimes a Confluence page, or just a message from the developer who wrote the endpoint. Wherever it lives, the manual move is the same: read it, then re-type each endpoint into Postman.&lt;/p&gt;

&lt;p&gt;It's not hard work. It's just slow, repetitive, and easy to get subtly wrong - a missing header here, a wrong content type there. And none of it is actually testing. It's setup that stands between you and the part of the job that matters.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;p&gt;Three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Postman account and an API key&lt;/li&gt;
&lt;li&gt;Claude (Claude Code or the desktop app) with the Postman MCP server connected&lt;/li&gt;
&lt;li&gt;The API definition - from wherever it lives&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  1. Get your Postman API key
&lt;/h3&gt;

&lt;p&gt;In Postman: &lt;strong&gt;Settings -&amp;gt; API keys -&amp;gt; Generate API Key&lt;/strong&gt;. Copy it somewhere safe - you'll pass it to the MCP server, not paste it into chats.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Connect the Postman MCP server to Claude
&lt;/h3&gt;

&lt;p&gt;MCP (Model Context Protocol) lets Claude talk directly to Postman instead of you copy-pasting back and forth. Add the server to your &lt;code&gt;.mcp.json&lt;/code&gt; (project root, or &lt;code&gt;~/.claude/mcp.json&lt;/code&gt; for global):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"postman"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@postman/postman-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--full"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"POSTMAN_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${POSTMAN_API_KEY}"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;POSTMAN_API_KEY&lt;/code&gt; in your environment, restart Claude, and run &lt;code&gt;/mcp&lt;/code&gt; to confirm it connected. Now Claude can create and edit collections in your workspace on its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Point it at the API
&lt;/h3&gt;

&lt;p&gt;If you have Swagger, even better - Spring services expose the full method library as OpenAPI at &lt;code&gt;/v3/api-docs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://your-service/v3/api-docs &lt;span class="nt"&gt;-o&lt;/span&gt; api.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the source doesn't have to be Swagger. Paste the Jira ticket text, the Confluence export, or the endpoint description straight into Claude. It pulls the endpoints out either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it actually works
&lt;/h2&gt;

&lt;p&gt;Here's the part I like. I don't just get a flat dump of requests - I ask Claude to build the collection as a &lt;strong&gt;runbook&lt;/strong&gt;, where the order of the requests is the order I run the test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;request names are steps: &lt;code&gt;1) create threshold&lt;/code&gt;, &lt;code&gt;2) get by id&lt;/code&gt;, &lt;code&gt;3) update&lt;/code&gt;, &lt;code&gt;4) delete and verify&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;top to bottom is the test sequence&lt;/li&gt;
&lt;li&gt;every value (host, ids, request bodies) is hardcoded right into the request - no &lt;code&gt;{{variables}}&lt;/code&gt; to fill in by hand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then testing looks like this: I open the collection and press Send, top to bottom. When a request creates something and returns a new id, Claude reads it from the response and patches it into the next requests through the Postman API. I keep pressing Send.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick example
&lt;/h2&gt;

&lt;p&gt;Say I give Claude an endpoint spec like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/threshold - create a detection threshold for a resource
GET /api/threshold/{id} - read it back
PUT /api/threshold/{id} - update it
DELETE /api/threshold/{id}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ask: &lt;em&gt;"Build a Postman collection in my workspace as a step-by-step runbook to create a threshold, read it, update it, and delete it. Hardcode the values, name each request as a numbered step."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A few seconds later there's a collection with four ordered requests, bodies filled in, auth set at the collection level. I run them in order. After step 1 returns the new threshold id, the GET/PUT/DELETE steps already point at it. I read each response and decide whether the service behaved correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this helps, and where it doesn't
&lt;/h2&gt;

&lt;p&gt;The setup work mostly disappears. The thinking doesn't, and that's the point.&lt;/p&gt;

&lt;p&gt;AI is good at: turning a spec into a structured collection, naming and ordering requests, filling in boilerplate, patching ids between steps.&lt;/p&gt;

&lt;p&gt;AI does &lt;strong&gt;not&lt;/strong&gt; do the actual QA: deciding which scenarios matter, what the edge cases are, whether a &lt;code&gt;201&lt;/code&gt; actually means the business logic is correct, reading logs to find why something failed. A green response is not a passing test - that judgment is still mine.&lt;/p&gt;

&lt;p&gt;So this isn't "AI tests for me". It's "AI clears the busywork so I spend my time on the part that needs a tester".&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If you do REST API testing and haven't tried Claude + Postman MCP yet, it's worth half an hour to set up. The first time a collection you'd have spent an hour building shows up ready in seconds, it clicks.&lt;/p&gt;

&lt;p&gt;I wrote up my full setup, prompt templates, and honest notes on where AI breaks down here: &lt;a href="https://github.com/anton-kirilchuk/ai-assisted-qa-mcp" rel="noopener noreferrer"&gt;github.com/anton-kirilchuk/ai-assisted-qa-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I post more about backend QA and AI-augmented testing on &lt;a href="https://www.linkedin.com/in/anton-kirilchuk/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; - happy to compare notes.&lt;/p&gt;

&lt;p&gt;How much of your testing time still goes to setup before the real testing starts?&lt;/p&gt;

</description>
      <category>api</category>
      <category>automation</category>
      <category>claude</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
