Skip to content

REST API

Base URL: https://api.protogrid.dev (a local stack answers at http://localhost:8080). All responses are JSON and carry next_actions. Anonymous access is rate limited per IP (20 requests per minute); a free API key raises that to 60 per minute and 5,000 per day. The x-ratelimit-* and retry-after headers say when to back off. Server names are reverse-DNS (io.github.owner/name) and may be given URL-encoded (io.github.owner%2Fname) or with the literal slash.

param type notes
q string, required intent in plain words, 1–500 chars
limit 1–50 default 10
class comma list R0,R1,R2,L0,unknown
transport streamable-http | sse keeps servers with a non-templated remote of that transport
category string one of the fixed taxonomy ids
min_trust 0–100
flags comma list every listed trust flag must be present
exclude_flags comma list any listed flag excludes a server, e.g. multi-version-spam,duplicate-repo

Hybrid search: tool-level and server-level keyword and semantic candidates, fused by reciprocal rank, re-ranked by trust, grouped by server. mode says hybrid or keyword (fallback when no embedding model is loaded).

Result fields: name, title, description, connection_class, autonomous, human_steps, categories, trust_score, trust_flags[], quality_score, quality_label (see quality labels), tool_count, score, matched_tools[] {name, description}.

The descriptor. ?schemas=true includes tool input/output schemas. 404 when unknown.

Current tools with full schemas, ordered by name. limit (1–100, default 100), cursor (the next_cursor of the previous page).

{ "server": "…", "count": 100, "tools": [{ "name": "…", "description": "…", "input_schema": { }, "output_schema": null, "annotations": { }, "source": "probe", "observed_at": "…" }], "next_cursor": "…", "next_actions": [ ] }

target = mcpServers (default) | vscode | cursor | claude-code-cli | codex-toml | gemini | goose.

Returns server, key (the config key, last segment of the name), kind (remote | package | bundle), class, autonomous, human_steps, target, content_type (application/json for config objects, text/plain for the CLI, TOML and YAML targets), connection, secrets[] {name, where}, and for remotes auth_type and oauth metadata when known.

status when
403 blocked on the blocklist
410 deleted deleted from the official registry
409 no_connection no usable remote or package

Examples per target:

# claude-code-cli
claude mcp add --transport http agentdm https://api.agentdm.ai/mcp/v1/grid --header "Authorization: ${AGENTDM_TOKEN}"
# codex-toml
[mcp_servers.agentdm]
url = "https://api.agentdm.ai/mcp/v1/grid"
env_http_headers = { "Authorization" = "AGENTDM_TOKEN" }
// cursor
{ "mcpServers": { "docs-mcp": { "type": "http", "url": "https://tandem.ac/mcp" } },
"deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=docs-mcp&config=eyJ0eXBlIjoi…" }

The descriptor’s quality block (see quality score) plus history, the daily score for the last days (1–400, default 90), blocked (true when the listing is on the blocklist, whatever its score) and owner (the descriptor’s owner-verified block).

Terminal window
curl -s 'https://api.protogrid.dev/v1/servers/io.github.acme%2Facme-mcp/quality?days=30'

Tool-definition history, newest first: tool, kind (added, removed, changed), observed_at, fields (what changed), description_before and description_after when the description changed, description_similarity (share of words in common), and both definition hashes. limit (1–200, default 50) and before (the next_before of the previous page). A server’s first observation is a baseline and records nothing.

For each npm or PyPI package of the server: status (resolved, incomplete, unknown to the resolver, or pending), dependency_count, the official MCP SDK in the graph (mcp_sdk), and every known advisory with id, severity, summary, the affected package and version, relation (direct or indirect), fixed_in (the lowest published fix above that version, or null) and a url on osv.dev. Advisories are matched daily; graphs are read on each new release and refreshed monthly, daily for monitored servers (see Quality score); the attribution field carries the data credit.

Terminal window
curl -s 'https://api.protogrid.dev/v1/servers/io.github.acme%2Facme-mcp/dependencies'

Probes a remote MCP server URL once and reports its quality checks and its readiness for the Claude and OpenAI directories (see Check your server). Body { "url": "https://mcp.example.com/mcp" }; ?wait=N (0 to 25 seconds) holds the request until the result is in.

Terminal window
curl -s -X POST 'https://api.protogrid.dev/v1/check?wait=25' -H 'content-type: application/json' -d '{"url":"https://mcp.example.com/mcp"}'

The answer is 202 with status queued or running, a Location and retry-after while the probe runs, and 200 with status done and result once it finished. result holds probe (outcome, protocol, a summary of the OAuth metadata, the tools without schemas, redirects), quality (the same checks as the descriptor, stability na) and readiness (one entry per directory with every requirement, its status, detail and source). server names the catalog server when the URL is one of its remotes, and page is the shareable result page. The same URL within 5 minutes returns the recent check. A refused URL answers 400 invalid_url with a reason; an exhausted allowance answers 429 check_quota_exceeded with scope (you, host or global) and retry-after.

Reads a check; ?wait=N as above. Finished results never change and are cacheable for an hour; unknown ids answer 404. Results are kept 30 days and every check response carries X-Robots-Tag: noindex.

Every successful GET carries Cache-Control: public, max-age=…, stale-while-revalidate=… and a weak ETag; If-None-Match answers 304. Defaults: search 60 s, server descriptors, tools and connections 300 s, /v0.1 300 s. /mcp, /healthz, errors and non-GET responses are no-store. Cached responses do not carry the per-IP rate-limit headers; a 429 always does, with retry-after.

Validation errors answer 400 with { "error": "bad_request", "issues": { "fieldErrors": { … } } }. Unknown routes answer 404 { "error": "not_found" }. Rate limiting answers 429 with retry-after; an exhausted daily quota answers 429 daily_quota_exceeded, and a bad API key 401 invalid_api_key (see API keys and limits).

{ "ok": true, "search": "hybrid" | "keyword", "mcp": "/mcp" }.