{
  "markdown": "# storebridge-mcp\n\nA remote **MCP (Model Context Protocol)** connector for [StoreBridge API](https://storebridge-api.vercel.app) — the unified Apple App Store + Google Play data API (search, app details, reviews, similar apps, charts, categories, developer portfolios, autocomplete, and a directional ASO keyword/rank suite).\n\n**Live:** `https://storebridge-mcp.vercel.app/mcp` (Vercel project `storebridge-mcp`, team `isaiahduprees-projects`) — 13 tools, verified against real production data. Since the upstream StoreBridge deployment is metered (RapidAPI/Apify), this connector authenticates its own outbound calls with the same Apify-actor bearer (`STOREBRIDGE_APIFY_BEARER`) and applies a soft per-IP rate limit (`STOREBRIDGE_MCP_RATE_LIMIT`, default 30 tool-calls/hour, in-memory) so the free MCP tier stays a discovery channel rather than an unmetered bypass of the paid listing — see `lib/ratelimit.js`.\n\n## What this is, and why it's a separate connector\n\nStoreBridge API is a plain REST API. Any HTTP client can already call it directly. This repo exists because **MCP clients (Claude, ChatGPT, and other MCP-aware agents) don't consume arbitrary REST APIs — they consume MCP tools.** `storebridge-mcp` is a thin adapter layer that:\n\n- Exposes each StoreBridge endpoint as a discoverable, typed MCP **tool** (name, description, zod input schema, annotations) that an LLM can reason about and call directly, instead of having to be taught the REST surface out-of-band.\n- Speaks the MCP **streamable-HTTP** transport at a single `/mcp` endpoint, so it can be registered as a connector in Claude, ChatGPT, or any other MCP client with one URL.\n- Does nothing else. It has no business logic of its own — every tool call is a pass-through `fetch` to StoreBridge, and the JSON response StoreBridge returns is handed back verbatim as the tool result.\n\n## Authentication: None (deliberate)\n\nUnlike this org's other MCP connectors (NotesBridge, GapRadar, EtsyOps, etc.), which require OAuth because they act on a signed-in user's private Mac/shop/account data, **StoreBridge's data has no per-user dimension at all** — it's public app-store metadata (listings, reviews, charts, developer pages). There is nothing to gate per-caller, so this connector intentionally ships with:\n\n- No OAuth, no login, no bearer tokens\n- No Supabase / database\n- No billing, no plans, no usage metering\n- No demo-vs-real account split — every caller gets the same real, live data\n\nThis makes the connector dramatically simpler than the org's OAuth-based connectors: `api/mcp.js` builds a fresh, stateless `McpServer` per request and serves it with zero auth checks.\n\n> **Known caveat (see below):** the *production* StoreBridge API deployment (`https://storebridge-api.vercel.app`) currently sits behind a RapidAPI proxy-secret guard on `/v1/*` (see \"Upstream auth caveat\"). That's an upstream deployment/monetization detail, not a reason to add auth to *this* connector — it just means the upstream base URL needs to be pointed at an open deployment (or the guard needs to be relaxed / the proxy secret injected server-side) before this connector's default config serves real production traffic end-to-end.\n\n## Tool list\n\nOne tool per StoreBridge endpoint (from `storebridge-api/openapi.yaml`):\n\n| Tool | StoreBridge endpoint | Description |\n|---|---|---|\n| `search_apps` | `GET /v1/search` | Search apps on Apple App Store, Google Play, or both. |\n| `get_apps_batch` | `GET /v1/apps` | Resolve an Apple app by bundle id, or batch-fetch many apps by comma-separated ids. |\n| `get_app` | `GET /v1/apps/{id}` | Full app details (description, version, rating histogram, screenshots, size, installs, etc). |\n| `get_app_reviews` | `GET /v1/apps/{id}/reviews` | Paginated reviews for an app. |\n| `get_similar_apps` | `GET /v1/apps/{id}/similar` | \"Customers also bought\" / related apps. |\n| `get_app_permissions` | `GET /v1/apps/{id}/permissions` | Google Play declared permissions (Google only). |\n| `get_app_datasafety` | `GET /v1/apps/{id}/datasafety` | Google Play \"Data safety\" section (Google only). |\n| `get_charts` | `GET /v1/charts` | Top-chart rankings (free/paid/grossing, by category). |\n| `get_categories` | `GET /v1/categories` | Category / genre list for a store. |\n| `get_developer` | `GET /v1/developers/{id}` | A developer's record plus their published apps. |\n| `autocomplete_suggest` | `GET /v1/suggest` | Autocomplete completions for a partial query. |\n| `get_aso_keywords` | `GET /v1/aso/keywords` | Directional keyword ideas + difficulty (estimated, from live search — not panel data). |\n| `get_aso_rank` | `GET /v1/aso/rank` | Point-in-time rank of an app across up to 20 keywords (estimated). |\n\nAll 13 tools are read-only and annotated `{ readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }` — none of them write anything, and all of them reflect live, externally-changing app-store data.\n\n(The build brief sketched ~9-10 illustrative tool names; StoreBridge's actual verified `openapi.yaml` surface has 13 GET endpoints, so this build maps 1:1 to all 13 rather than dropping three real ones to hit a round number.)\n\n## How it wraps storebridge-api\n\nEach tool handler does a plain `fetch(\\`${STOREBRIDGE_API_BASE_URL}${path}\\`, ...)` against the real StoreBridge REST API and returns the parsed JSON as MCP tool-result content:\n\n```js\n{ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }\n```\n\nUpstream HTTP errors (4xx/5xx) are caught and surfaced as a typed MCP error result via an `asError` helper rather than crashing the request.\n\n`STOREBRIDGE_API_BASE_URL` (env var) controls the upstream base URL. It defaults to `https://storebridge-api.vercel.app`.\n\n## Project layout\n\n```\napi/mcp.js       MCP endpoint (StreamableHTTPServerTransport, stateless, no auth)\napi/health.js    GET /api/health\nlib/tools.js     All 13 tool definitions (zod schemas + fetch-and-forward handlers)\nlocal-server.js  Plain-Node http server for local dev / smoke testing (not deployed)\ntest/smoke.mjs   Real end-to-end smoke test (initialize, tools/list, tools/call)\nvercel.json      Routes /mcp -> api/mcp.js, /health -> api/health.js\n```\n\nThere is no `.well-known` / OAuth-metadata surface in this repo on purpose: the 401 + `WWW-Authenticate: Bearer resource_metadata=...` dance and `/.well-known/oauth-protected-resource` / `/.well-known/oauth-authorization-server` endpoints in this org's other connectors exist purely to support the OAuth discovery flow. An MCP streamable-HTTP server with no auth has nothing for a client to discover or authorize — it just accepts POST requests. Skipping OAuth metadata entirely is correct here, not an oversight.\n\n## Local development\n\n```bash\nnpm install\nnpm run dev          # starts local-server.js on http://localhost:3900\n```\n\nEndpoints locally: `POST http://localhost:3900/mcp`, `GET http://localhost:3900/health`.\n\nTo point at a self-hosted / open StoreBridge instance instead of production (useful while the production RapidAPI guard is active — see below):\n\n```bash\nSTOREBRIDGE_API_BASE_URL=http://localhost:8080 npm run dev\n```\n\n## Smoke test\n\n```bash\nnpm run dev &                 # terminal 1\nnpm run smoke                 # terminal 2\n```\n\n`test/smoke.mjs` drives the running server over real HTTP/JSON-RPC and verifies:\n\n1. `GET /health` returns `{ ok: true, ... }`\n2. `initialize` succeeds and reports `serverInfo.name === \"storebridge\"`\n3. `tools/list` returns all 13 tools with their zod-derived JSON schemas\n4. `tools/call` for `search_apps` with `{ term: \"notes\", store: \"apple\", limit: 3 }` returns real app results fetched live (not mocked)\n\n## Upstream auth caveat (read before deploying)\n\nWhile building this, I read `storebridge-api`'s own `server.js` / `src/guard.js`: the **production** deployment gates every `/v1/*` route behind a RapidAPI proxy-secret (`rapidApiGuard`), and only opens up when `RAPIDAPI_PROXY_SECRET` is unset (self-host/dev mode). That means, as currently deployed, `https://storebridge-api.vercel.app/v1/search?...` returns `403 forbidden` without a valid `X-RapidAPI-Proxy-Secret` header — it is not actually open on the live URL today, even though the data itself is public information (app-store listings) and the long-term intent (per the org's product line) is a fully public, keyless API.\n\nThis doesn't change the architecture of *this* connector — `storebridge-mcp` still has zero auth of its own, by design, because there's no per-caller state to protect. It does mean that before `storebridge-mcp`'s default `STOREBRIDGE_API_BASE_URL` (the production URL) will serve real traffic end-to-end, one of the following needs to happen upstream:\n\n- Deploy an open (no `RAPIDAPI_PROXY_SECRET`) StoreBridge instance for this connector to point at, or\n- Relax the guard for a `/v1/*` traffic class that isn't going through RapidAPI, or\n- Have this connector inject a server-side RapidAPI proxy secret / Apify bearer on outbound requests (would need `RAPIDAPI_PROXY_SECRET` or `APIFY_BEARER` added as an env var here and forwarded as a header in `lib/tools.js`'s `callStoreBridge`).\n\nThe smoke test in this repo proves the MCP protocol plumbing and tool-calling mechanics end-to-end against a real, live, self-hosted StoreBridge instance (`node server.js` in the `storebridge-api` repo with no `RAPIDAPI_PROXY_SECRET` set — its guard is explicitly inert in that mode) fetching real Apple App Store data — see the smoke test output in the build report for the exact live response.\n\n## Deploy\n\nNot deployed yet (by design — verify first). Once verified:\n\n```bash\ncd /Users/isaiahdupree/Software/storebridge-mcp\nnpx vercel --yes --prod\n```\n\nAfter deploy, the MCP connector URL to register in Claude/ChatGPT/any MCP client is:\n\n```\nhttps://<deployment-domain>/mcp\n```\n",
  "bytes": 9788,
  "sha": "1f7460e3e8808aab830c22e366e7f9ed72eee403df34722ebe8da10970b08d06",
  "repo_slug": "isaiahdupree/storebridge-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_isaiahdupree_storebridge_mcp_b016d7d0/readme"
}