Quickstart: Raw JSON-RPC
Pipeworx is an HTTP MCP gateway. Any client that can POST JSON-RPC 2.0 to a URL talks to it. No SDK required.
Working in a shell and have Node.js?
pipeworx callwraps these same calls so you can skip the envelope:npx pipeworx@latest call adzuna_search --country=us | jq.
Endpoint
https://gateway.pipeworx.io/mcp
Or scoped variants:
https://gateway.pipeworx.io/<pack>/mcp # one pack
https://gateway.pipeworx.io/mcp?task=... # task-scoped
https://gateway.pipeworx.io/mcp?vertical=... # vertical-scoped
List tools
curl -X POST https://gateway.pipeworx.io/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| jq '.result.tools[].name'
Call a tool
curl -X POST https://gateway.pipeworx.io/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "ask_pipeworx",
"arguments": { "question": "What is the US trade deficit with China?" }
}
}'
Real capture, trimmed — fred_get_series({series_id: "MORTGAGE30US"}) on the internal (paid-equivalent) tier used for verification:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "{\"series_id\":\"MORTGAGE30US\", ...}" }],
"structuredContent": { "series_id": "MORTGAGE30US", "series_title": "30-Year Fixed Rate Mortgage Average...", "observations": [...] },
"_meta": {
"tier": "paid",
"source": "fred",
"fetched_at": "2026-08-10T19:51:05.713Z",
"cost": { "total": 5, "components": [{ "name": "base", "credits": 5 }] }
}
}
}
Two things worth calling out that the previous version of this page didn’t mention:
result.structuredContent— the same data ascontent[0].text, already parsed. Read this instead ofJSON.parse-ing the text block._meta.rateLimit({ limit, remaining, resetAt }) is added for every tier exceptpaid— confirmed inshared/src/responses.ts’sbuildMeta(); not shown above because paid/unlimited accounts have nothing to report against a cap._meta.cache({ hit, ttl_seconds, fresh_until }) is present when the tool result is cacheable;_meta.source/fetched_at/costare always present on a successful call.
On an error, _meta carries examples, alternatives, and retry_hint/feedback_hint instead — see error recovery. One exception: an unknown tool name comes back as a bare JSON-RPC -32602 error with no _meta at all — the name is what failed, so there’s nothing to retry-hint; call discover_tools({task}) to find the real name.
Other MCP methods
| Method | Purpose |
|---|---|
initialize | Returns server capabilities + instructions (read these — they tell agents how to use Pipeworx best) |
tools/list | List tools (with inputSchema.examples and outputSchema) |
tools/call | Invoke a tool |
resources/templates/list | List pipeworx:// URI patterns |
resources/read | Fetch a pipeworx://... resource |
prompts/list | List server-side prompt playbooks |
prompts/get | Get a prompt with arguments substituted |
Authentication
| Tier | How |
|---|---|
| Anonymous (50/day) | No auth |
| BYO key (200/day) | X-API-Key: your-key header |
| Free account (200/day) | Authorization: Bearer <token> (GitHub OAuth signup at pipeworx.io) |
| Paid (unlimited) | Authorization: Bearer <token> (Stripe subscription) |
Pass tool-specific API keys
For paid data sources, pass your own key as a call argument — but the argument name is
per-tool, not a universal _apiKey. Check the tool’s inputSchema from tools/list
for the exact name. FRED and ATTOM read _apiKey; Altos reads _altosKey:
{
"name": "fred_get_series",
"arguments": {
"series_id": "MORTGAGE30US",
"_apiKey": "your-fred-api-key"
}
}
{
"name": "altos_market_stats",
"arguments": {
"region": "ca_94103",
"_altosKey": "your-altos-api-key"
}
}
Passing the wrong name (e.g. _apiKey for an Altos tool) is silently dropped as an
unrecognized argument — verified live: altos_market_stats with _apiKey set still
returns "Altos Research API key required... pass via _altosKey". Trust that
message, not the error’s signup_hint field — the generic signup_hint currently
says _apikey (lowercase, and wrong for Altos regardless of case) for every tool; see
error recovery for the full auth-error pattern. Any
argument starting with _ is treated as an injected credential and stripped before
analytics logging — this covers _apiKey, _altosKey, and every other per-tool key,
not just the generic one.
TypeScript shortcut: @pipeworx/sdk
If you’re in JS/TS, the SDK wraps all of this:
import { Pipeworx } from '@pipeworx/sdk';
const pw = new Pipeworx();
const result = await pw.call('fred_get_series', { series_id: 'MORTGAGE30US' });
npm install @pipeworx/sdk