docs/mcp.md
Rama main · réplica de lectura del repositorio original.
# MCP server
DataBounty Community ships a real [Model Context Protocol](https://modelcontextprotocol.io) server — JSON-RPC,
OAuth 2.1 with PKCE, client ID metadata documents or dynamic client registration, API-key auth as an
alternative, and per-credential rate limiting. **46 tools.**
This is the intended path for agents. Large contributions use the website's
bulk-upload-review handoff: MCP creates the one-time link, then the contributor reviews parsed rows in the browser before submitting.
---
## Connecting
**Endpoint:** `POST/GET http://<dashboard-host>/mcp`
That is the *only* MCP endpoint. There is deliberately **no `/mcp/sse`** — it was removed on purpose, so
a client configured for it will hang rather than connect. Point at `/mcp`.
`apps/web` is the public MCP gateway and proxies `/mcp/*` plus the OAuth discovery documents through to
the API. Clients should use the dashboard origin; the API origin remains an internal implementation detail.
### Interactive — OAuth 2.1 + PKCE
For a client a person is driving (Claude Desktop, Claude Code, Cursor, Codex, Windsurf). The client
discovers, registers and redirects the person to approve scopes in their browser. **The client never
receives the password.**
**Discovery.** An unauthenticated request to `/mcp` answers `401` with a `WWW-Authenticate: Bearer`
header whose `resource_metadata` parameter points at the protected-resource document. From there the
client finds the authorization server. Both documents are served at the path-inserted spelling and at
the root fallback, so every client generation finds them:
```
/.well-known/oauth-protected-resource/mcp # path-inserted (preferred)
/.well-known/oauth-authorization-server/mcp
/.well-known/oauth-protected-resource # root fallback
/.well-known/oauth-authorization-server
```
`MCP_PUBLIC_URL` is the public dashboard/MCP **origin** (`https://console.example.com`). A trailing `/mcp`
is tolerated and stripped, so a value copied from a client config still works.
**Client registration.** Two options, both accepted:
- *Client ID metadata document* (preferred) — the client's `client_id` is an `https` URL that serves its
own metadata (name, redirect URIs). Nothing to register in advance; the consent screen shows that host.
- *Dynamic client registration* — `POST /mcp/oauth/register`, for clients that do not publish a metadata
document.
**Authorization rules.** PKCE is mandatory and `S256` is the only accepted method. The `resource`
indicator (RFC 8707) is required on both the authorization and token requests and must name this MCP
server. Authorization responses carry `iss` (RFC 9207) so the client can reject a response from any other
issuer. Redirects to a loopback address are allowed for desktop and CLI clients, and the consent screen
says so explicitly, since the client name in that case comes from the client itself.
Endpoints: `POST /mcp/oauth/register` · `GET /mcp/oauth/authorize` · `POST /mcp/oauth/token` ·
`POST /mcp/oauth/revoke` · `GET /mcp/oauth/grants`.
**Credential lifetime and refresh recovery.** Access tokens last eight hours and refresh tokens last 30
days. When two desktop-client processes race to rotate the same refresh token, a token retired by a
successful rotation has a bounded 60-second recovery window: each caller receives a new working pair
instead of disconnecting the whole MCP server. This exception never applies to an explicit revoke or
account suspension. A stale replay is rejected and audited without destroying the current healthy
successor credential.
### Protocol versions
The server speaks both MCP transport eras over the same `/mcp` endpoint, so no client-side flag is needed:
- **Sessionful streamable HTTP** — `initialize`, then a server-issued `Mcp-Session-Id` header on every
request. This is what today's Claude Code, Codex and Cursor send.
- **Stateless (2026-07-28)** — no session; the client calls `server/discover` and names the method in an
`Mcp-Method` header on each request.
The negotiated version is echoed back in the response, so a client can confirm which path it is on.
The dashboard's **API & MCP** page has a ready-made config for each supported client — start there rather
than hand-writing one.
### Automation — API key
For unattended jobs. Issue a scoped key in the dashboard and send:
```
Authorization: Bearer db_live_sk_...
```
Keys are shown in full exactly once. Only a hash is stored, so a lost key is rotated, never recovered.
### Rate limits
Keyed **per credential**, not per IP — one noisy agent cannot throttle another on the same host or
behind the same NAT.
---
## Scopes
A tool runs only if the credential carries its scope. Grant the narrowest set that does the job.
| Scope | Tools | Grants |
|---|---|---|
| `public` | 6 | Browse pools, categories, stats, contracts, upload limits. No account needed. |
| `read` | 9 | Your own work: submissions, progress, karma, notifications, issues, file status. |
| `contribute` | 6 | Submit, revise, dispute, create an upload-review link, check its status. |
| `validate` | 5 | Claim audit windows, decide them, and list your own audits. |
| `artifact` | 7 | Prepare and complete uploads, list and delete your files. |
| `account` | 10 | Handle, onboarding, attribution preference, notification read-state, issue replies. |
| `sponsor` | 2 | Evidence for items in your own community request's pool; dispute an accepted item during the window. |
**`account` is deliberately separate from `contribute`.** A handle is your permanent public profile URL
and the name your dataset credit attaches to, so claiming one is its own consent decision rather than a
side effect of "submit work". An `account` credential still cannot verify an email, change a password,
or read admin surfaces.
---
## The 45 tools
### Discovery — `public`
| Tool | |
|---|---|
| `list_community_pools` | Active pools open for contribution, with dataset type, difficulty and karma per accepted item. |
| `get_pool` | One pool: contract summary, live progress, karma per accepted item. |
| `get_pool_contract` | The dataset type's schema, fields and verification requirements. **Read this in full before submitting.** |
| `list_dataset_categories` | Supported coding and benchmark categories. |
| `get_community_stats` | Public totals: pools, published datasets, accepted items, karma awarded. |
| `get_file_upload_limits` | Live byte limits (single vs multipart) **and** the item-count limits `submit_pool_items` enforces (`bulkThresholdItems`, `maxItemsPerRequest`). |
### Contributing — `contribute`
| Tool | |
|---|---|
| `submit_pool_items` | Submit up to the contract's live inline limit. Larger contributions use `create_upload_review_link`. **Validation runs asynchronously** — wait the returned recheck interval, then call `check_submission` once. Karma is awarded on final acceptance, never on submit. |
| `revise_submission` | Revise an item sent back for fixes. A fixed item that is then accepted still earns the pool's full per-item karma. |
| `dispute_submission` | Dispute a flagged verdict. |
| `list_my_submissions` | |
| `create_upload_review_link` | Draft upload-review link for bulk preview. |
| `get_upload_review_status` | Check what happened after handing off an upload-review link — still being reviewed, submitted, cancelled, or abandoned. |
### Checking your work — `read`
| Tool | |
|---|---|
| `check_submission` | Validation status and test outcomes, including the persisted-job recheck estimate. This is the polling tool after `submit_pool_items`. |
| `whoami` | Identity, handle, karma balance, ranks, live active-audit count against your validator cap, and your earned badges. |
| `get_karma_details` | Breakdown, tier ladder, progress to next tier. |
| `get_my_work_progress` | Contributions, accepted items, earned karma. |
| `get_file_status` · `get_file_processing_checks` | Scan verdict and processing results for a file you own. |
| `list_notifications` | |
| `get_issue` · `list_my_issues` | |
### Validating — `validate`
| Tool | |
|---|---|
| `list_audits` | Windows open to you, with item count and karma reward. Never includes your own submissions. |
| `claim_audit` | **Exclusive for 24 hours.** No other validator can claim or decide it while held. Required before `submit_decisions`. |
| `get_audit` | Details and items in a window. |
| `submit_decisions` | Your verdicts. Requires having claimed the window first. |
| `list_my_audits` | |
### Files — `artifact`
| Tool | |
|---|---|
| `prepare_file_upload` → `complete_file_upload` | Single-request upload. Use only when `sizeBytes` is under the limit `get_file_upload_limits` reports. |
| `prepare_large_file_upload` → `complete_large_file_upload` | Real chunked multipart — parallel and resumable, backed by the active storage driver. Supply every part number and ETag on completion. |
| `abort_large_file_upload` | Cancels an in-flight multipart upload and releases reserved parts. |
| `list_files` · `delete_file` | Artifacts owned by your account. |
Completion queues scanning and parsing as background jobs — a completed upload is not a processed file.
Check status before assuming it is usable.
### Account — `account`
| Tool | |
|---|---|
| `suggest_handles` | Confirmed-free suggestions, DB-checked and valid under the handle rules. |
| `get_handle_availability` | Validates and checks one handle; returns a reason when refused. |
| `claim_handle` | Claim your public handle. |
| `complete_onboarding` | |
| `resend_email_verification` | |
| `get_attribution_preference` · `set_attribution_preference` | Public-profile visibility and whether your name appears on published dataset credit. |
| `mark_notifications_read` | Mark one notification, or every notification, read. |
| `report_issue` · `reply_to_issue` | File and follow up on a support case. |
### Sponsoring — `sponsor`
For the person whose community request created the pool. Creating a request stays dashboard-only; these
tools manage one that already exists.
| Tool | |
|---|---|
| `get_sponsor_submission_evidence` | Per-stage evidence (dedupe, contamination, execution, LLM review, human audit) for submissions in a pool you own. Owner-only — a request you do not own returns nothing, not a partial view. |
| `dispute_accepted_submission` | Dispute an item that was accepted into your pool, while its dispute window is open. Routes to a handler; it never reverses the acceptance on its own. Outside the window it is refused. |
Handle rules are identical across MCP and REST: lowercase letters, digits and single interior hyphens,
3–20 characters, no leading/trailing/doubled hyphen, and not reserved. Reserved covers every landing
route name and impersonation-prone names — see [api.md](api.md#your-account--v1me).
---
## Working with it well
**Read the contract first.** `get_pool_contract` returns the exact field keys, roles and verification
requirements. Payload shape is per dataset type — there are 50 — so do not assume a shape from another
pool.
**Everything heavy is asynchronous.** Submit, wait the returned `recheckAfterSeconds`, then call
`check_submission` once. Upload, then follow the returned `get_file_status` interval. A tool returning
successfully means the work was *accepted for processing*.
**Karma is awarded on final acceptance only** — never for claiming or submitting — and is then held
through the dispute window before it lands.
**Trust states are honest, so read them.** A stage that was skipped, is unsupported, unconfigured or
stale says exactly that. `execution` with no sandbox key reports `no_provider_configured`; `llm` with no
key reports the same outcome, carrying `status: "pending_llm_review"` in its evidence detail. Neither means
passed — both route the item to a human. Treat any stage result that is not an explicit pass as not-passed.
**Claims expire.** An audit window is yours for 24 hours; walk away and it returns to the queue.
**You cannot review your own work.** Conflict-of-interest filtering is server-side, so `list_audits`
simply never offers you a window containing your submissions.