One config. Your database or your API, as MCP tools
Most MCP tutorials hand you a Node project. Install an SDK, write a tool handler, wire stdio — and you end up with something that runs on your laptop, as you, for exactly one user.
Fine for a demo. Not something you can give a customer.
The other way: describe the tool in config, deploy, point Claude at a URL.
api/tasks:
output: http
method: POST
mcp:
enabled: true
tool_name: list_tasks
actions:
- name: ValidateToken
input: a|headers|
assert:
http_code_on_error: 401
tests:
- value: airpipe-jwt
is_valid_jwt: a|ap_var::MCP_SECRET|
- name: ListTasks
run_when_succeeded: [ValidateToken]
database: main
query: |
SELECT id, title, status
FROM tasks
ORDER BY created_at DESC
LIMIT 200;
Verify the token, run the query. That's the tool.
Note what's missing: any MCP-specific auth. Air Pipe optionally takes the client's bearer token, forwards it into the interface, and runs the same actions an HTTP request would. Securing an MCP tool is securing a route.
The full file adds a CheckBody action — its assert tests become the tool's input schema and the OpenAPI request body. You describe the input once.
global:
databases:
main:
driver: postgres
conn_string: "a|ap_var::DATABASE_URL|"
a|ap_var::DATABASE_URL| is a managed variable, so the config you share carries no credentials.
Installing the pack is about one click: it finds every ap_var:: the config needs, prompts for the missing ones, then deploys to staging and gives you the URLs.
{
"mcpServers": {
"my-tasks": {
"url": "https://api.airpipe.io/<org>/<env>/mcp",
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}
Mint the token once at jwt.io — HS256, secret is your MCP_SECRET. Restart the client and the tool appears.
You also get an HTTP endpoint, OpenAPI docs, metrics and a trace per tool call. Same file, not a second project.
Swap the query for an HTTP call and the tool doesn't change shape:
- name: CallMyApi
http:
url: a|ap_var::MY_API_BASE|/v1/tasks
method: GET
bearer_auth: a|ap_var::MY_API_TOKEN|
Same token check, same schema, same tool. So the data can stay behind the service that already enforces your rules — which matters, because "we're not giving an AI our production database" is what usually kills this conversation.
tools/call runs your code. tools/list doesn't.
Listing tools returns metadata, so the auth inside your handlers never fires for it. Anyone with the URL can enumerate every tool and its full schema. They can't call anything. They can read the map.
One line per tool closes it:
list_authorizer: authorize-discovery
That points at an interface which re-runs the same token check when a client lists tools. No valid token, no tools — not even the names. I checked it end to end: no token and bad token both return an empty array; valid token returns the tools.
https://airpipe.io/marketplace/pack/mcp-quickstart
Four files. Install, set two variables, seed, paste the URL into your client.
Need per-customer isolation? MCP Postgres Starter is the same shape with tenant-scoped tokens and revocation: https://airpipe.io/marketplace/pack/mcp-postgres-starter/
You can hand-roll all this with the TypeScript SDK. You'll also hand-roll the auth, the tenant scoping, the discovery gate, the traces, and a REST API for whatever doesn't speak MCP. That's the trade.
Is tools/list open on your MCP server right now? Worth checking.
Air Pipe is on Peerlist if you want to look at the project or leave feedback:
0
1
0