{
  "markdown": "<!-- mcp-name: io.github.furkan708/mcpify -->\n\n# mcpify\n\n[![Tests](https://img.shields.io/badge/tests-520%20passed-brightgreen)](https://github.com/furkan708/mcpify/actions/workflows/ci.yml)\n[![CI](https://github.com/furkan708/mcpify/actions/workflows/ci.yml/badge.svg)](https://github.com/furkan708/mcpify/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/furkan708/mcpify/actions/workflows/codeql.yml/badge.svg)](https://github.com/furkan708/mcpify/actions/workflows/codeql.yml)\n[![PyPI](https://img.shields.io/pypi/v/mcpify-openapi)](https://pypi.org/project/mcpify-openapi/)\n[![PyPI Downloads](https://img.shields.io/pypi/dm/mcpify-openapi)](https://pypi.org/project/mcpify-openapi/)\n[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)\n![License](https://img.shields.io/badge/license-MIT-green)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-4A90D9)](server.json)\n![Dependencies](https://img.shields.io/badge/dependencies-zero-success)\n\nEnglish | [Türkçe](README.tr.md)\n\n<p align=\"center\">\n  <img src=\"docs/demo.gif\" alt=\"mcpify in action — listing and serving OpenAPI endpoints as MCP tools\" width=\"720\">\n</p>\n\n**Turn any OpenAPI REST API into an [MCP](https://modelcontextprotocol.io) server** — so Claude Code, Cursor, and every other MCP client can call your API directly. One command, zero runtime dependencies:\n\n```bash\nmcpify serve https://your-company.com/openapi.json\n```\n\n```bash\n# try it right now, nothing installed (uvx pulls from PyPI on demand)\nuvx --from mcpify-openapi mcpify list examples/petstore.json --cost\n```\n\nFocused, production-ready, CLI-first: one job (OpenAPI → MCP). Everything\nelse — governance, credentials, token economics, operations — is opt-in\nand stays out of the way until you need it:\n\n- **Safe for agents by default** — lazy context budget (`--lazy`), secret masking (`--redact`), blast-radius limits (`--read-only`, per-token RBAC)\n- **Ready for real deployments** — stdio + HTTP/SSE, OAuth2 and split read/write credentials, health probes, audit trail, metrics, multi-API serving, hot reload\n- **Proven, not promised** — 520 tests across twenty-eight suites, a hostile-spec corpus, live-CI checks, zero runtime dependencies\n\n## Why you'll like it\n\n**From spec to server**\n\n- **60 seconds to working** — point it at any OpenAPI 3.x spec (file or URL)\n- **Every operation becomes a first-class MCP tool** — input schemas are generated from `parameters` + `requestBody`, internal `$ref`s are resolved\n- **Spec versions diffed from the tool view** — `mcpify diff old.yaml new.yaml` reports added/removed/changed operations with per-change **breaking** verdicts and a migration guide; `--fail-on-breaking` is a CI gate\n- **`mcpify doctor`** — tells you if your spec is agent-friendly before you ship: missing operationIds, missing summaries, instruction-like tool text, overlong descriptions; `--probe` dials the API once — with your real credential (`--auth-env`) when you want auth proven end-to-end, and `--fail-on-http-error` for a strict CI gate\n- **`mcpify try` / `mcpify mock` / `mcpify output-server`** — call the tools without an agent client, serve a schema-shaped fake API for CI, or bake a serve command into a shareable script\n\n**Credentials & policy**\n\n- **Credentials never touch the spec or the model** — pulled from your environment at call time; the spec's own security declarations pick the flags (bearer, basic, header, query)\n- **OAuth2 client-credentials built in** — tokens are fetched, cached, refreshed and re-fetched on a mid-flight 401 (RFC 6749, stdlib only); `--write-oauth2-*` gives non-GET calls a **second client identity** so reads and writes authenticate as different clients\n- **Least-privilege by default** — `--write-auth-env` splits the static credential (reads on your read key, writes on a dedicated key), `--read-only` filters the surface, `--deny/--allow` hides mutating GETs, per-token RBAC gives each bearer token its own allow/deny scopes\n- **`--redact password,token`** — values whose key names a secret are masked with `***` at every level of every response (error bodies included, case-insensitive); the model never sees them\n- **Audit trail without content exposure** — one JSON line per call: tool, API, status, latency, an argument *fingerprint* (never raw arguments); `--plugin` loads your Python module for auth/request/result hooks\n\n**Token economics**\n\n- **See the bill before serving** — `mcpify list --cost` prices the surface (~4 chars/token): what every agent pays in EVERY `tools/list`; multi-API configs get per-API and total prices in one run\n- **`--fields id,event`** — response projection that selects at every level: selected keys keep their value, non-selected containers stay transparent, emptied containers drop. Live weather.gov: 350 alerts in full inside the budget that previously truncated at ~189\n- **Valid truncation** — oversized responses are cut along JSON structure with an explicit `\"truncated\": true` marker, never mid-document\n- **`--lazy` search-then-call** — cut api.weather.gov's listing by 95.5%; search results now show what pulling each full schema would cost, so the agent pulls only what it needs\n- **`[tool-text]` overrides** — doctor flags model-facing instruction-like descriptions; you replace them per tool in config\n\n**Operations**\n\n- **Two transports, one tool surface** — stdio for local agents; `serve --http 8080` speaks MCP Streamable HTTP (SSE responses for clients that ask, JSON otherwise) so a whole team shares one server, with optional bearer tokens\n- **Several APIs, one MCP server** — `[apis.NAME]` sections in `.mcpify.toml`: per-API auth, caching, retries, filters and rate limits; collision-safe renames; aggregated health; `mcpify status` probes every API in parallel\n- **Upstream courtesy built in** — ETag-aware caching, idempotent-only retries (502/503/504), `--wait-on-429` honors Retry-After, `--rate-limit RPS` caps requests/second (per upstream in multi-API, retries included)\n- **Observability, opt-in only** — Prometheus `--metrics` (call counters, latencies, cache, health — plus projection/redaction counters when those run), `--otel` spans, `--reload` hot swap, `mcpify ui` local dashboard\n- **Host it yourself for free** — docker-compose with automatic-HTTPS Caddy plus a hardened systemd unit: [Self-hosting guide](docs/SELF-HOSTING.md)\n- **Zero runtime dependencies** — the entire tree is auditable stdlib Python; YAML specs need an optional `pip install 'mcpify[yaml]'`\n\n## Quick start\n\n```bash\n# install (installs the `mcpify` command)\npipx install mcpify-openapi\n\n# run without installing (uvx — pulls from PyPI on demand)\nuvx --from mcpify-openapi mcpify list ./openapi.json --read-only\n\n# first time? the wizard writes a config for you\nuvx --from mcpify-openapi mcpify init\n\n# ...as a container (GHCR, published on every release)\ndocker run -i ghcr.io/furkan708/mcpify:latest serve ./openapi.json --read-only\n\n# ...or from source\ngit clone https://github.com/furkan708/mcpify.git\ncd mcpify && pip install .\n\n# 1. preview the tools that will be generated (add --cost for the context price)\nmcpify list examples/petstore.json\n\n# 2. validate the spec is agent-friendly (+ --probe for a live pre-flight)\nmcpify doctor examples/petstore.json\n\n# 3. serve it over MCP\nmcpify serve examples/petstore.json --base-url https://petstore.example.com/v1\n\n# 4. no agent client at hand? try the tools in your terminal\nmcpify try examples/petstore.json --base-url https://petstore.example.com/v1\n\n# 5. or share it over HTTP with the whole team\nmcpify serve examples/petstore.json --http 8080 --http-token $SHARED_TOKEN\n```\n\n### With authentication\n\n```bash\n# Bearer token read from the environment (never hardcoded)\nexport PETSTORE_KEY=\"sk-...\"\nmcpify serve petstore.json \\\n  --base-url https://petstore.example.com/v1 \\\n  --auth-env PETSTORE_KEY \\\n  --auth-style bearer \\            # optional: auto-detected from the spec\n  --read-only\n```\n\nNo explicit style needed in the common case — the spec's security\ndeclarations pick bearer/basic/header/query (with the right name) for\nyou. For HTTP Basic, the env variable holds `username:password`:\n`--auth-style basic --auth-env CREDS`.\n\n| Flag | Meaning |\n| ---- | ------- |\n| `--auth-env VAR` | environment variable holding the credential |\n| `--auth-style bearer\\|basic\\|header\\|query` | how it is sent (**default: auto-detected from the spec**) |\n| `--auth-name NAME` | header / query name for non-bearer styles (e.g. `X-API-Key`) |\n\n### With OAuth2 (client credentials)\n\nFor APIs behind an OAuth2 identity provider (RFC 6749 §4.4). Credentials\nlive in the environment; the access token is fetched, cached until its\n`expires_in`, refreshed transparently, and re-fetched automatically once\nif the API answers 401 mid-flight:\n\n```bash\nexport OAUTH2_CLIENT_ID=\"...\"\nexport OAUTH2_CLIENT_SECRET=\"...\"\nmcpify serve api.json \\\n  --oauth2-token-url https://idp.example.com/oauth2/token \\\n  --oauth2-client-id-env OAUTH2_CLIENT_ID \\\n  --oauth2-client-secret-env OAUTH2_CLIENT_SECRET \\\n  --oauth2-scope \"read write\"        # optional; --oauth2-client-auth body for token endpoints that reject Basic\n```\n\n**Split write identities too:** `--write-oauth2-token-url` (+ client/scope\nflags) runs a second client-credentials flow for non-GET calls — reads\nauthenticate as the read client, writes as the write client, each with\nits own token cache and the same 401 self-heal. Mutually exclusive with\n`--write-auth-env` (pick one credential kind for writes).\n\n### Multiple APIs in one server\n\nPut several OpenAPI documents in one config and serve them as a single\ntool surface — no gateway, no per-API process:\n\n```toml\n# .mcpify.toml\n[apis.catalog]\nspec = \"https://shop.example.com/openapi.json\"\nauth-env = \"CATALOG_TOKEN\"          # per-API credential\ncache-ttl = 60\nrate-limit = 5                      # per-API courtesy throttle (req/s)\nredact = \"password,client_secret\"   # per-API response masking\n\n[apis.crm]\nspec = \"./crm.yaml\"\nread-only = true                    # per-API policy\nbase-url = \"https://crm.internal/v2\"\nfields = \"id,name\"                  # per-API response projection\n\n[apis.weather]\nspec = \"https://api.weather.gov/openapi.json\"\ntimeout = 10\n```\n\nSurface switches (`--lazy`, `--enable-preview`, `--http`, `--format`) are\nserver-wide flags; credentials, policies, caching and retries are per-API.\n\n```bash\nmcpify list --cost      # preview every API and price each surface\nmcpify serve            # stdio, all three APIs, prefixed on collisions\nmcpify serve --http 8080\nmcpify try              # REPL across every API\nmcpify status           # probes each API concurrently\n```\n\n`mcpify status` reports per API — `[catalog] reachable (status 200, 0.03s)\n— https://shop.example.com — 31 tools` — and exits non-zero if any API is\nunreachable. When two APIs expose the same tool name (`list_pets`), both\nget renamed with their label (`catalog_list_pets`, `crm_list_pets`) so\nnothing silently wins; non-conflicting names stay untouched. The\n`mcpify_health` tool returns one report covering every API. Precedence\nper key: CLI flags > `[apis.NAME]` > `[serve]`. Pass a positional spec\n*or* `[apis.*]` sections — never both.\n\n## Plug it into your agent\n\n**Claude Code:**\n\n```bash\nclaude mcp add my-api -- mcpify serve openapi.json --read-only\n```\n\n**Claude Desktop / Cursor / any MCP client** (`claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"petstore\": {\n      \"command\": \"mcpify\",\n      \"args\": [\"serve\", \"~/specs/petstore.json\", \"--auth-env\", \"PETSTORE_KEY\"]\n    }\n  }\n}\n```\n\n**HTTP transport (team-shared server)** — run `mcpify serve api.json --http 0.0.0.0:8080 --http-token $TOKEN` once, then point HTTP-capable clients at it:\n\n```json\n{\n  \"mcpServers\": {\n    \"petstore\": {\n      \"type\": \"http\",\n      \"url\": \"http://your-host:8080\",\n      \"headers\": { \"Authorization\": \"Bearer <token>\" }\n    }\n  }\n}\n```\n\nNow ask your agent: *\"list the pets, then create one named Milo\"* — it discovers `list_pets` and `create_pet`, fills the arguments, and performs real HTTP calls.\n\n## How operations become tools\n\n| OpenAPI | mcpify |\n| ------- | ------ |\n| `operationId` | tool name (sanitized; falls back to `method_path`) |\n| `summary` / `description` | tool description the agent reads |\n| `deprecated: true` | shown by `mcpify list` before you expose old endpoints |\n| `parameters` (path/query/header) | individual typed arguments with enums |\n| `requestBody` (JSON) | a `body` object argument |\n| `$ref` pointers | resolved inline (components → real schemas) |\n| `servers[0].url` | default base URL (override: `--base-url`) |\n\nThe agent only ever sees the tool list and your API's JSON responses —\nmcpify adds no middleware, caches nothing you did not ask for, and sends\ncredentials nowhere except your API.\n\n## Doctor\n\n```bash\n$ mcpify doctor my-api.json\nopenapi: 3.0.3\ntitle:   Acme API\npaths:   23\ntools:   41 operations\nservers: https://api.acme.com\nwarning: 12/41 operations have no operationId (names fall back to method_path)\nwarning: 30/41 operations have no summary (agents see no description)\n```\n\nAdd `--probe` for a live pre-flight — after the static report, mcpify\ndials one argument-free GET (or the base URL) and reports reachability;\na connection failure exits non-zero so CI and shell scripts stop before\nserving:\n\n```bash\n$ mcpify doctor https://api.weather.gov/openapi.json --probe\n...\nprobe:    GET /alerts → 200 reachable (2.80s)\n```\n\n## CLI reference\n\n```\nmcpify list <spec> [--tag T] [--include P] [--exclude P] [--read-only] [--json]\nmcpify list --cost                        # price the surface (~4 chars/token)\nmcpify list --cost --lazy                 # ...and the 3-meta-tool lazy surface\nmcpify list --config .mcpify.toml --cost  # multi-API: every surface priced\nmcpify serve <spec> [--base-url URL] [--server INDEX|NAME] [--name N] [--auth-env VAR]\n                    [--auth-style bearer|header|query] [--auth-name NAME]\n                    [--oauth2-token-url URL --oauth2-client-id-env VAR\n                     --oauth2-client-secret-env VAR] [--timeout S]\n                    [--read-only] [--tag T] [--include P] [--exclude P]\n                    [--http [HOST:]PORT] [--http-token TOKEN] [--wait-on-429 SEC]\nmcpify try <spec> [same serve flags]        # interactive REPL, no agent needed\nmcpify output-server <spec> -o FILE [-- <any serve flags>]\nmcpify ui <spec> [same serve flags]         # local dashboard (tool explorer, health, config)\nmcpify mock <spec> [--http 8000] [--delay-ms N]\nmcpify diff OLD NEW [--json] [--fail-on-breaking]        # upgrade report + CI gate\nmcpify diff OLD NEW --probe [--auth-env V]               # ...+ live check of the NEW API + cost delta\nmcpify config-schema                        # JSON Schema for .mcpify.toml (editor wiring)\nmcpify doctor <spec> [--probe --auth-env V --fail-on-http-error]   # static audit + live pre-flight / CI gate\n\n# token economics: --fields id,name (projection), --redact password,token (masking),\n#   --rate-limit RPS (upstream courtesy, retries included)\n# credential split: --write-auth-env WRITE_KEY_ENV or --write-oauth2-token-url (reads keep --auth-env)\n# tool-text overrides: [tool-text.TOOL] description = \"...\" in .mcpify.toml\n\n# multi-API: define [apis.NAME] sections in .mcpify.toml, then run\n#   mcpify list|serve|try|status|ui (no positional spec) — one process, every API\n# ops add-ons for serve/ui: --metrics [HOST:]PORT   --reload   --cache-warm\n#   --audit-log FILE   --http-token-file FILE   --plugin FILE (repeatable)   --otel [ENDPOINT]\n```\n\n### Notes & limitations\n\n- JSON specs work out of the box; YAML specs need `pip install 'mcpify[yaml]'`\n- External `$ref` targets (files or URLs) are bundled automatically at load; circular\n  cross-file refs are left in place rather than unwound (surface skips what it cannot resolve)\n- Oversized JSON responses truncate to valid JSON (first items + a truncation marker);\n  non-JSON bodies cut at a character boundary\n- `--fields` selects at every level by documented rule (selected keys verbatim,\n  non-selected containers transparent); it is a projection, not a security boundary —\n  use `--redact` when a field must never reach the model\n- Request bodies are exposed as a single `body` object argument — predictable over clever\n- HTTP transport serves one JSON-RPC response per request (batching was removed from\n  the MCP spec); clients that send `Accept: text/event-stream` get it framed as a\n  single SSE `message` event. Server-initiated streams (a GET stream with sessions)\n  stay deliberately out of scope for a stateless server\n- Spec versions: OpenAPI 3.x and Swagger 2.x roots are accepted; 3.x is the happy path\n\n## Hardened against the real world\n\nmcpify is audited on every release against a 10-category checklist of MCP\nbest practices and published production failure modes — not just our own\nexamples:\n\n- **Hostile-spec corpus (12/12):** circular `$ref`s, multipart uploads,\n  `allOf` schemas, server URL variables, relative base URLs, oversized\n  responses — every scenario derived from a documented real-world failure,\n  fixed, and locked in by a regression test. Sources include the arXiv\n  study of REST→MCP generation across 18 real APIs.\n- **Live integration:** the real api.weather.gov spec loads in CI — and\n  the live checks found the last two real bugs (nested-truncation\n  envelope splits, top-level-only projection) before any user did.\n- **MCP lifecycle enforced:** tools are unreachable until the client\n  completes the `initialize` handshake.\n- **Session survives upstream failures:** a slow upstream (read timeout), a\n  mid-response disconnect, or even an unexpected exception inside one tool\n  becomes a clean `isError` tool result with remediation — never a dead\n  stdio connection (the failure mode reported against other OpenAPI-to-MCP\n  servers, replayed here and locked in by regression tests).\n- **Blast-radius controls:** read-only mode, deny/allow policy layer,\n  per-token RBAC, response projection + secret masking, rate limiting,\n  40k-char valid truncation, `--timeout`, credentials never logged.\n\nFull checklist with per-item status: **[docs/AUDIT-CHECKLIST.md](docs/AUDIT-CHECKLIST.md)**\n\n## Tests\n\n**520 passing**, plus one live-integration test that loads the real\napi.weather.gov document (auto-skipped when offline) and an OTel positive\ntest that runs wherever the optional tracing extra is installed. Every\nsuite runs on Python 3.10–3.12 across Linux and Windows; `ruff`, strict\n`mypy` and CodeQL gate every push.\n\n| Suite | Tests | What it pins down |\n|---|---:|---|\n| Spec parsing & resolution | 13 | OpenAPI 3.x + YAML loading, `$ref` chains, `allOf` merge, server variables, malformed input |\n| Tool translation | 19 | operationId naming with collision suffixing, input schemas, enums, body handling, annotation & output-schema derivation |\n| Agent surface | 32 | HTTP-derived annotations, structured output contract, remediation errors, `--lazy` search, dry-run previews |\n| CLI | 15 | `list` / `doctor` / `serve` flags, `--json` output, deprecated badges |\n| Hostile corpus | 11 | circular `$ref`s, multipart bodies, relative base URLs, 300 KB truncation, 500-op performance — each traced to a documented real-world failure |\n| Lifecycle & hygiene | 8 | initialize handshake (`-32002`), byte-pure stdio, credentials never logged |\n| Protocol end-to-end | 9 | real JSON-RPC over stdio against a live local HTTP API, wire-level assertions |\n| Policy layer | 7 | `--read-only`, `--allow` / `--deny` precedence, mutating-GET protection |\n| `$ref` parameters | 4 | parameter schemas resolved against the full spec — the weather.gov bug class (one test hits the live document) |\n| Ops & configuration | 47 | config files + env precedence, init wizard, cache TTL & bounds, retry safety, XML conversion, discovery, batching, status/health |\n| Protocol version compat | 5 | 2026-07-28 stateless `_meta` requests and the legacy 2025-06-18 handshake, on the same wire |\n| HTTP transport | 19 | Streamable HTTP: lifecycle over POST, 405/411/413/415 error ladder, parse/batch rejections, bearer enforcement, bind-string parser |\n| OAuth2 client-credentials | 18 | token fetch/cache/refresh with a fake clock, Basic vs body client auth, public clients, every failure mode, 401 self-heal end-to-end |\n| `try` REPL | 26 | piped-stdin sessions: selection by number/name, typed prompts, re-prompt on bad input, `:raw`/`:info`, clean EOF/Ctrl+C exits, read-only surface |\n| `output-server` | 11 | embedded spec integrity, guard rails (existing file, bad spec, unknown flags), secret warnings, and a real subprocess E2E handshake |\n| Server selection | 17 | `--server INDEX|NAME` rules: index, description/URL name matching, error listings, `--base-url` precedence, server-variable defaults, CLI/status/config/doctor wiring |\n| Auth auto-detection & Basic | 22 | securitySchemes → style/name resolution (OpenAPI + Swagger 2.0), requirement-order precedence, operation-level security, exact hint text, HTTP Basic header encoding, CLI/try/doctor wiring, explicit-style override |\n| Rate-limit courtesy (`--wait-on-429`) | 9 | Retry-After honored once within cap, cap exceeded returns 429 untouched, missing header falls back to retry delay, HTTP-date form never waits, POST never auto-waited, CLI wiring |\n| Multi-API aggregation | 26 | `[apis.*]` merge with two-sided collision prefixes and `_2` suffixes, per-API routing/auth/cache isolation, concurrent aggregated health (dead-API named in hint), lazy search across APIs incl. label match, preview routing, status exit codes, `--env` inheritance, both-rejected flag combos |\n| Ops: dashboard, metrics, mock, reload | 25 | `/metrics` text format (counters/histograms/cache hit-miss/health gauges), token'd UI routes, masked preview API, config-form writer (+unknown-key 400), schema-shaped mock responses with template routing, hot-reload rebuild incl. broken-spec survival |\n| CLI connectivity glue | 10 | `--http` wiring, `MCPIFY_HTTP_TOKEN` fallback, OAuth2 flag rules, config-file keys, wizard option 5, `try` smoke test |\n| Spec diff (`mcpify diff`) | 14 | added/removed/changed ops, breaking verdicts (required param added/became, body became required, op removal), deprecation & operationId warnings, migration guide, document-level diff, CLI exit contract 0/1/2, `--json` |\n| v1.11 serving: audit, cache, RBAC, plugins | 17 | JSONL audit trail with argument fingerprints + fail-safe on unwritable files, ETag 304 revalidation on stale entries, `mcpify_cache_invalidate` (scoped + full), `--cache-warm` pre-calls argument-free GETs only, token-file scoping end-to-end (401 / filtered lists / refused calls, deny wins, duplicate-token rejection), plugin hooks on real requests, `mcpify ui` dispatch (dead-command regression), `config-schema` matches the config module, OTel guard |\n| External `$ref` bundling | 6 | file + URL-base targets inlined, component-only target files, nested refs resolved relative to their own file, missing targets skipped, circular refs survive, same-document refs untouched |\n| Governance: split keys, tool text, valid truncation | 21 | read-key/write-key per method over a live upstream (shared-identity default unchanged), style/name inheritance + explicit override, config `write-auth-*` keys in serve/envs/apis, `[tool-text]` override through `list --json`, unknown-tool warnings, validator errors, schema/keys parity, doctor instruction-like + overlong-description counts, oversized array → valid JSON with marker, object key-keeping, non-JSON fallback, error-prefix survival |\n| v1.13: cost, projection, SSE, OAuth2 write | 20 | surface pricing in JSON + human output, recursive projection with transparent envelopes (both rules pinned: the top-level-only first rule failed live), selected keys keep their arrays, SSE framing vs JSON clients, write-flow resolution + mutual exclusion with `--write-auth-env` |\n| v1.16: status policy, REPL session controls, diff probe + cost delta | 12 | policy (fields/redact/rate-limit) in multi-API JSON+human status and single-spec `policy:` line, `:redact`/`:fields` session set/show/clear over a live upstream (masking verified on the wire), diff surface-cost delta in JSON+human, `--probe` reachable/unreachable exit contract (2 on probe failure), form retry-delay float |\n| v1.15: auth-probe, strict gate, metrics, lazy pricing | 16 | probe with a real credential (401-without vs 200-with over a live local upstream), strict-mode verdicts, doctor CLI exit contract, projection/redaction Prometheus counters (values counted, fresh-session enable), count_redact_targets, lazy-surface pricing lines, `init --probe` reachable/unreachable, dashboard-form token keys (float coercion, unknown-key rejection) |\n| v1.14: redact, rate-limit, probe, multi list | 29 | masking at every level incl. error bodies and selected-key overlap, arrays masked in place, limiter slots with a fake clock, retry throttling, probe target selection + reachability exit contract, config `redact`/`rate-limit` in serve/apis/envs, per-upstream limiters, multi-API `list` + pricing |\n\nPolicy on failures: every bug found in the wild becomes a pinned\nregression test before the fix ships — the suite only grows.\n\nRun it locally:\n\n```bash\npip install pytest pyyaml\npytest -v\n```\n\n## Roadmap\n\nThe v1.6–1.16 roadmap is fully shipped. Possible future work (not\npromised): server-initiated SSE (a GET stream with sessions —\ndeliberately out for a stateless transport).\n- [x] ~~`status` policy visibility, REPL `:redact`/`:fields`, `diff --probe` + cost delta, form examples~~ — shipped in v1.16.0\n- [x] ~~Authenticated `doctor --probe` + `--fail-on-http-error` CI gate, `init --probe`, projection/redaction metrics, lazy-surface pricing~~ — shipped in v1.15.0\n- [x] ~~`--redact`, `--rate-limit`, `doctor --probe`, lazy-search costs, multi-API `list`~~ — shipped in v1.14.0\n- [x] ~~OAuth2 write flow (`--write-oauth2-*`), `list --cost`, `--fields` projection, SSE POST responses~~ — shipped in v1.13.0\n- [x] ~~Read/write credential split, tool-text overrides, doctor prompt-hygiene audit, structure-aware truncation~~ — shipped in v1.12.0\n- [x] ~~Spec diff + audit log + per-token RBAC + plugin hooks + config JSON Schema + external `$ref` bundling + OTel extra~~ — shipped in v1.11.0\n- [x] ~~Web dashboard, Prometheus metrics, mock server, hot reload~~ — shipped in v1.10.0\n- [x] ~~Multi-API aggregation: one `serve` process fronting several OpenAPI documents~~ — shipped in v1.9.0\n- [x] ~~HTTP transport~~, ~~OAuth2 client-credentials~~, ~~`mcpify try` REPL~~, ~~`--output-server`~~ — shipped in v1.6.0\n\n## License\n\nMIT — see the [LICENSE](LICENSE) file for details.\n",
  "bytes": 26648,
  "sha": "9c9c180516f72cb1d3adb497c04942d87c3762d56a9588d26fe098ecfde478cc",
  "repo_slug": "furkan708/mcpify",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_furkan708_mcpify_1ca6ac8f/readme"
}