mcp-postman-runner
Run the requests in a Postman collection folder — and get structured, assertion-level results back — straight from your AI assistant.
A Model Context Protocol (MCP) server that executes a folder of a Postman collection: it resolves {{variables}}, runs the collection + item pre-request scripts (so token-auth patterns work), previews or fires each request, supports read and write-method payloads, and evaluates embedded pm.test scripts — then returns status, timing, request diagnostics, response metadata, body, and per-assertion pass/fail.
It replicates only the slice of newman needed for agent-driven API testing, with no runtime dependencies beyond the MCP SDK and zod.
🎯 Why use this
The Postman connector/API can create requests but can't run them. This server is the execution engine in a Jira → Postman → assess → comment workflow:
Jira ticket ─► derive test cases ─► create a Postman folder (named = ticket key) with pm.test scripts
─► run_folder (this MCP) ─► assess responses ─► comment results on the ticket
Supported AI assistants
Any MCP client — Claude Desktop, Claude Cowork, GitHub Copilot (VS Code), Cursor, Windsurf, etc.
✨ Features
- Folder execution — run every request in a folder, in order, sharing variables across the run.
- Preflight previews — inspect resolved URLs, methods, redacted headers, body mode/preview,
write-request count, and safety warnings before sending any HTTP traffic.
- Auth that just works — collection/item pre-request scripts run (incl.
pm.sendRequest), so a token fetched once flows to the rest of the folder. - Write-method payload support — execute POST/PUT/PATCH/DELETE tests with raw, JSON,
urlencoded, form-data, and GraphQL body modes.
- Safety gates — production-like targets and write methods are blocked unless the caller passes
explicit approval flags for that run.
- Assertion evaluation — the embedded
pm.testscripts run via a minimalpm/expectsandbox; you get deterministic pass/fail per assertion. - Structured output — status, time, redacted request diagnostics, response body metadata,
truncated response body, and assertion details for each request, ready for an agent to assess.
- Credential-less — holds no secrets; the caller passes the collection/environment JSON.
- Zero runtime deps — only
@modelcontextprotocol/sdkandzod.
📋 Prerequisites
- Node.js >= 18 (uses the global
fetch). - Network access from wherever this runs to the API under test.
- A Postman collection (and optional environment) JSON — typically fetched via the Postman API/connector.
🚀 Quick start
Add to your MCP client config:
{
"mcpServers": {
"postman-runner": {
"command": "npx",
"args": ["-y", "mcp-postman-runner@latest"]
}
}
}
npx fetches and caches the package on first launch. CLI help: npx -y mcp-postman-runner@latest --help.
🛠️ Tools
| Tool | Purpose | Key arguments | | --- | --- | --- | | list_folders | List folders in a collection (name, id, path, request count) | collection | | preview_requests | Resolve a folder/request without HTTP execution; return redacted targets, bodies, safety warnings, and write counts | collection, folderName?/folderId?, requestName?, environment?, allowProduction?, allowWrites?, approvalNote? | | run_folder | Run every request in a folder; return results + assertions | collection, folderName (e.g. the Jira ticket key) or folderId, environment?, timeoutRequestMs?, allowProduction?, allowWrites?, approvalNote? | | run_request | Run a single named request (re-run one case) | collection, requestName, folderName?/folderId?, environment?, allowProduction?, allowWrites?, approvalNote? |
All tools take the collection JSON (the collection object from the Postman API / connector's getCollection), and optionally an environment JSON.
Safety-first workflow
- Fetch the collection and environment JSON from Postman.
- Use
list_foldersto choose the exact folder. - Use
preview_requeststo inspect resolved URLs, HTTP methods, redacted auth, body previews,
writeRequests, and safety warnings.
- If the target is production-like, get explicit approval for the exact base URL, auth source,
scope/tenant, HTTP methods, and data sensitivity, then pass allowProduction: true with an approvalNote.
- If the folder contains POST/PUT/PATCH/DELETE requests, confirm the environment is safe for
mutation, then pass allowWrites: true with an approvalNote.
- Call
run_folderorrun_requestonly after the preview is approved.
By default, the runner blocks production-like targets and write methods. This is deliberate: GET/read-only requests can expose real data, and write-method requests can mutate state.
preview_requests result
{
"summary": {
"totalRequests": 3,
"methodCounts": { "GET": 1, "POST": 1, "PUT": 1 },
"writeRequests": 2,
"warnings": 0
},
"safety": {
"blocked": true,
"productionLikeTargets": ["https://api.example.com/v1/orders"],
"writeMethods": ["POST", "PUT"],
"warnings": [
"production-like target detected; pass allowProduction with an approval note to execute",
"write methods detected; pass allowWrites after confirming the target is safe for mutation"
],
"approvalNote": null
},
"requests": [
{
"name": "TC-02 create order",
"method": "POST",
"url": "https://api-dev.example.net/v1/orders?api_key=%3Credacted%3E",
"headers": { "Authorization": "<redacted>", "Content-Type": "application/json" },
"body": {
"mode": "raw",
"sent": true,
"contentType": "application/json",
"bytes": 42,
"preview": "{\"name\":\"Demo\",\"password\":\"<redacted>\"}",
"previewTruncated": false
},
"warnings": []
}
]
}
run_folder / run_request result
{
"summary": {
"totalRequests": 9,
"requestsErrored": 0,
"assertionsTotal": 24,
"assertionsFailed": 4,
"anyFailure": true,
"durationMs": 1420,
"methodCounts": { "GET": 7, "POST": 1, "PUT": 1 },
"statusCounts": { "200": 7, "400": 2 },
"bytesReceived": 21860
},
"results": [
{
"name": "TC-01 Happy path", "method": "GET",
"url": "https://api-dev.example.net/api/v2/countries/states/cities",
"request": {
"method": "GET",
"url": "https://api-dev.example.net/api/v2/countries/states/cities",
"headers": { "Authorization": "<redacted>" },
"body": { "mode": null, "sent": false, "contentType": null, "bytes": null, "preview": null, "previewTruncated": false }
},
"status": 200, "statusText": "OK", "timeMs": 142,
"assertionsPassed": 3, "assertionsFailed": 0,
"assertions": [ { "name": "status is 200", "passed": true, "error": null } ],
"response": { "contentType": "application/json", "bytes": 2186, "bodyTruncated": false },
"responseBody": "{ ... }", // truncated at 20k chars
"warnings": []
}
]
}
Write-method payload support
The runner supports the common Postman body modes used for POST/PUT/PATCH/DELETE tests:
| Postman body mode | Runner behavior | | --- | --- | | raw | Resolves variables and sends the raw string. If Postman marks it as JSON, or the body parses as JSON, Content-Type: application/json is inferred when missing. | | urlencoded | Sends application/x-www-form-urlencoded and skips disabled params. | | formdata | Sends FormData fields and skips disabled fields. File fields are represented as string placeholders and returned as warnings; local file loading is intentionally not performed. | | graphql | Sends { query, variables } as JSON and reports invalid variables JSON as a warning. | | file / unsupported modes | Request preview/result includes a warning; local file body upload is not implemented. |
Bodies are sent only for methods where HTTP payloads make sense. If a body is defined on GET or HEAD, the runner omits it and records a warning.
🔬 How it works
- Variables — merges collection variables + environment values; resolves
{{var}}(nested, iteratively). - Request build — builds resolved URL, headers, method, body, redacted diagnostics, and safety warnings.
- Preview or execute —
preview_requestsstops after request build;run_folder/run_requestcontinue only if safety gates pass. - Auth / pre-request — execution runs collection-level then item-level pre-request scripts.
pm.sendRequestis supported, so the common "POST the auth URL, store the token, reuse it" pattern works; the token is cached in the run's variables. - Request — fires with
fetch(per-request timeout), including supported write-method bodies. - Assertions — runs the request's
testscript through apm/expectsandbox and records eachpm.testresult.
Supported pm subset
pm.test, pm.expect (eql/equal/deep, true/false/null, have.property, at.most/least, above/below, within, include, oneOf, a/an, match, empty, negation via .not), pm.response.code/.json()/.text(), pm.environment & pm.variables get/set, and pm.sendRequest. See ARCHITECTURE.md for details.
🔌 Platform integration
Claude Desktop
Add the server to claude_desktop_config.json:
{
"mcpServers": {
"postman-runner": {
"command": "npx",
"args": ["-y", "mcp-postman-runner@latest"]
}
}
}
Restart Claude Desktop. A safe prompt pattern is: fetch the Postman collection/environment, call preview_requests, show the safety summary, and only run the folder after you approve the target.
GitHub Copilot in VS Code
Register the same npx -y mcp-postman-runner@latest command in your VS Code MCP/tool setup. A useful Jira-driven flow is:
- Fetch the Jira ticket and endpoint contract.
- Use a Postman connector to fetch
getCollection(model: "full")andgetEnvironment(...). - Call
list_foldersand choose the ticket folder. - Call
preview_requestsand inspectsafety, resolved target URLs, and write-method payloads. - Call
run_folderwithallowProduction/allowWritesonly when explicitly approved. - Ask Copilot to classify results into PASS / FAIL / WARNING / NEEDS-DATA / BLOCKED.
Cursor and Windsurf
Configure an MCP server named postman-runner with:
{
"command": "npx",
"args": ["-y", "mcp-postman-runner@latest"]
}
Then provide the agent with collection/environment JSON from a Postman connector, the Postman API, or sanitized fixtures. This MCP does not authenticate to Postman; it only runs the JSON you pass in.
Postman connector / API workflow
Use this server alongside a Postman connector:
getCollection(model: "full")→ pass the returnedcollectionobject here.getEnvironment(...)→ pass the returnedenvironmentobject when variables/auth are needed.preview_requests({ collection, environment, folderName })→ inspect resolved requests and safety gates.run_folder({ collection, environment, folderName, allowWrites, allowProduction, approvalNote })→ execute after approval.
For Jira-driven testing, name the Postman folder after the ticket key so runner results map cleanly back to test-case IDs and ticket comments.
🔒 Security
Credential-less by design; secrets in the passed environment are kept in memory for one run and never logged. Returned diagnostics redact sensitive-looking headers, query parameters, and JSON/form body keys. Only run collections you trust — their pre-request/pm.test scripts execute in the server process. See SECURITY.md.
Before running against production or production-like targets, use preview_requests and get explicit approval for the exact base URL, auth source, scope, methods, and data sensitivity. GET requests can still expose real data; write methods can mutate state.
🤝 Contributing
See CONTRIBUTING.md. Uses Conventional Commits + semantic-release.
📜 License
🔗 Links
- Issues: <https://github.com/tezaswiraj7222/mcp-postman-runner/issues>
- MCP: <https://modelcontextprotocol.io>






