Install
$ agentstack add mcp-gabrielbauman-anyapi-mcp Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ● Shell / process execution Used
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
anyapi-mcp
anyapi-mcp is one local MCP server that lets your model talk to almost any HTTP API. Add it once to Claude Code or Claude Desktop, then point it at any API you find (an OpenAPI spec, a GraphQL endpoint, a SOAP/WSDL service, or an AT Protocol/XRPC service like Bluesky) and your model can search and call it right away. No separate server or custom integration per API: one server covers everything you register, and it stays token-efficient however many calls a task takes.
Under the hood it generates a typed client from the API's own description and exposes a small set of tools: search to find operations, execute to run a short TypeScript program against that client, and add_api/list_apis/ remove_api to manage what's registered. Instead of one MCP tool per endpoint clogging the context window, the model writes code and runs it in a locked-down sandbox; intermediate results stay in that subprocess rather than round-tripping through the model, so a ten-step workflow costs one tool call and a handful of tokens, not ten.
Because that client is fully typed, the model drives the API without guesswork: a wrong argument is a type error, caught before any request leaves the machine.
Point an MCP client at anyapi-mcp serve with nothing registered yet and the server explains what it is and how to register one, so an empty server self-onboards instead of dead-ending. APIs added mid-session work immediately, no restart.
anyapi-mcp add https://example.com/openapi.json --docs https://example.com/docs --token
anyapi-mcp list
anyapi-mcp serve # stdio MCP server, for Claude Desktop / Claude Code
Requirements
- Deno 2.x (tested on 2.8).
- macOS or Linux.
- macOS: tokens are stored in the login keychain via
security. - Linux: tokens are stored via
secret-tool- installlibsecret-tools(e.g.
apt-get install libsecret-tools).
executeruns the model's code in adenosubprocess, so **denomust be on
PATH** - including when you run the compiled binary (which is otherwise self-contained).
Install
The quickest way - builds from source, so you'll need Deno 2.x (it's a runtime dependency too; see [Requirements](#requirements)):
curl -fsSL https://gabrielbauman.github.io/anyapi-mcp/install.sh | sh
It fetches the source, runs deno task compile, drops an anyapi-mcp binary in ~/.local/bin (override the location with ANYAPI_MCP_BIN_DIR), and registers it with Claude Code, Claude Desktop, and OpenCode so it's ready to use (skip that last step with ANYAPI_MCP_NO_INSTALL=1).
Or build it yourself:
deno task compile # produces a self-contained ./anyapi-mcp binary
mv ./anyapi-mcp ~/.local/bin/ # or anywhere on your PATH
anyapi-mcp install # register it with Claude Code, Claude Desktop, and OpenCode
Or run from source during development:
deno task dev list # = deno run -A src/main.ts list
Commands
add [options]
Inspects the source (an OpenAPI spec, a GraphQL endpoint, a WSDL, or an atproto PDS/service URL), derives the base URL and host, builds a searchable operation index, generates a typed client, and writes a registry entry.
| Option | Description | | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | --kind | Protocol (default: openapi). graphql introspects an endpoint; soap reads a WSDL URL; atproto takes a PDS/service URL (e.g. https://bsky.social). | | --id | Id used on the CLI and in execute (default: the base URL in reverse-DNS form, e.g. com.github.api). | | --name | Human-friendly name (default: spec info.title). | | --base-url | Override the base URL (otherwise derived from the spec's document-, path-, or operation-level servers). | | --docs | Documentation URL to store and surface (not parsed). | | --token | Store a bearer token. Read without echo from a TTY, or piped via stdin. | | --identifier | atproto: the account handle/email to authenticate as (not a secret). | | --app-password | atproto: store an app password now. Read without echo from a TTY, or piped via stdin. | | --oauth | Treat the API as OAuth 2.0 even if the spec doesn't declare it. | | --auth-url / --token-url | OAuth authorize / token endpoints (override the spec's values). | | --scope | Scope to request at login (repeatable; default: the spec's scopes). | | --scope-separator | Scope separator in the authorize URL (default " "; Strava uses ","). | | --no-auth | Register without authentication. | | --force | Overwrite an existing API with the same id instead of failing (e.g. to fix a wrong base URL). |
If the base URL can't be derived and would fall back to a raw spec-hosting host (e.g. raw.githubusercontent.com), add fails loudly instead of registering a broken base — pass --base-url with the real API origin.
OpenAPI specs that declare an OAuth 2.0 authorization-code flow are detected automatically: the API is registered as oauth2, and you run [login](#login-id-options) once to authenticate (see [OAuth](#oauth-apis)).
# bearer auth, prompted without echo:
anyapi-mcp add https://api.github.com/openapi.json --token
# bearer auth, piped (CI):
echo "$GITHUB_TOKEN" | anyapi-mcp add --token
# no auth - id defaults to the reverse-DNS base URL (here: io.swagger.petstore3.api.v3):
anyapi-mcp add https://petstore3.swagger.io/api/v3/openapi.json
# OAuth is auto-detected from the spec; just add, then `login`:
anyapi-mcp add https://developers.strava.com/swagger/swagger.json --id com.strava.api
# graphql - introspect an endpoint (id: com.trevorblades.countries):
anyapi-mcp add https://countries.trevorblades.com/ --kind graphql
# soap - read a public WSDL pointing at a live service:
anyapi-mcp add "http://www.dneonline.com/calculator.asmx?WSDL" --kind soap
# atproto - anonymous public reads (no login), via the public AppView:
anyapi-mcp add https://public.api.bsky.app --kind atproto --id bsky-public
# atproto - register your account to post / read private data (PDS + login):
anyapi-mcp add https://bsky.social --kind atproto --id bsky --identifier you.bsky.social
anyapi-mcp login bsky # prompts for an app password (no echo)
list
Lists registered APIs with id, name, base URL, operation count, and auth kind. For OAuth APIs it also shows live login status and token expiry (e.g. oauth2 (logged in, expires in 5h) or oauth2 (not logged in)).
regenerate [id ...]
Rebuilds the generated client code (typed .d.ts/client module + operation index) for registered APIs by re-fetching each one's saved source. With no id it does all of them; pass ids to target specific APIs, or --stale-only to rebuild just those whose code predates the current build.
This only refreshes generated code: saved credentials and OAuth config are left untouched (bearer tokens, OAuth client credentials, and login state all survive; baseUrl and the host allowlist are preserved too). Run it after upgrading anyapi-mcp so cached code matches the new generators - though serve also does this automatically (see below), so you rarely need to run it by hand. Each API is independent: if one source can't be re-fetched, the rest still regenerate and that API keeps its existing (working) code.
login [options]
Authenticates an OAuth 2.0 API in the browser (see [OAuth](#oauth-apis)). Stores the OAuth app credentials in the keystore (the client secret is read without echo, like add --token), opens the provider's consent page, captures the redirect on a local one-shot callback server, and saves the resulting tokens (which then refresh automatically). Re-running it re-authenticates.
| Option | Description | | ---------------------------- | --------------------------------------------------------------------------- | | --client-id | OAuth app client id (required on first login). | | --client-secret | Client secret (omit to be prompted without echo; or pipe via stdin). | | --scope | Scope to request (repeatable; default: the API's configured scopes). | | --scope-separator | Scope separator in the authorize URL (default " "; Strava uses ","). | | --redirect-uri | Local callback URL to listen on (default http://localhost:9876/callback). | | --port | Shortcut to set the callback port (host localhost, path /callback). | | --auth-url / --token-url | Override the stored authorize / token endpoint. | | --no-browser | Print the authorize URL instead of opening a browser (headless/SSH). |
logout [--forget-client]
Removes the stored OAuth tokens for an API (it stays registered). By default the OAuth app credentials are kept so the next login needs no flags; --forget-client removes those too.
remove
Removes the registry entry, deletes stored secrets from the keystore (bearer token, or OAuth client credentials + tokens), and cleans up cached files.
serve
Runs the stdio MCP server. It re-reads the registry on each call (so newly registered APIs are picked up without a restart). On startup, if the build's codegen version has changed since an API's code was generated (i.e. you upgraded anyapi-mcp), it regenerates that API's code first - the same work as regenerate, limited to stale entries, with credentials preserved and any re-fetch failure logged but non-fatal. It exposes:
search-{ query, api? }→ compact operation matches (api,method,
path, operationId, summary, params, requestBodyHint). Each param also carries a description and its allowed enum values when the spec provides them, so the model can pick valid arguments without a failed call.
execute-{ api, code, check?, timeoutMs? }→ runscodeagainst a
typed client and returns { stdout, stderr, exitCode } verbatim. For OAuth APIs the access token is refreshed automatically first; if the API isn't authenticated, the result explains how to fix it (call authenticate, or run anyapi-mcp login). check:false skips type-checking for one run (use when a stale spec enum rejects a value the live API still accepts); timeoutMs raises the 30s default (capped at 120s) for long or paginated runs.
authenticate-{ api }→ opens the user's browser to (re-)authenticate
an OAuth API and stores the tokens. Lets the model recover from an expired or revoked session without leaving the chat. It never accepts secrets — the user must have run anyapi-mcp login once to set up the OAuth app credentials.
configure_oauth-{ api, scopes?, scopeSeparator?, extraAuthParams? }
→ lets the model fix OAuth provider quirks it discovers (wrong scope set, comma-vs-space separator, an extra authorize param like access_type=offline). It only touches safe request params — never the authorize/token endpoints (those carry the client secret and stay CLI-only), and reserved params like redirect_uri/client_id are rejected. Call with just { api } to read the current config.
add_api-{ specUrl, kind?, id?, name?, baseUrl?, docsUrl?, force? }→
registers a new API (kind openapi, graphql, or soap) so the model can self-serve public APIs. Secrets are not accepted here; for authenticated APIs use anyapi-mcp add … --token (bearer) or anyapi-mcp login (OAuth) so the secret goes to the OS keychain, not the conversation. force:true overwrites an existing id in place (e.g. to correct a wrong baseUrl) instead of failing; an OAuth API stays logged in across the overwrite.
list_apis-{}→ the registered APIs as JSON (id, name, kind, baseUrl,
operation count, auth/login status, docsUrl). Lets the model see what's available and confirm an add_api/remove_api took effect mid-session.
remove_api-{ api }→ unregisters an API: removes its entry, deletes
any stored secrets from the keychain, and cleans up its cached types and ops index. The model's own way to clean up a mistaken registration.
The server also sends MCP instructions at connect time describing the workflow, and - when the registry is empty - exactly how to register an API.
OAuth APIs
Many user-facing APIs (Strava, Google, GitHub, …) use OAuth 2.0. anyapi-mcp supports the authorization-code flow end to end:
- Add the API. OpenAPI specs that declare an authorization-code flow are
detected automatically (anyapi-mcp add registers it as oauth2). For sources that don't declare one, pass --oauth --auth-url … --token-url ….
- Create an OAuth app with the provider and set its redirect/callback URL
to the one add/login prints (default http://localhost:9876/callback). You get a client id and client secret.
- Log in once:
``sh anyapi-mcp login com.strava.api --client-id --client-secret \ --scope read --scope activity:read_all ` This opens your browser, you approve, and the tokens are stored in the OS keychain. The access token then **refreshes automatically** before each execute` — you don't log in again until you revoke access.
From then on the model just calls search/execute as usual. If a session can't be refreshed (e.g. you revoked the app), the model can call the authenticate tool to re-open the browser login — no secrets pass through the conversation, since the client credentials are already in the keychain.
A small built-in quirks table fixes well-known providers whose specs are wrong or non-standard — e.g. Strava's spec lists /api/v3/oauth/* (the live endpoints are /oauth/*) and Strava wants comma-separated scopes. For anything else, the registry entry is the override (it's what every refresh reads): anyapi-mcp login --auth-url/--token-url/--scope-separator/--scope writes the corrected values onto it. The model can also fix the safe params it discovers (scopes, scope separator, extra author
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: gabrielbauman
- Source: gabrielbauman/anyapi-mcp
- License: Apache-2.0
- Homepage: https://gabrielbauman.github.io/anyapi-mcp/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.