{
  "markdown": "# dribba\n\nOfficial SDK and CLI for the [Dribba](https://dribba.com) public API.\n\n**No API key, no OAuth, no account.** Every read endpoint is public. If you were\nlooking for the credentials page, there isn't one — see\n[dribba.com/auth.md](https://dribba.com/auth.md).\n\n- Reference: <https://dribba.com/docs>\n- Contract: <https://dribba.com/openapi.json> (OpenAPI 3.1)\n- Developer portal: <https://dribba.com/developers>\n\n## CLI\n\nNothing to install:\n\n```bash\nnpx dribba services --table\nnpx dribba cases --limit 3 | jq -r '.items[].slug'\nnpx dribba estimate --platforms ios,android --complexity complex\nnpx dribba ask \"flutter migration\"\nnpx dribba markdown /servicios\nnpx dribba --help\n```\n\nAdd `--sandbox` to hit the frozen fixtures instead of production.\n\n## MCP server (stdio bridge)\n\nDribba's MCP server is remote — Streamable HTTP at `https://dribba.com/mcp`. If\nyour client only speaks stdio, this package ships the bridge:\n\n```json\n{\n  \"mcpServers\": {\n    \"dribba\": { \"command\": \"npx\", \"args\": [\"-y\", \"dribba-mcp\"] }\n  }\n}\n```\n\n```bash\nnpx dribba-mcp            # product surface: 5 tools + llms.txt resources\nnpx dribba-mcp --docs     # documentation surface: 4 tools\n```\n\nIt forwards JSON-RPC and nothing else, so the tools, resources and protocol\nversion are whatever the server declares — there is no second implementation to\ndrift. If your client does speak Streamable HTTP, skip the bridge and point it\nstraight at the URL.\n\nVerified with the official `@modelcontextprotocol/sdk` over stdio: connect,\n`tools/list`, `tools/call`, `resources/list`, `resources/read`.\n\n## SDK\n\n```bash\nnpm i dribba        # JavaScript / TypeScript\npip install dribba  # Python 3.9+, same methods, also dependency-free\n```\n\nThe Python client lives in [`python/`](./python) and is published to PyPI as\n[`dribba`](https://pypi.org/project/dribba/).\n\n```js\nimport { Dribba } from \"dribba\";\n\nconst dribba = new Dribba();\n\nconst { items, total, next_cursor } = await dribba.services({ limit: 5 });\nconst study = await dribba.case(\"cityxerpa\");\nconst budget = await dribba.estimate({ platforms: [\"ios\", \"android\"] });\n\n// Whole collections, following the cursor for you\nfor await (const job of dribba.paginate(\"/api/v1/jobs\")) {\n  console.log(job.title);\n}\n```\n\n### Errors\n\nEvery 4xx/5xx throws a `DribbaError`. Branch on `code` — it is stable. `title`\nand `detail` are prose and may be reworded.\n\n```js\nimport { DribbaError } from \"dribba\";\n\ntry {\n  await dribba.service(\"nope\");\n} catch (error) {\n  if (error instanceof DribbaError && error.code === \"resource_not_found\") {\n    console.log(error.resolution); // what to do next, from the server\n  }\n}\n```\n\n### Rate limits\n\n120 requests per 60 seconds per IP. After any call, `dribba.rateLimit` holds what\nthe last response advertised, so you can self-throttle instead of provoking a\n429:\n\n```js\nawait dribba.company();\nconsole.log(dribba.rateLimit); // { limit: 120, remaining: 118, reset: 47 }\n```\n\n### Sandbox\n\nFrozen fixtures with production shapes. Useful because a test that asserts\n\"there are 9 services\" breaks the day we publish the tenth — against the sandbox\nit does not.\n\n```js\nconst sandbox = new Dribba({ sandbox: true });\nconst services = await sandbox.services(); // services.sandbox === true\n```\n\n### Idempotency\n\n`Idempotency-Key` on any POST. Same key and same body replays the stored\nresponse; same key with a different body is a 400.\n\n```js\nawait dribba.estimate(input, { idempotencyKey: crypto.randomUUID() });\n```\n\n### Markdown, and the async export\n\nAny page as markdown, and a one-request export of many pages:\n\n```js\nconst page = await dribba.markdown(\"/servicios\");\n\nconst job = await dribba.startExport([\"/\", \"/precios\", \"/servicios\"]);\nawait dribba.waitForExport(job.id);\nconst everything = await dribba.exportResult(job.id);\n```\n\nExport jobs live in one server instance's memory and expire after 15 minutes; a\n404 while polling means the request reached a different instance, not that the\nwork was lost.\n\n## Beyond the REST API\n\n- **MCP** — two remote servers over Streamable HTTP, no auth:\n  `https://dribba.com/mcp` (actions) and `https://dribba.com/docs/mcp` (docs).\n  See <https://dribba.com/developers/mcp>.\n- **Markdown of any page** — `Accept: text/markdown`, or append `.md`.\n- **The whole site** as an [OKF](https://dribba.com/okf) bundle.\n- **`/ask`** — NLWeb: a natural-language question, verbatim passages back.\n\n## Skills and the Agent Plugins manifest\n\nThis repo doubles as a portable [Agent Plugin](https://agent-plugins.org):\n\n```\nplugin.json          the manifest\nmcp.json             the two remote MCP servers\nskills/              seven SKILL.md files describing what dribba.com exposes\n```\n\nInstall the skills into your agent:\n\n```bash\nnpx skills add dribbaengineering/dribba\n```\n\n`skills/` is **generated** from what the site serves at\n`https://dribba.com/.well-known/agent-skills/`. Edit the site, not the copy — the\ncopy is what drifts.\n\n## Requirements\n\nNode 20+. Zero dependencies.\n\n## License\n\nMIT. The data behind the API is CC BY 4.0 — cite \"Dribba\" and link the source\nURL.\n",
  "bytes": 5070,
  "sha": "494d5b41679f5ca623df0c5964e024e0ff39a2393dc8f4c214cb088578bf3f2a",
  "repo_slug": "dribbaengineering/dribba",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_com_dribba_dribba_930426f3/readme"
}