Mcpify
This MCP server exposes pet-store operations as callable tools plus a built-in health check.
list_pets β list all pets, optionally filtered by kind (cat/dog/bird) and limited by count
get_pet β fetch a single pet by its numeric
petIdlist_vaccinations β list vaccinations for a pet by
petIdget_stats β retrieve store statistics
mcpify_health β verify upstream reachability and server configuration (tool count, cache, retry, auth)
mcpify
English | TΓΌrkΓ§e
Turn any OpenAPI REST API into an MCP server β so Claude Code, Cursor, and every other MCP client can call your API directly. One command, zero runtime dependencies:
mcpify serve https://your-company.com/openapi.json# try it right now, nothing installed (uvx pulls from PyPI on demand)
uvx --from mcpify-openapi mcpify list examples/petstore.json --costFocused, production-ready, CLI-first: one job (OpenAPI β MCP). Everything else β governance, credentials, token economics, operations β is opt-in and stays out of the way until you need it:
Safe for agents by default β lazy context budget (
--lazy), secret masking (--redact), blast-radius limits (--read-only, per-token RBAC)Ready for real deployments β stdio + HTTP/SSE, OAuth2 and split read/write credentials, health probes, audit trail, metrics, multi-API serving, hot reload
Proven, not promised β 520 tests across twenty-eight suites, a hostile-spec corpus, live-CI checks, zero runtime dependencies
Why you'll like it
From spec to server
60 seconds to working β point it at any OpenAPI 3.x spec (file or URL)
Every operation becomes a first-class MCP tool β input schemas are generated from
parameters+requestBody, internal$refs are resolvedSpec versions diffed from the tool view β
mcpify diff old.yaml new.yamlreports added/removed/changed operations with per-change breaking verdicts and a migration guide;--fail-on-breakingis a CI gatemcpify doctorβ tells you if your spec is agent-friendly before you ship: missing operationIds, missing summaries, instruction-like tool text, overlong descriptions;--probedials the API once β with your real credential (--auth-env) when you want auth proven end-to-end, and--fail-on-http-errorfor a strict CI gatemcpify 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
Credentials & policy
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)
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 clientsLeast-privilege by default β
--write-auth-envsplits the static credential (reads on your read key, writes on a dedicated key),--read-onlyfilters the surface,--deny/--allowhides mutating GETs, per-token RBAC gives each bearer token its own allow/deny scopes--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 themAudit trail without content exposure β one JSON line per call: tool, API, status, latency, an argument fingerprint (never raw arguments);
--pluginloads your Python module for auth/request/result hooks
Token economics
See the bill before serving β
mcpify list --costprices the surface (~4 chars/token): what every agent pays in EVERYtools/list; multi-API configs get per-API and total prices in one run--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 ~189Valid truncation β oversized responses are cut along JSON structure with an explicit
"truncated": truemarker, never mid-document--lazysearch-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[tool-text]overrides β doctor flags model-facing instruction-like descriptions; you replace them per tool in config
Operations
Two transports, one tool surface β stdio for local agents;
serve --http 8080speaks MCP Streamable HTTP (SSE responses for clients that ask, JSON otherwise) so a whole team shares one server, with optional bearer tokensSeveral 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 statusprobes every API in parallelUpstream courtesy built in β ETag-aware caching, idempotent-only retries (502/503/504),
--wait-on-429honors Retry-After,--rate-limit RPScaps requests/second (per upstream in multi-API, retries included)Observability, opt-in only β Prometheus
--metrics(call counters, latencies, cache, health β plus projection/redaction counters when those run),--otelspans,--reloadhot swap,mcpify uilocal dashboardHost it yourself for free β docker-compose with automatic-HTTPS Caddy plus a hardened systemd unit: Self-hosting guide
Zero runtime dependencies β the entire tree is auditable stdlib Python; YAML specs need an optional
pip install 'mcpify[yaml]'
Related MCP server: @spec2tools/stdio-mcp
Quick start
# install (installs the `mcpify` command)
pipx install mcpify-openapi
# run without installing (uvx β pulls from PyPI on demand)
uvx --from mcpify-openapi mcpify list ./openapi.json --read-only
# first time? the wizard writes a config for you
uvx --from mcpify-openapi mcpify init
# ...as a container (GHCR, published on every release)
docker run -i ghcr.io/furkan708/mcpify:latest serve ./openapi.json --read-only
# ...or from source
git clone https://github.com/furkan708/mcpify.git
cd mcpify && pip install .
# 1. preview the tools that will be generated (add --cost for the context price)
mcpify list examples/petstore.json
# 2. validate the spec is agent-friendly (+ --probe for a live pre-flight)
mcpify doctor examples/petstore.json
# 3. serve it over MCP
mcpify serve examples/petstore.json --base-url https://petstore.example.com/v1
# 4. no agent client at hand? try the tools in your terminal
mcpify try examples/petstore.json --base-url https://petstore.example.com/v1
# 5. or share it over HTTP with the whole team
mcpify serve examples/petstore.json --http 8080 --http-token $SHARED_TOKENWith authentication
# Bearer token read from the environment (never hardcoded)
export PETSTORE_KEY="sk-..."
mcpify serve petstore.json \
--base-url https://petstore.example.com/v1 \
--auth-env PETSTORE_KEY \
--auth-style bearer \ # optional: auto-detected from the spec
--read-onlyNo explicit style needed in the common case β the spec's security
declarations pick bearer/basic/header/query (with the right name) for
you. For HTTP Basic, the env variable holds username:password:
--auth-style basic --auth-env CREDS.
Flag | Meaning |
| environment variable holding the credential |
| how it is sent (default: auto-detected from the spec) |
| header / query name for non-bearer styles (e.g. |
With OAuth2 (client credentials)
For APIs behind an OAuth2 identity provider (RFC 6749 Β§4.4). Credentials
live in the environment; the access token is fetched, cached until its
expires_in, refreshed transparently, and re-fetched automatically once
if the API answers 401 mid-flight:
export OAUTH2_CLIENT_ID="..."
export OAUTH2_CLIENT_SECRET="..."
mcpify serve api.json \
--oauth2-token-url https://idp.example.com/oauth2/token \
--oauth2-client-id-env OAUTH2_CLIENT_ID \
--oauth2-client-secret-env OAUTH2_CLIENT_SECRET \
--oauth2-scope "read write" # optional; --oauth2-client-auth body for token endpoints that reject BasicSplit write identities too: --write-oauth2-token-url (+ client/scope
flags) runs a second client-credentials flow for non-GET calls β reads
authenticate as the read client, writes as the write client, each with
its own token cache and the same 401 self-heal. Mutually exclusive with
--write-auth-env (pick one credential kind for writes).
Multiple APIs in one server
Put several OpenAPI documents in one config and serve them as a single tool surface β no gateway, no per-API process:
# .mcpify.toml
[apis.catalog]
spec = "https://shop.example.com/openapi.json"
auth-env = "CATALOG_TOKEN" # per-API credential
cache-ttl = 60
rate-limit = 5 # per-API courtesy throttle (req/s)
redact = "password,client_secret" # per-API response masking
[apis.crm]
spec = "./crm.yaml"
read-only = true # per-API policy
base-url = "https://crm.internal/v2"
fields = "id,name" # per-API response projection
[apis.weather]
spec = "https://api.weather.gov/openapi.json"
timeout = 10Surface switches (--lazy, --enable-preview, --http, --format) are
server-wide flags; credentials, policies, caching and retries are per-API.
mcpify list --cost # preview every API and price each surface
mcpify serve # stdio, all three APIs, prefixed on collisions
mcpify serve --http 8080
mcpify try # REPL across every API
mcpify status # probes each API concurrentlymcpify status reports per API β [catalog] reachable (status 200, 0.03s) β https://shop.example.com β 31 tools β and exits non-zero if any API is
unreachable. When two APIs expose the same tool name (list_pets), both
get renamed with their label (catalog_list_pets, crm_list_pets) so
nothing silently wins; non-conflicting names stay untouched. The
mcpify_health tool returns one report covering every API. Precedence
per key: CLI flags > [apis.NAME] > [serve]. Pass a positional spec
or [apis.*] sections β never both.
Plug it into your agent
Claude Code:
claude mcp add my-api -- mcpify serve openapi.json --read-onlyClaude Desktop / Cursor / any MCP client (claude_desktop_config.json):
{
"mcpServers": {
"petstore": {
"command": "mcpify",
"args": ["serve", "~/specs/petstore.json", "--auth-env", "PETSTORE_KEY"]
}
}
}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:
{
"mcpServers": {
"petstore": {
"type": "http",
"url": "http://your-host:8080",
"headers": { "Authorization": "Bearer <token>" }
}
}
}Now 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.
How operations become tools
OpenAPI | mcpify |
| tool name (sanitized; falls back to |
| tool description the agent reads |
| shown by |
| individual typed arguments with enums |
| a |
| resolved inline (components β real schemas) |
| default base URL (override: |
The agent only ever sees the tool list and your API's JSON responses β mcpify adds no middleware, caches nothing you did not ask for, and sends credentials nowhere except your API.
Doctor
$ mcpify doctor my-api.json
openapi: 3.0.3
title: Acme API
paths: 23
tools: 41 operations
servers: https://api.acme.com
warning: 12/41 operations have no operationId (names fall back to method_path)
warning: 30/41 operations have no summary (agents see no description)Add --probe for a live pre-flight β after the static report, mcpify
dials one argument-free GET (or the base URL) and reports reachability;
a connection failure exits non-zero so CI and shell scripts stop before
serving:
$ mcpify doctor https://api.weather.gov/openapi.json --probe
...
probe: GET /alerts β 200 reachable (2.80s)CLI reference
mcpify list <spec> [--tag T] [--include P] [--exclude P] [--read-only] [--json]
mcpify list --cost # price the surface (~4 chars/token)
mcpify list --cost --lazy # ...and the 3-meta-tool lazy surface
mcpify list --config .mcpify.toml --cost # multi-API: every surface priced
mcpify serve <spec> [--base-url URL] [--server INDEX|NAME] [--name N] [--auth-env VAR]
[--auth-style bearer|header|query] [--auth-name NAME]
[--oauth2-token-url URL --oauth2-client-id-env VAR
--oauth2-client-secret-env VAR] [--timeout S]
[--read-only] [--tag T] [--include P] [--exclude P]
[--http [HOST:]PORT] [--http-token TOKEN] [--wait-on-429 SEC]
mcpify try <spec> [same serve flags] # interactive REPL, no agent needed
mcpify output-server <spec> -o FILE [-- <any serve flags>]
mcpify ui <spec> [same serve flags] # local dashboard (tool explorer, health, config)
mcpify mock <spec> [--http 8000] [--delay-ms N]
mcpify diff OLD NEW [--json] [--fail-on-breaking] # upgrade report + CI gate
mcpify diff OLD NEW --probe [--auth-env V] # ...+ live check of the NEW API + cost delta
mcpify config-schema # JSON Schema for .mcpify.toml (editor wiring)
mcpify doctor <spec> [--probe --auth-env V --fail-on-http-error] # static audit + live pre-flight / CI gate
# token economics: --fields id,name (projection), --redact password,token (masking),
# --rate-limit RPS (upstream courtesy, retries included)
# credential split: --write-auth-env WRITE_KEY_ENV or --write-oauth2-token-url (reads keep --auth-env)
# tool-text overrides: [tool-text.TOOL] description = "..." in .mcpify.toml
# multi-API: define [apis.NAME] sections in .mcpify.toml, then run
# mcpify list|serve|try|status|ui (no positional spec) β one process, every API
# ops add-ons for serve/ui: --metrics [HOST:]PORT --reload --cache-warm
# --audit-log FILE --http-token-file FILE --plugin FILE (repeatable) --otel [ENDPOINT]Notes & limitations
JSON specs work out of the box; YAML specs need
pip install 'mcpify[yaml]'External
$reftargets (files or URLs) are bundled automatically at load; circular cross-file refs are left in place rather than unwound (surface skips what it cannot resolve)Oversized JSON responses truncate to valid JSON (first items + a truncation marker); non-JSON bodies cut at a character boundary
--fieldsselects at every level by documented rule (selected keys verbatim, non-selected containers transparent); it is a projection, not a security boundary β use--redactwhen a field must never reach the modelRequest bodies are exposed as a single
bodyobject argument β predictable over cleverHTTP transport serves one JSON-RPC response per request (batching was removed from the MCP spec); clients that send
Accept: text/event-streamget it framed as a single SSEmessageevent. Server-initiated streams (a GET stream with sessions) stay deliberately out of scope for a stateless serverSpec versions: OpenAPI 3.x and Swagger 2.x roots are accepted; 3.x is the happy path
Hardened against the real world
mcpify is audited on every release against a 10-category checklist of MCP best practices and published production failure modes β not just our own examples:
Hostile-spec corpus (12/12): circular
$refs, multipart uploads,allOfschemas, server URL variables, relative base URLs, oversized responses β every scenario derived from a documented real-world failure, fixed, and locked in by a regression test. Sources include the arXiv study of RESTβMCP generation across 18 real APIs.Live integration: the real api.weather.gov spec loads in CI β and the live checks found the last two real bugs (nested-truncation envelope splits, top-level-only projection) before any user did.
MCP lifecycle enforced: tools are unreachable until the client completes the
initializehandshake.Session survives upstream failures: a slow upstream (read timeout), a mid-response disconnect, or even an unexpected exception inside one tool becomes a clean
isErrortool result with remediation β never a dead stdio connection (the failure mode reported against other OpenAPI-to-MCP servers, replayed here and locked in by regression tests).Blast-radius controls: read-only mode, deny/allow policy layer, per-token RBAC, response projection + secret masking, rate limiting, 40k-char valid truncation,
--timeout, credentials never logged.
Full checklist with per-item status: docs/AUDIT-CHECKLIST.md
Tests
520 passing, plus one live-integration test that loads the real
api.weather.gov document (auto-skipped when offline) and an OTel positive
test that runs wherever the optional tracing extra is installed. Every
suite runs on Python 3.10β3.12 across Linux and Windows; ruff, strict
mypy and CodeQL gate every push.
Suite | Tests | What it pins down |
Spec parsing & resolution | 13 | OpenAPI 3.x + YAML loading, |
Tool translation | 19 | operationId naming with collision suffixing, input schemas, enums, body handling, annotation & output-schema derivation |
Agent surface | 32 | HTTP-derived annotations, structured output contract, remediation errors, |
CLI | 15 |
|
Hostile corpus | 11 | circular |
Lifecycle & hygiene | 8 | initialize handshake ( |
Protocol end-to-end | 9 | real JSON-RPC over stdio against a live local HTTP API, wire-level assertions |
Policy layer | 7 |
|
| 4 | parameter schemas resolved against the full spec β the weather.gov bug class (one test hits the live document) |
Ops & configuration | 47 | config files + env precedence, init wizard, cache TTL & bounds, retry safety, XML conversion, discovery, batching, status/health |
Protocol version compat | 5 | 2026-07-28 stateless |
HTTP transport | 19 | Streamable HTTP: lifecycle over POST, 405/411/413/415 error ladder, parse/batch rejections, bearer enforcement, bind-string parser |
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 |
| 26 | piped-stdin sessions: selection by number/name, typed prompts, re-prompt on bad input, |
| 11 | embedded spec integrity, guard rails (existing file, bad spec, unknown flags), secret warnings, and a real subprocess E2E handshake |
Server selection | 17 | `--server INDEX |
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 |
Rate-limit courtesy ( | 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 |
Multi-API aggregation | 26 |
|
Ops: dashboard, metrics, mock, reload | 25 |
|
CLI connectivity glue | 10 |
|
Spec 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, |
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, |
External | 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 |
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 |
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 |
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 |
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, |
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 |
Policy on failures: every bug found in the wild becomes a pinned regression test before the fix ships β the suite only grows.
Run it locally:
pip install pytest pyyaml
pytest -vRoadmap
The v1.6β1.16 roadmap is fully shipped. Possible future work (not promised): server-initiated SSE (a GET stream with sessions β deliberately out for a stateless transport).
statuspolicy visibility, REPL:redact/:fields,diff --probe+ cost delta, form examplesβ shipped in v1.16.0Authenticateddoctor --probe+--fail-on-http-errorCI gate,init --probe, projection/redaction metrics, lazy-surface pricingβ shipped in v1.15.0--redact,--rate-limit,doctor --probe, lazy-search costs, multi-APIβ shipped in v1.14.0listOAuth2 write flow (--write-oauth2-*),list --cost,--fieldsprojection, SSE POST responsesβ shipped in v1.13.0Read/write credential split, tool-text overrides, doctor prompt-hygiene audit, structure-aware truncationβ shipped in v1.12.0Spec diff + audit log + per-token RBAC + plugin hooks + config JSON Schema + external$refbundling + OTel extraβ shipped in v1.11.0Web dashboard, Prometheus metrics, mock server, hot reloadβ shipped in v1.10.0Multi-API aggregation: oneserveprocess fronting several OpenAPI documentsβ shipped in v1.9.0HTTP transport,OAuth2 client-credentials,mcpify tryREPL,β shipped in v1.6.0--output-server
License
MIT β see the LICENSE file for details.
Available Tools
5 toolsget_petBRead-onlyIdempotent
[GET] Get a single pet
| Name | Required | Description | Default |
|---|---|---|---|
| petId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds only '[GET]', which mostly duplicates the safety information already provided by annotations such as readOnlyHint=true, idempotentHint=true, and destructiveHint=false. It does not disclose additional behavioral details like missing-ID handling, authentication requirements, rate limits, or response shape; the annotations do the heavy lifting.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no filler or redundant elaboration. For a simple one-parameter read operation, this is appropriately compact and easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter, read-only get operation, the description plus annotations may be minimally sufficient, but the agent is left to infer too much from the tool name and parameter name. Missing guidance on what petId represents, how to handle nonexistent pets, and what a successful response looks like keeps this from being fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The sole required parameter petId has an empty schema description (0% coverage), and the tool description does not explain that petId identifies which pet to fetch or how it should be interpreted. The parameter name is suggestive, but the description adds no semantic value beyond what the schema already exposes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb ('Get') and resource ('a single pet'), which unambiguously conveys the operation and distinguishes it from list_pets by emphasizing singular retrieval. It does not explicitly contrast with siblings or mention the petId parameter, but the core purpose is clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The word 'single' implies this tool is for retrieving one specific pet rather than listing pets or vaccinations, so usage context is indirectly suggested. However, there is no explicit statement of when to use this tool versus list_pets, no prerequisites, and no mention of alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statsCRead-onlyIdempotent
[GET] Store statistics
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already convey readOnlyHint, idempotentHint, openWorldHint, and destructiveHint. The description adds no behavioral context beyond the redundant "[GET]" marker, such as whether results are aggregated, paginated, or time-bound.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Although the description is short, it is under-specified rather than usefully concise. It only repeats the title and adds an HTTP-verb hint that is already available in the annotations, so the brevity buys the agent no added insight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no clarification of what "statistics" means, the description is incomplete for an agent deciding whether this tool meets a user's request. It also fails to clarify how this endpoint relates to the sibling pet/vaccination tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the input schema is an empty object with no required fields. There is no parameter burden for the description to carry, so the baseline of 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description "[GET] Store statistics" restates the tool title and name almost verbatim. It identifies the resource at a high level but does not specify what statistics are included, so an agent cannot tell whether this returns sales totals, visit counts, or something else.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided about when to use get_stats instead of list_pets, get_pet, list_vaccinations, or mcpify_health. There is no mention of typical use cases, exclusions, or alternatives, so the agent must guess based on the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_petsBRead-onlyIdempotent
[GET] List all pets
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Filter by kind | |
| limit | No | How many pets to return |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the description adds only the '[GET]' method and list scope. It does't disclose pagination/default limit/response shape or filtering behavior, so contextual transparency is thin.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One short sentence with no filler, method prefix ('[GET]') front-loaded. Every token earns its place; it is appropriately sized for a simple list endpoint.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only list with two optional params and no output schema, the description is mostly sufficient to invoke it. However, it leaves ambiguity about whether 'all' is exhaustive or paginated, and gives no hint of the return shape β a real but minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and both parameters already have meaningful descriptions ('Filter by kind', 'How many pets to return'). The description adds nothing beyond the schema, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List all pets'), making the operation clear. It distinguishes from sibling get_pet (singular object vs. collection) and other siblings by resource/scope, though it doesn't explicitly name them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or alternative routing. The word 'all' implies collection-level fetching, and siblings like get_pet imply single-item lookup, but the description leaves the choice to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_vaccinationsBRead-onlyIdempotent
[GET] List vaccinations of a pet
| Name | Required | Description | Default |
|---|---|---|---|
| petId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructveHint=false. The description adds only '[GET]', which mostly duplicates the read-only annotation, and provides no additional behavioral context such as empty results, 404 behavior, or authentication requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence with no filler or redundant elaboration. It is front-loaded and easy to parse, though extremely minimal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read-only endpoint with rich annotations, a short description can be sufficient. However, it omits any mention of response shape, parameter semantics, or conditions for use, making it only minimally complete for guiding a correct call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for the only parameter petId, and the description does not explicitly map 'petId' to its role beyond saying 'of a pet'. This gives a weak hint that petId identifies the pet but does not compensate for the undocumented parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('List') and resource ('vaccinations of a pet'), which clearly distinguishes it from siblings like list_pets and get_pet. No ambiguity about what operation this tool performs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'of a pet' implies the tool is for retrieving vaccination records for one pet, but it does not explicitly state when to use it over alternatives or mention any exclusions. Usage is implied rather than directly guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mcpify_healthARead-onlyIdempotent
Check that the upstream API is reachable and report this server's own configuration (tool count, cache, retry, auth).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate a safe, read-only, idempotent operation. The description adds valuable context beyond annotations by disclosing that the tool reaches out to the upstream API and reports specific configuration details (tool count, cache, retry, auth). No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, no filler, and the main purpose is front-loaded before the specific reported fields. Every part of the sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity, no parameters, and strong annotations, the description sufficiently covers what the tool does and what it reports. It could specify the response format, but for a health-check tool with no inputs this is a minor omission.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters, there is nothing for the description to clarify about inputs. The baseline of 4 applies since the schema is trivially complete and no param-level guidance is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'Check' and names the exact resources: upstream API reachability and the server's own configuration. It clearly differentiates this health/config tool from the data-oriented siblings like list_pets and get_stats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The context is clear: use this when you need to verify upstream connectivity or inspect server configuration. It does not explicitly mention exclusions or when to prefer a sibling, but the described purpose strongly implies the appropriate usage scenario.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v1.0.0- First observed
get_pet - First observed
get_stats - First observed
list_pets - First observed
list_vaccinations - First observed
mcpify_health
TDQS
Scored across 5 tools
The four data tools are mostly distinct: list_pets/get_pet follow a standard list/detail pattern, and list_vaccinations clearly targets a subresource. get_stats and mcpify_health are also separate, though get_stats is vague enough that an agent might briefly confuse it with a health/status report.
list_pets, get_pet, list_vaccinations, and get_stats all use the snake_case verb_noun pattern. mcpify_health breaks that pattern structurally, and get_stats is less descriptive than a name like get_store_statistics would be.
Five tools is a compact, well-scoped set for this server. Each tool covers a distinct function: pet collection, pet detail, vaccination lookup, statistics, and health/configuration.
The read-oriented workflow is covered: list pets, get a specific pet, list vaccinations, retrieve stats, and check health. However, there are no create/update/delete tools for pets or vaccinations, which is a notable lifecycle gap unless the server is intentionally read-only.
Maintenance
Related MCP Connectors
Point Gecko at an OpenAPI spec; get first-call-correct, auth-hidden agent tools.
- typeshipOAuthdev.typeship
Generate a typed SDK, CLI, and MCP server from any OpenAPI or GraphQL spec, and keep them current.
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
Build, validate, deploy β HTTP APIs, cron jobs, webhooks and MCP tools β from your AI client.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceTurn any OpenAPI/Swagger spec into MCP tools. Zero config, zero code. Supports Swagger 2.0, OpenAPI 3.x, Bearer/API-key/OAuth2 auth, flat parameter schemas for better LLM accuracy, and smart response truncation.128 npm3MIT
- AlicenseNot gradedqualityCmaintenanceExposes any OpenAPI spec endpoints as AI agent tools via stdio, requiring no code generation or maintenance.18MIT
- AlicenseNot gradedqualityDmaintenanceAuto-generates MCP tools from your OpenAPI spec, allowing natural language interaction with any API via configurable headers and serverless deployment.19 npmMIT
- AlicenseNot gradedqualityAmaintenanceBridges any OpenAPI 3.x REST API to Claude Code by automatically generating one tool per endpoint from your spec, with full argument validation and auth support.6 npmMIT