Any-API MCP Server Template
A minimal, configurable Model Context Protocol (MCP) server you can use to adapt any HTTP API into an MCP toolset. It focuses on safety, clarity, and fast onboarding.
What You Get
- Generic HTTP tools:
api_probe,api_get,api_post,api_put,api_delete - Pluggable auth (header, bearer, basic, query param)
- Safe defaults: retries for GET only, rate-limit awareness (Retry-After), STDERR logging with redaction
- Zero-boilerplate startup via STDIO (MCP)
- TypeScript, strict mode, ESM
Quick Start
- Create a new repo and copy this template directory:
- Repo name suggestion:
mcp-any-api - Copy
templates/any-api-mcp/*into the new repo root
- Install and build
npm ci
npm run build
- Configure environment (two simple options)
Option A — API key/token you already have:
Create
.env.local(auto-loaded by scripts) with your API details:
API_BASE=https://api.example.com/v1
AUTH_MODE=bearer # one of: none|bearer|header|basic|query
AUTH_TOKEN=YOUR_TOKEN # bearer token or header value depending on mode
AUTH_HEADER=Authorization # used if AUTH_MODE=header (default Authorization)
AUTH_QUERY_KEY=api_key # used if AUTH_MODE=query
ALLOW_DESTRUCTIVE=false # guard writes
Option B — OAuth 2.0 (automated helpers):
Client Credentials (service-to-service):
TOKEN_URL=https://auth.example.com/oauth/token \
CLIENT_ID=... CLIENT_SECRET=... SCOPE="api.read api.write" \
npm run oauth2:client
This writes AUTH_MODE/AUTH_TOKEN into .env.local.
Device Code (user sign-in on a second device):
DEVICE_AUTH_URL=https://auth.example.com/oauth/device/code \
TOKEN_URL=https://auth.example.com/oauth/token \
CLIENT_ID=... SCOPE="api.read" \
npm run oauth2:device
Follow the printed verification URL and code. Upon success, the script updates .env.local.
4) Run in dev
```bash
npm run dev
- Add to your MCP client (example Claude Desktop)
{
"mcpServers": {
"any-api": {
"command": "node",
"args": ["/absolute/path/to/dist/server.js"],
"env": {
"API_BASE": "https://api.example.com/v1",
"AUTH_MODE": "bearer",
"AUTH_TOKEN": "YOUR_TOKEN",
"ALLOW_DESTRUCTIVE": "false"
}
}
}
}
Tools
api_probe(safe):- Inputs:
path(string),method(string), optionalheaders(record) - Executes a single request and returns status, content-type, body preview (first N bytes)
- Inputs:
api_get(safe):- Inputs:
path, optionalquery(record), optionalheaders - Retries on
429/502/503/504with backoff; honorsRetry-After
- Inputs:
api_post(guarded),api_put(guarded),api_delete(guarded):- Inputs:
path, optionalpayload(any), optionalheaders - DELETE supports optional payload if API expects a body
- Inputs:
All tools auto-join API_BASE with path and attach auth based on AUTH_MODE.
Auth Modes
none: no auth headerbearer:Authorization: Bearer <AUTH_TOKEN>header:<AUTH_HEADER>: <AUTH_TOKEN>basic:Authorization: Basic <AUTH_TOKEN>(you provide base64)query: appends?<AUTH_QUERY_KEY>=<AUTH_TOKEN>(or&when query exists)
Rate Limiting
- GETs retry on
429/502/503/504using exponential backoff with jitter Retry-Afterheader is honored when present- Scripts accept
PROBE_DELAY_MSto pace probes
Examples
Probe a path safely:
{
"path": "/users",
"method": "OPTIONS"
}
GET with query:
{
"path": "/search",
"query": { "q": "widgets", "page": 2 }
}
POST (guarded):
{
"path": "/widgets",
"payload": { "name": "Example", "price": 100 }
}
Customizing
- Add typed, domain-specific tools by creating new handlers in
src/server.ts - Keep
ALLOW_DESTRUCTIVE=falseuntil you’re ready to allow writes - To support OAuth2 flows, fetch tokens outside the server and set
AUTH_MODE=bearerwithAUTH_TOKEN
Scripts
npm run validate:endpoints(safe): probes a set of paths/methods via GET/OPTIONS; pacing + Retry-After; dynamic delay adaptationnpm run probe:get(safe): throttled GET probe for a given listnpm run discover:openapi(safe): tries common OpenAPI/Swagger URLs, lists endpoints/methods, and saves raw specnpm run scan:wordlist(safe): OPTIONS-scan using a small default wordlist or a provided file; dynamic delay adaptationnpm run inventory:api(safe): one-command inventory; tries OpenAPI first, then wordlist; writes JSON toreports/npm run openapi:to:tools(safe): converts an OpenAPI JSON file totools.jsonfor dynamic tool registrationnpm run scan:to:tools(safe): converts a wordlist scan report totools.jsonnpm run oauth2:client/npm run oauth2:device: obtain OAuth tokens and update.env.local
Environment knobs:
PROBE_DELAY_MS: pacing between requests (default 800–1500ms)OUTPUT/OUTPUT_DIR: where to save reportsWORDLIST: path to a custom wordlist (forscan:wordlist)
All scripts auto-load .env.local.
Dynamic Tools (No Code Changes)
This server auto-registers tools from tools.json (if present in the working directory). You can generate tools.json from discovery output:
From OpenAPI:
OPENAPI_FILE=reports/openapi_*.json TOOLS_FILE=tools.json npm run openapi:to:tools
From wordlist scan:
SCAN_FILE=reports/wordlist_*.json TOOLS_FILE=tools.json npm run scan:to:tools
Once tools.json exists, restart the server and the generated tools are available automatically. GET tools are safe; mutating tools are guarded (require ALLOW_DESTRUCTIVE=true).
Example: Hexnode API
Use the provided example tools file and Hexnode credentials:
- Copy example to working tools file
cp templates/any-api-mcp/examples/hexnode.tools.json tools.json
- Configure Hexnode env in
.env.local(header auth)
API_BASE=https://<portal>.hexnodemdm.com/api/v1
AUTH_MODE=header
AUTH_HEADER=Authorization
AUTH_TOKEN=<your-hexnode-api-key>
ALLOW_DESTRUCTIVE=false
- Start the server
npm run build && npm start
Note: Some Hexnode tenants use singular policy paths (/policy/…) and others plural (/policies/…). The example includes both; use whichever works for your tenant or remove non-applicable entries from tools.json.
File Layout
src/server.ts: MCP entrypointsrc/lib/*.ts: helpers (qs, retry, logger)scripts/*: verification probesdist/*: compiled output
License
Add your preferred license before public release.
