{
  "markdown": "<p align=\"center\">\n  <h1 align=\"center\">@cocaxcode/api-testing-mcp</h1>\n  <p align=\"center\">\n    <strong>The most complete MCP server for API testing. Period.</strong><br/>\n    42 MCP tools &middot; Zero config &middot; Works in any MCP client\n  </p>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@cocaxcode/api-testing-mcp\"><img src=\"https://img.shields.io/npm/v/@cocaxcode/api-testing-mcp.svg?style=flat-square&color=cb3837\" alt=\"npm version\" /></a>\n  <a href=\"https://www.npmjs.com/package/@cocaxcode/api-testing-mcp\"><img src=\"https://img.shields.io/npm/dm/@cocaxcode/api-testing-mcp.svg?style=flat-square\" alt=\"npm downloads\" /></a>\n  <img src=\"https://img.shields.io/badge/tools-42-blueviolet?style=flat-square\" alt=\"42 tools\" />\n  <img src=\"https://img.shields.io/badge/tests-171-brightgreen?style=flat-square\" alt=\"171 tests\" />\n  <img src=\"https://img.shields.io/badge/node-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white\" alt=\"Node\" />\n  <a href=\"https://opensource.org/licenses/MIT\"><img src=\"https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square\" alt=\"License\" /></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"#quick-overview\">Overview</a> &middot;\n  <a href=\"#just-talk-to-it\">Just Talk to It</a> &middot;\n  <a href=\"#installation\">Installation</a> &middot;\n  <a href=\"#features\">Features</a> &middot;\n  <a href=\"#tool-reference\">Tool Reference</a> &middot;\n  <a href=\"#storage\">Storage</a> &middot;\n  <a href=\"#architecture\">Architecture</a>\n</p>\n\n---\n\n## Quick Overview\n\nThe most complete [MCP server](https://modelcontextprotocol.io) for API testing — 42 tools, zero config, nothing else comes close. This is not just a request sender. It is a full testing workbench: HTTP requests with assertions, multi-step flows with variable extraction, OpenAPI import with schema-aware mock data, load testing with percentile metrics, response diffing across environments, bulk test runners, reusable collections, environment groups with directory scoping and persistent defaults, Postman import/export, and cURL export. All from natural conversation. No accounts, no cloud, no generated files. Everything runs inline and stores as plain JSON you own.\n\n---\n\n## Just Talk to It\n\nYou don't need to learn tool names or parameters. Describe what you want and the AI picks the right tool.\n\n```\n\"Create a group called my-project and add this directory as scope\"\n\"Set up a dev environment with BASE_URL http://localhost:3000\"\n\"Switch to prod for this session\"\n\"Set dev as the default environment\"\n\"Import my API spec from /api-docs-json\"\n\"Show me all user endpoints\"\n\"GET /users\"\n\"Create a user with random data\"\n\"Verify that DELETE /users/5 returns 204\"\n\"Login as admin, extract the token, then fetch dashboard stats\"\n\"How fast is /health with 50 concurrent requests?\"\n\"Run all my saved smoke tests\"\n\"Compare the users endpoint between dev and prod\"\n\"Export the create-user request as curl\"\n\"Export my collection to Postman\"\n```\n\nIf you've imported an OpenAPI spec, the AI already knows every endpoint, every required field, every valid enum value. When you say \"create a blog post\", it reads the schema and builds the request correctly — no guessing.\n\n---\n\n## Installation\n\n### Claude Code\n\n```bash\nclaude mcp add --scope user api-testing -- npx -y @cocaxcode/api-testing-mcp@latest\n```\n\n### Claude Desktop\n\nAdd to your config file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\\Claude\\claude_desktop_config.json` on Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"api-testing\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@cocaxcode/api-testing-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Cursor / Windsurf\n\nAdd to `.cursor/mcp.json` or `.windsurf/mcp.json` in your project root:\n\n```json\n{\n  \"mcpServers\": {\n    \"api-testing\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@cocaxcode/api-testing-mcp@latest\"]\n    }\n  }\n}\n```\n\n<details>\n<summary>VS Code / Codex CLI / Gemini CLI</summary>\n\n**VS Code** — add to `.vscode/mcp.json`:\n\n```json\n{\n  \"servers\": {\n    \"api-testing\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@cocaxcode/api-testing-mcp@latest\"]\n    }\n  }\n}\n```\n\n**Codex CLI (OpenAI)**:\n\n```bash\ncodex mcp add api-testing -- npx -y @cocaxcode/api-testing-mcp@latest\n```\n\nOr add to `~/.codex/config.toml`:\n\n```toml\n[mcp_servers.api-testing]\ncommand = \"npx\"\nargs = [\"-y\", \"@cocaxcode/api-testing-mcp@latest\"]\n```\n\n**Gemini CLI** — add to `~/.gemini/settings.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"api-testing\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@cocaxcode/api-testing-mcp@latest\"]\n    }\n  }\n}\n```\n\n</details>\n\n### Quick Start\n\nOnce installed, set up an environment so relative paths resolve automatically:\n\n```\n\"Create an environment called dev with BASE_URL http://localhost:3000\"\n```\n\nIf your API has a Swagger/OpenAPI spec, import it:\n\n```\n\"Import my API spec from http://localhost:3000/api-docs-json\"\n```\n\nVerify with: *\"List my environments\"* — you should see the one you just created.\n\n---\n\n## Features\n\n### HTTP Requests\n\nSend any HTTP method with headers, query params, JSON body, auth, and `{{variable}}` interpolation. Relative URLs auto-resolve against `BASE_URL`.\n\n```\n\"POST to /api/users with name Jane and email jane@company.com using my bearer token\"\n```\n\nSupports: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS — Bearer / API Key / Basic auth — custom timeouts.\n\n### Compression modes (v0.13+)\n\nAI agents pay for every byte that lands in their context window. By default, `request` now returns a compressed response that cuts 70-95% of those tokens without losing debugging value. Three optional parameters control it:\n\n| Param | Values | What it does |\n|---|---|---|\n| `verbosity` | `'minimal'` / `'normal'` (default) / `'full'` | Controls detail level |\n| `only_fields` | `['user.id', 'items[*].name']` | Returns only these body paths (dot-notation + wildcards) |\n| `max_body_bytes` | number (default `2048`) | Body size cap for `'normal'` |\n\n**Modes:**\n\n- **`minimal`** — only `status`, `timing`, `size_bytes`, first 200 chars of body. Perfect for health checks, polling loops, or fire-and-forget calls. *Saves ~95% tokens.*\n- **`normal`** *(default)* — filtered headers (drops `Date`, `Server`, `CF-*`, `Set-Cookie`, etc.) + body truncated to `max_body_bytes`. Covers ~80% of debugging use cases. *Saves ~75% tokens.*\n- **`full`** — complete response untouched. Use when you explicitly need every header or the full body.\n\n**Typical savings on a 5 KB JSON response** (≈1,500 tokens):\n\n| Mode | Tokens consumed | Savings |\n|---|---|---|\n| `full` | ~1,500 | 0% (baseline) |\n| `normal` | ~300-400 | ~75% |\n| `minimal` | ~50-80 | ~95% |\n| `only_fields: ['data.id']` | ~30 | ~98% |\n\n> For a head-to-head comparison against `curl`, `WebFetch` and other native alternatives with measured numbers, see [Native alternatives](#native-alternatives-real-token-cost) below.\n\n**Recovering full responses:** every compressed response includes a `call_id`. If you need the full body later, call `inspect_last_response({ call_id })` — no need to re-execute the request. This works for `request`, `assert`, and each step of `flow_run`. Responses are kept in a 20-slot ring buffer and persisted to `.api-testing/last-responses/` with a 1-hour TTL.\n\n```json\n// Example: normal (default) response\n{\n  \"call_id\": \"k3m9a2xp\",\n  \"status\": 200,\n  \"statusText\": \"OK\",\n  \"method\": \"GET\",\n  \"url\": \"https://api.example.com/users/1\",\n  \"timing\": { \"total_ms\": 142 },\n  \"size_bytes\": 5324,\n  \"headers\": { \"content-type\": \"application/json\" },\n  \"body\": { \"id\": 1, \"email\": \"...\", \"...\": \"...\" },\n  \"body_truncated\": true,\n  \"hint\": \"Body truncated to 2048 bytes (full size: 5324B). Call inspect_last_response({ call_id: \\\"k3m9a2xp\\\" }) for the full body.\",\n  \"tokens_saved_estimate\": 820\n}\n```\n\n### Native alternatives: real token cost\n\nHow this MCP compares against the native options Claude Code has when `api-testing` is not available (Bash + curl, WebFetch, etc.).\n\n**TL;DR**: compared to raw `curl`, `request` saves between **65% and 97%** of context tokens depending on the mode, with no loss of debugging information. Measured on a real call to `GET /api/v1/blog` returning 8 posts (~8.7 KB of JSON, 19 response headers):\n\n| How the agent calls it | Uses MCP? | Tokens consumed | Delta vs curl |\n|---|:-:|---|---|\n| `Bash` + `curl` (raw stdout) | ❌ native | ~2,170 | baseline |\n| `WebFetch` (LLM summary) | ❌ native | ~400-800 | −65%, but no auth / no envs / no inspect |\n| `request` verbosity=`full` | ✅ MCP | ~2,170 | 0% (same as curl, no compression) |\n| **`request` verbosity=`normal`** *(default)* | ✅ MCP | **~750** | **−65%** |\n| `request` verbosity=`minimal` | ✅ MCP | ~50 | **−97%** |\n| `request` with `only_fields: [\"data[*].id\",\"data[*].title\"]` | ✅ MCP | ~190 | **−91%** |\n\n> Why this table's numbers differ slightly from the \"Compression modes\" section above: these come from a single real-world response, while the previous table shows typical savings on a synthetic 5 KB response. Trend and order of magnitude are the same.\n\nNotes:\n\n- The default mode (`normal`) already saves 65% without any configuration: it filters out noisy headers (Date, Server, CF-*, Set-Cookie…) and caps the body at 2048 bytes.\n- `only_fields` accepts dot-paths with array index and wildcard support (`items[*].name`) — returns only the fields you ask for.\n- The MCP also adds features that have no direct native equivalent: `{{variable}}` interpolation, stored environments, auth schemas, flows, Postman import/export, and `inspect_last_response` to recover the full body without re-hitting the server.\n- Every registered MCP adds a fixed overhead of ~300-600 tokens per session (its instructions block + tool names). Typical break-even: 1-2 real calls per session.\n\n### Assertions\n\nValidate responses with structured pass/fail results:\n\n```\n\"Verify that GET /api/health returns 200, body.status is ok, and responds in under 500ms\"\n```\n\n```\nPASS — 3/3 assertions passed\n  status === 200\n  body.status === \"ok\"\n  timing.total_ms < 500\n```\n\n10 operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `contains`, `not_contains`, `exists`, `type`\n\n### Request Flows\n\nChain requests with variable extraction between steps. Perfect for auth flows and CRUD sequences.\n\n```\n\"Login as admin@test.com, extract the access token, then use it to fetch all users\"\n```\n\n<details>\n<summary>What the tool executes</summary>\n\n```\nflow_run({\n  steps: [\n    {\n      name: \"login\",\n      method: \"POST\",\n      url: \"/auth/login\",\n      body: { email: \"admin@test.com\", password: \"SecurePass#99\" },\n      extract: { \"TOKEN\": \"body.access_token\" }\n    },\n    {\n      name: \"get-users\",\n      method: \"GET\",\n      url: \"/api/users\",\n      headers: { \"Authorization\": \"Bearer {{TOKEN}}\" }\n    }\n  ]\n})\n```\n\n</details>\n\n### OpenAPI Import\n\nImport specs from a URL or local file (JSON and YAML). Once imported, the AI knows every endpoint, parameter, and schema.\n\n```\n\"Import my API spec from http://localhost:3000/api-docs-json\"\n\"Import the spec from ./openapi.yaml\"\n\"What parameters does POST /users expect?\"\n```\n\nSupports OpenAPI 3.x with full `$ref` resolution, `allOf`, `oneOf`, `anyOf`. OpenAPI 2.0 partially supported.\n\n### Mock Data Generation\n\nGenerate realistic fake data from your OpenAPI schemas. Respects types, formats (`email`, `uuid`, `date-time`), enums, and required fields.\n\n```\n\"Generate mock data for creating a user\"\n```\n\n```json\n{\n  \"email\": \"user42@example.com\",\n  \"name\": \"Test User 73\",\n  \"password\": \"TestPass123!\",\n  \"role\": \"admin\"\n}\n```\n\n### Load Testing\n\nFire N concurrent requests and get performance metrics:\n\n```\n\"How fast is the health endpoint with 50 concurrent requests?\"\n```\n\n```\nLOAD TEST — GET /api/health\nRequests:    50 concurrent\nSuccessful:  50 | Failed: 0\nReq/sec:     23.31\n\n  Min: 45ms | Avg: 187ms\n  p50: 156ms | p95: 412ms | p99: 523ms\n  Max: 567ms\n```\n\n### Response Diffing\n\nExecute two requests and compare their responses field by field. Detect regressions or compare environments.\n\n```\n\"Compare the users endpoint between dev and prod\"\n```\n\n### Bulk Testing\n\nRun every saved request in a collection (or filter by tag) and get a summary:\n\n```\n\"Run all my saved smoke tests\"\n```\n\n```\nBULK TEST — 8/8 passed | 1.2s total\n  health       — GET  /health      → 200 (45ms)\n  list-users   — GET  /users       → 200 (123ms)\n  create-post  — POST /blog        → 201 (89ms)\n  login        — POST /auth/login  → 200 (156ms)\n```\n\n### Collections\n\nSave requests for reuse with tags. Build regression suites.\n\n```\n\"Save this request as create-user with tags auth, smoke\"\n\"List all requests tagged smoke\"\n```\n\n### Environments\n\nEnvironments hold your variables — `BASE_URL`, tokens, API keys — and keep them separated by context. The system has three core concepts:\n\n**Group.** A group organizes environments and binds them to directories. A group has N scopes (directories) that share its environments, and exactly one default environment. When you create an environment inside a group, it belongs to that group. When you `cd` into a directory that is a scope of a group, its environments become available automatically.\n\n**Default.** The default environment activates automatically when you enter a scope of its group. It persists between sessions — restart your editor, reopen your terminal, and the default is still there. Set it once and forget about it.\n\n**Active.** The active environment is what is being used right now for variable resolution. It starts as the default when you enter a scope, but you can switch it at any time. The active selection is session-only — it resets to the default on restart.\n\nGlobal environments (not associated with any group) still exist. They require explicit activation with `env_switch` and do not persist between sessions.\n\n**Practical example:**\n\n```\n\"Create a group called my-api\"\n\"Add this directory as scope to my-api\"\n\"Create a dev environment with BASE_URL http://localhost:3000\"   <- auto-joins group, auto-default\n\"Create a prod environment with BASE_URL https://api.example.com\"\n\"List environments\"                                              <- shows dev (active, default) and prod\n\"Switch to prod\"                                                 <- session only\n\"Set prod as default\"                                            <- persists\n```\n\n**Automatic interpolation.** Any `{{variable}}` in URLs, headers, query params, or request bodies is resolved against the active environment before the request fires. Set `BASE_URL` once and every relative path just works.\n\n**Your credentials never leave your machine.** Environment files are plain JSON stored in `~/.api-testing/`. Nothing syncs to any cloud. Nothing gets embedded in exports. Nothing gets tracked by git. Your tokens and secrets stay exactly where they should: on your disk, under your control.\n\n### Postman Import & Export\n\nBidirectional Postman support. Migrate seamlessly between Postman and your AI workflow.\n\n```\n\"Import my Postman collection from ./exported.postman_collection.json\"\n\"Export my collection to Postman\"\n\"Export the dev environment for Postman\"\n```\n\n<details>\n<summary>Import details</summary>\n\n**Collection:** Postman v2.1 format. Folders become tags. Auth inherited from folders/collection level. Supports raw JSON, x-www-form-urlencoded, form-data bodies.\n\n**Environment:** Prefers `currentValue` over `value`. Skips disabled variables. Optional `activate` flag.\n\n</details>\n\n<details>\n<summary>Export details</summary>\n\n**Collection:** Requests grouped in folders by tag. Auth mapped to Postman's native format. `{{variables}}` preserved as-is.\n\n**Environment:** All variables exported as `enabled: true` in Postman-compatible format.\n\n</details>\n\n### Native Export & Import\n\nExport collections and environments to a portable `.atm/` folder. Share with your team or copy between projects.\n\n```\n\"Export my collection and dev environment\"\n```\n\n```\nyour-project/\n└── .atm/\n    ├── collection.json\n    └── dev.env.json\n```\n\n> **Note:** `.atm/` is automatically added to `.gitignore` on first export.\n\n### cURL Export\n\nConvert any saved request into a ready-to-paste cURL command with resolved variables.\n\n```\n\"Export the create-user request as curl\"\n```\n\n```bash\ncurl -X POST \\\n  'https://api.example.com/users' \\\n  -H 'Authorization: Bearer eyJhbGci...' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"Jane\",\"email\":\"jane@company.com\"}'\n```\n\n---\n\n## Tool Reference\n\n42 tools across 10 categories:\n\n| Category | Tools | Count |\n|----------|-------|:-----:|\n| **Requests** | `request` | 1 |\n| **Inspect** | `inspect_last_response` | 1 |\n| **Testing** | `assert` | 1 |\n| **Flows** | `flow_run` | 1 |\n| **Collections** | `collection_save`, `collection_list`, `collection_get`, `collection_delete` | 4 |\n| **Environments** | `env_create`, `env_list`, `env_set`, `env_get`, `env_switch`, `env_rename`, `env_delete`, `env_spec`, `env_project_clear`, `env_project_list` | 10 |\n| **Groups** | `env_group_create`, `env_group_list`, `env_group_delete`, `env_group_add_scope`, `env_group_remove_scope`, `env_set_default`, `env_set_group` | 7 |\n| **API Specs** | `api_import`, `api_spec_list`, `api_endpoints`, `api_endpoint_detail` | 4 |\n| **Mock** | `mock` | 1 |\n| **Utilities** | `load_test`, `export_curl`, `diff_responses`, `bulk_test`, `export_collection`, `import_collection`, `export_environment`, `import_environment`, `export_postman_collection`, `import_postman_collection`, `export_postman_environment`, `import_postman_environment` | 12 |\n\n> **Tip:** You don't need to call tools directly. Describe what you want and the AI picks the right one.\n\n---\n\n## Storage\n\nEverything is local. No database, no cloud sync, no telemetry. All data lives in `~/.api-testing/` as plain JSON files you can read, back up, or delete at any time.\n\n```\n~/.api-testing/\n├── groups/               # Environment groups with scopes and defaults\n├── environments/         # Environment variables — tokens, keys, passwords\n├── collections/          # Saved requests (shareable, no secrets)\n├── specs/                # Imported OpenAPI specs\n└── project-envs.json     # Session-only active environments (cleared on restart)\n```\n\n**Global storage vs project exports.** The `~/.api-testing/` directory is your private, global store — this is where credentials live and they never leave. When you export a collection or environment, it goes to `.atm/` in your project root. That folder is auto-added to `.gitignore` on first export, but even if you choose to commit it, your credentials stay in `~/.api-testing/` and are never copied into `.atm/`. You can safely share `.atm/` exports with your team without leaking secrets.\n\nOverride the default storage path:\n\n```json\n{\n  \"env\": { \"API_TESTING_DIR\": \"/path/to/custom/.api-testing\" }\n}\n```\n\n> **Warning:** If you override `API_TESTING_DIR` to a path inside a git repository, add `.api-testing/` to your `.gitignore` to avoid pushing credentials.\n\n---\n\n## Architecture\n\n```\nsrc/\n├── index.ts              # Entry point (shebang + StdioServerTransport)\n├── server.ts             # createServer() factory\n├── tools/                # 42 tool handlers (one file per category)\n│   ├── request.ts        # HTTP request (1)\n│   ├── inspect.ts        # inspect_last_response (1)\n│   ├── assert.ts         # Assertions (1)\n│   ├── flow.ts           # Request chaining (1)\n│   ├── collection.ts     # Collection CRUD (4)\n│   ├── environment.ts    # Environments + groups (17)\n│   ├── api-spec.ts       # OpenAPI import/browse (4)\n│   ├── mock.ts           # Mock data generation (1)\n│   ├── load-test.ts      # Load testing (1)\n│   └── utilities.ts      # curl, diff, bulk, import/export (11)\n├── lib/                  # Business logic (no MCP dependency)\n│   ├── http-client.ts    # fetch wrapper with timing\n│   ├── storage.ts        # JSON file storage engine (atomic writes)\n│   ├── compress.ts       # Response compression + verbosity modes\n│   ├── response-cache.ts # Ring buffer + disk cache for inspect\n│   ├── schemas.ts        # Shared Zod schemas (HttpMethodSchema, AuthSchema)\n│   ├── url.ts            # BASE_URL resolution\n│   ├── path.ts           # Dot-notation accessor (body.data.0.id)\n│   ├── interpolation.ts  # {{variable}} resolver\n│   └── openapi-parser.ts # $ref + allOf/oneOf/anyOf resolution\n└── __tests__/            # 10+ test suites, 171 tests\n```\n\n**Stack:** TypeScript (strict) · MCP SDK · Zod · Vitest · tsup\n\n---\n\n[MIT](./LICENSE) · Built by [cocaxcode](https://github.com/cocaxcode)\n",
  "bytes": 20473,
  "sha": "dff1efce8008c754c85fc34023ac66dd5ece340e9d59525aec7ac7683b2f91f1",
  "repo_slug": "cocaxcode/api-testing-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_cocaxcode_api_testing_mcp_ef5c0cbe/readme"
}