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
min_quality 0–100 minimum quality score; servers that are not scored are left out
quality_flags comma list every listed quality flag must be present
exclude_quality_flags comma list any listed quality flag excludes a server, e.g. known-vulns
owner_verified true | false true keeps only servers whose owner proved control of the namespace (not an audit)

Hybrid search: tool-level and server-level keyword and semantic candidates, fused by reciprocal rank, re-ranked by trust, grouped by server. A short query that names a publisher (stripe, github) puts that publisher’s own servers first, and a server whose title or name matches it next. Quality and a verified owner never change the order; filter on them instead. 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), quality_flags[], owner_verified, 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/dev.protogrid%2Fregistry/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), new_links (sites the definition names that the server never named before, see new sites), 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/dev.protogrid%2Fregistry/dependencies'

Pass or fail for one server against rules you choose, with every rule it broke, so an agent, a gateway or a pipeline applies one rule in one place. Name at least one rule; without any the answer is 400 no_rules.

rule type fails when
min_quality 0–100 the quality score is lower, or the server is not scored
min_trust 0–100 the trust score is lower, or not computed
no_fail comma list of check ids any of these checks fails, e.g. tools.hidden_text,stability.rug_pull; an unknown id is a 400 that lists the valid ones
exclude_quality_flags comma list any of these quality flags is raised
exclude_flags comma list any of these trust flags is raised
class comma list the connection class is not one of these
owner_verified true no owner proved control of the namespace

A blocked or deleted listing never passes. The answer is 200 whether the gate passes or not: pass, failed (each with rule and detail), the rules it applied, the server’s quality (score, label, flags), trust, class, owner_verified and tools_hash. Pin tools_hash to notice when the tools change after the gate passed.

Terminal window
curl -s 'https://api.protogrid.dev/v1/servers/dev.protogrid%2Fregistry/gate?min_quality=75&no_fail=tools.hidden_text&exclude_quality_flags=known-vulns,hidden-text'

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. With an API key, "fresh": true in the body runs a new check anyway (for CI right after a deploy); it counts against your hourly allowance, and a check of the same URL that has not finished yet is still returned. 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" }.