MCP: OpsBlu for agents
One streamable-HTTP MCP server at https://opsblu.com/mcp, authenticated with the same API key as REST. Six tools that mirror the REST
endpoints. Aggregates and search are free; the agent pays credits only when it opens a record.
Transport: streamable HTTP (JSON-RPC 2.0, stateless, no SSE). Free tools work without a key; billed tools return an error asking for one. If your client insists on OAuth rather than a static header, use the REST API for now.
Connect
Pick your client. Sign in to see your key filled in.
{
"mcpServers": {
"opsblu": {
"type": "http",
"url": "https://opsblu.com/mcp",
"headers": {
"Authorization": "Bearer ob_live_YOUR_KEY"
}
}
}
}Claude Desktop → Settings → Developer → Edit Config. Claude Code: `claude mcp add --transport http opsblu https://opsblu.com/mcp --header "Authorization: Bearer ob_live_YOUR_KEY"`
Sign in to see your key filled in. Connecting adds 750 free credits.
Claude Desktop
- Settings → Developer → Edit Config. This opens
claude_desktop_config.json. - Add the
opsbluentry from the Claude tab above undermcpServers. - Restart Claude Desktop. The hammer icon lists the six tools.
Claude Code
claude mcp add --transport http opsblu https://opsblu.com/mcp \
--header "Authorization: Bearer ob_live_YOUR_KEY" Add --scope project to share it via .mcp.json (keep the key in an env var: --header "Authorization: Bearer $OPSBLU_KEY").
ChatGPT
- Settings → Connectors → Advanced → enable Developer mode.
- Create a connector: name OpsBlu, MCP server URL
https://opsblu.com/mcp, authentication: API key in header, headerAuthorization: Bearer ob_live_…. - In a chat, open the + menu and enable the OpsBlu connector.
Cursor
Cursor Settings → MCP → Add new server, or drop the Cursor tab's JSON into .cursor/mcp.json in your project.
Any MCP client
- Transport: streamable HTTP (POST JSON-RPC to
/mcp; SSE for server-initiated messages). - Header:
Authorization: Bearer ob_live_…(orX-API-Key). - Protocol: MCP 2025-06-18.
tools/listreturns the six tools with JSON Schemas identical to the REST query/body shapes.
Tools
| Tool | Cost | Input | Output | REST twin |
|---|---|---|---|---|
territory_stats | Free | state, city?, category? — or geojson polygon, categories? | Stats: total, depth (phones, websites, emails, ads, cwv_fail, no_website, new_90d), categories, platforms, tracking, new_by_month. Never names or coordinates. Counts <5 suppressed. | GET /v1/stats · POST /v1/stats/polygon |
search_businesses | Free | Filters: state, city, zip, category, q, no_website, cwv_fail, platform, has_ads, has_analytics, server_side, new_days, changed_days, has_phone, has_email, hot, cursor, limit | items[] of {id, name, category, city, state, signals, has_phone, has_email, has_website, platform, revealed}, total, next_cursor, estimate {records, hot_records, credits, usd} | GET /v1/businesses |
get_business | 3 credits · 10 if hot | id | Full record (address, phone, emails, website, web.cwv/seo, marketing, signals) + credits_used + balance_remaining | GET /v1/businesses/{id} |
get_changes_since | Free list | since (RFC 3339), territory_id? or state/city/category, types? | events[] of {type, at, business summary}. Opening a record is a get_business call. | GET /v1/changes |
enrich_domain | Free (report card) | url or domain | Report card: cwv_mobile, cwv_desktop, seo, platform, tech_stack, marketing, tracking_health, peer comparison | POST /v1/report-card → GET /v1/report-card/{id} |
watch_territory | Free | name, kind (city|zip|polygon), state/city/zip or geojson, alerts {email, slack_webhook, webhook, types, cadence} | Territory {id, …}. Use its id in get_changes_since. | POST /v1/territories |
Full field definitions are in the REST schemas. Tool outputs are the REST JSON, verbatim.
Auth, limits, caps
- Keys come from /app/api-keys. Creating your first key grants the +750 connect bonus (business email accounts).
- Per-key spend cap: set it when you create the key. The agent cannot spend past it; it gets
402 spend_capand a message it can read. - Account spend cap: /app/billing. Applies on top of any key cap. "Your agent can't run away with your card."
- Rate limits: ~120 calls/min per key for free tools; paid tools are naturally limited by credits. On
429the response includesretry_afterseconds. - Revoke a key any time; in-flight sessions fail with
401 auth_invalid.
How credits surface to the agent
Every paid tool result carries credits_used and balance_remaining, and every search result carries an estimate. A well-prompted agent reads them before spending:
{
"total": 91,
"items": [ { "id": "ob_por_lan_0012", "name": "…", "signals": { "no_website": true, "hot": false }, "has_phone": true, "revealed": false } ],
"estimate": { "records": 91, "hot_records": 7, "already_revealed": 0, "credits": 322, "usd": 3.22 }
} { "record": { "id": "ob_por_lan_0012", "phone": "(503) 555-0199", "emails": [], "website": "", "signals": {…} },
"credits_used": 3, "balance_remaining": 925, "already_revealed": false } Opening the same record again in the same calendar month returns credits_used: 0 and already_revealed: true.
Prompting tips
- Aggregates first. "Run territory_stats before searching, and tell me the count before you open anything."
- Reveal only what you will contact. "Open at most 10 records, prefer ones with has_email = true."
- Make the budget explicit. "Stop if balance_remaining would drop below 500."
- Use the signals as the pitch. cwv_fail, no_website and ads_no_tracking are the first sentence of the outreach email.
- Use territories for recurring work. One watch_territory call, then get_changes_since every morning. See the morning check recipe.