Docs
Every item has the same parts: purpose, inputs, output, one example with its real output, errors. Example outputs were captured from https://api.lookupd.com; outputs longer than 40 lines are cut. Plain text: /docs.md.
Set up an agent with this line: Set up lookupd for me: read https://lookupd.com/agent.md and follow it.
On this page
- CLI: lookupd find
- CLI: lookupd telemetry
- CLI: lookupd login
- CLI: lookupd hooks
- CLI: lookupd mcp
- MCP: find_capability
- MCP: get_entry
- MCP: health
- MCP: report_outcome
- REST API: GET /v0.1/find
- REST API: GET /v0.1/entries/{name}
- REST API: GET /v0.1/entries/{name}/health
- REST API: GET /v0.1/servers
- REST API: GET /v0.1/servers/{serverName}/versions
- REST API: GET /v0.1/servers/{serverName}/versions/{version}
- REST API: POST /v0.1/events
- REST API: GET /v0.1/resolve
- REST API: GET /v0.1/version
- REST API: GET /v0.1/health
- REST API: GET /v0.1/ping
- REST API: POST /v1/registrations
- REST API: GET /v1/registrations/{id}
- REST API: POST /v1/registrations/{id}/verify
- REST API: GET /v1/registrations/{id}/analytics
CLI
The lookupd command, installed on demand with npx. Every example runs as written.
lookupd find
Find MCP servers for a task and print ranked candidates with install snippets.
Inputs
| name | type | required | meaning |
|---|---|---|---|
task | string (positional, one or more words) | yes | Short capability phrase, for example read Linear issues. |
--runtime | enum: claude-code | codex | claude-desktop | cursor | vscode | generic | no | Runtime that selects the install snippet. Default: detected from the environment. |
--limit | integer | no | Number of results to ask for (the API allows 1 to 10, default 5). |
--json | flag | no | Print the API response as JSON instead of a text list. |
Output
A ranked text list; with --json, the same JSON as GET /v0.1/find. Rankings are provisional.
Example
npx -y lookupd@latest find "read Linear issues" --limit 1 --json
Output of the example
{
"results": [
{
"name": "app.linear/linear",
"title": "Linear",
"description": "Find and manage issues, projects, and documents in your Linear workspace.",
"kind": "mcp_server",
"status": "active",
"version": "1.0.2",
"repositoryUrl": null,
"websiteUrl": "https://linear.app",
"transports": [
"streamable-http"
],
"install": [
{
"runtime": "claude-code",
"kind": "command",
"label": "remote (streamable-http)",
"value": "claude mcp add --transport http linear https://mcp.linear.app/mcp"
},
{
"runtime": "claude-code",
"kind": "command",
"label": "remote (streamable-http)",
"value": "claude mcp add --transport http linear https://mcp.linear.app/mcp/readonly"
}
],
"score": 2.8,
"summary": null,
"capabilityTags": [],
"health": {
"status": "auth_required",
"lastProbedAt": "2026-11-04T00:37:25.700Z",
"lastUpAt": "2026-11-04T00:37:25.700Z",
"uptime7d": 1,
"p50LatencyMs": null,
"toolsCount": null,
"toolsChangedAt": null
},
... (9 more lines)Errors
- usage: lookupd find <task...> (exit 1): no task given
- --runtime must be one of claude-code, codex, claude-desktop, cursor, vscode, generic (exit 1)
- lookupd: rate limited; retry in Ns (exit 1)
lookupd telemetry
Turn anonymous outcome reports on or off, or show the current setting and where it comes from. On by default from 0.2.0; DO_NOT_TRACK=1 or LOOKUPD_TELEMETRY=0 in the environment turns them off.
Inputs
| name | type | required | meaning |
|---|---|---|---|
mode | enum: on | off | status | yes | on lists report_outcome in the stdio bridge; off hides it; status prints the setting. |
Output
status prints on or off, then the source in parentheses: default, lookupd telemetry on|off, DO_NOT_TRACK or LOOKUPD_TELEMETRY. on and off print a one-line confirmation.
Example
npx -y lookupd@latest telemetry status
Output of the example
unset
Errors
- usage: lookupd telemetry on|off|status (exit 1): mode missing or unknown
lookupd login
Store an optional API key in ~/.config/lookupd/config.json. Lookups work without one.
Inputs
| name | type | required | meaning |
|---|---|---|---|
--key | string, lk_ followed by letters and digits | yes | The API key to store. |
Output
API key stored
Example
npx -y lookupd@latest login --key lk_YOUR_KEY
Output of the example
API key stored
Errors
- usage: lookupd login --key lk_<key> (exit 1): key missing or malformed
lookupd hooks
Install, remove or show the opt-in call hook in Claude Code (~/.claude/settings.json) or Codex (~/.codex/hooks.json). The hook runs after each MCP tool call and sends one call event: the server's registry name (resolved from the URL or package in your MCP config), the tool name, whether the call succeeded, your runtime, the client's session id and the lookup id when known. Never arguments, output, prompts or paths. It sends nothing while telemetry is off. Codex asks you to trust a new hook once with /hooks.
Inputs
| name | type | required | meaning |
|---|---|---|---|
action | enum: install | remove | status | yes | What to do. |
--client | enum: claude-code | codex | no | Whose hook file to edit; default claude-code. |
Output
install and remove print the file they changed and what the hook sends; status prints one line per client.
Example
npx -y lookupd@latest hooks status
Output of the example
claude-code: not installed (~/.claude/settings.json) codex: not installed (~/.codex/hooks.json)
Errors
- usage: lookupd hooks install|remove|status [--client claude-code|codex] (exit 1)
lookupd mcp
Serve lookupd's MCP tools over stdio by bridging to https://api.lookupd.com/mcp. MCP clients launch this command; you do not run it by hand.
Inputs
| name | type | required | meaning |
|---|---|---|---|
| none | |||
Output
No output of its own. It speaks MCP over stdin and stdout. The first run with the default telemetry setting prints a one-time notice to stderr.
Example
claude mcp add lookupd -- npx -y lookupd@latest mcp
Output of the example
(no output: the process serves MCP over stdio until the client closes it)
Errors
- The remote endpoint is unreachable: the bridge lists no remote tools until it connects
MCP
Four tools on the remote endpoint https://api.lookupd.com/mcp (streamable HTTP, no login). The stdio bridge (npx -y lookupd@latest mcp) serves the same tools.
find_capability
Find MCP servers that provide a capability for a task. Pass a short capability phrase, not the user's full request. Lookups are free.
Inputs
| name | type | required | meaning |
|---|---|---|---|
task | string, 1-200 characters | yes | Short capability phrase. |
kind | enum: mcp_server | no | Only mcp_server in this release. |
runtime | enum: claude-code | codex | claude-desktop | cursor | vscode | generic | no | Caller's runtime; selects the install snippet. |
verified_only | boolean | no | Only verified (registered) publishers. |
max_results | integer, 1-10 | no | Default 5. |
capability | enum: tag from lookupd's taxonomy | no | Capability tag to prefer, for example issue-tracking. |
session | string, 8-64 of A-Z a-z 0-9 _ - | no | The random id you make up once per conversation and repeat on every lookupd call in it, report_outcome included, so lookups and outcomes join up. Never derived from the user, project or machine. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
Output
JSON: results[] (name, install snippets, score, health, lookupd metadata incl. verification and publisher), featured[] (reserved for labeled placement; empty, since placement is not offered), ranking: provisional, and lookup_id (quote it on report_outcome so the outcome ties to this search).
Example
curl -s -X POST https://api.lookupd.com/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"find_capability","arguments":{"task":"read Linear issues","runtime":"generic","max_results":1}}}'Output of the example
{
"result": {
"content": [
{
"type": "text",
"text": "(the structuredContent below, as a JSON string)"
}
],
"structuredContent": {
"results": [
{
"name": "app.linear/linear",
"title": "Linear",
"description": "Find and manage issues, projects, and documents in your Linear workspace.",
"kind": "mcp_server",
"status": "active",
"version": "1.0.2",
"repositoryUrl": null,
"websiteUrl": "https://linear.app",
"transports": [
"streamable-http"
],
"install": [
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp\"\n }\n }\n}"
},
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp/readonly\"\n }\n }\n}"
}
],
"score": 2.8,
"summary": null,
"capabilityTags": [],
"health": {
... (21 more lines)Errors
- Invalid arguments: the tool result is an error naming the field
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
get_entry
Full details for one entry. Pass name, or url or package for a server already in your MCP config to find its registry name.
Inputs
| name | type | required | meaning |
|---|---|---|---|
name | string, 1-200 characters | no | Registry name, for example app.linear/linear. |
url | string, 1-500 characters | no | Remote URL from the MCP config. |
package | string, 1-200 characters | no | npm or PyPI package from the MCP config. |
runtime | enum: claude-code | codex | claude-desktop | cursor | vscode | generic | no | Runtime for install snippets. Default: generic. |
session | string, 8-64 of A-Z a-z 0-9 _ - | no | The random id you make up once per conversation and repeat on every lookupd call in it, report_outcome included, so lookups and outcomes join up. Never derived from the user, project or machine. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
Output
JSON: raw server.json, install snippets, lookupd metadata, and setup: what an agent needs to make it work (transports, runtime hints, environment variables and headers with required and secret flags, whether the endpoint needs a login, and the last 30 days of outcome reports: success rate and failure classes). When several entries launch the same url or package, matches lists them, most likely first. Also changes: the newest 10 things lookupd saw change on it (tools added, removed or schema-changed; version and description changes), newest first.
Example
curl -s -X POST https://api.lookupd.com/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_entry","arguments":{"name":"app.linear/linear"}}}'Output of the example
{
"result": {
"content": [
{
"type": "text",
"text": "(the structuredContent below, as a JSON string)"
}
],
"structuredContent": {
"entry": {
"name": "app.linear/linear",
"title": "Linear",
"description": "Find and manage issues, projects, and documents in your Linear workspace.",
"kind": "mcp_server",
"status": "active",
"version": "1.0.2",
"repositoryUrl": null,
"websiteUrl": "https://linear.app",
"transports": [
"streamable-http"
],
"install": [
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp\"\n }\n }\n}"
},
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp/readonly\"\n }\n }\n}"
}
],
"score": 0,
"summary": null,
"capabilityTags": [],
"health": {
"status": "auth_required",
... (77 more lines)Errors
- isError: No entry named <name>
- isError: Pass name, url or package
- isError: No entry launches <url or package>
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
health
Probe status of an entry: up, auth_required, down, dead, not_probeable or unprobed, with 7-day uptime, median latency, tool count and the last probe.
Inputs
| name | type | required | meaning |
|---|---|---|---|
name | string, 1-200 characters | yes | Registry name. |
session | string, 8-64 of A-Z a-z 0-9 _ - | no | The random id you make up once per conversation and repeat on every lookupd call in it, report_outcome included, so lookups and outcomes join up. Never derived from the user, project or machine. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
Output
JSON: name, status, lastSeenAt, health, lastProbe.
Example
curl -s -X POST https://api.lookupd.com/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"health","arguments":{"name":"app.linear/linear"}}}'Output of the example
{
"result": {
"content": [
{
"type": "text",
"text": "(the structuredContent below, as a JSON string)"
}
],
"structuredContent": {
"name": "app.linear/linear",
"status": "active",
"lastSeenAt": "2026-11-01T08:51:30.650Z",
"health": {
"status": "auth_required",
"lastProbedAt": "2026-11-04T00:37:25.700Z",
"lastUpAt": "2026-11-04T00:37:25.700Z",
"uptime7d": 1,
"p50LatencyMs": null,
"toolsCount": null,
"toolsChangedAt": null
},
"lastProbe": {
"startedAt": "2026-11-04T00:37:25.510Z",
"status": "auth_required",
"errorClass": "auth",
"httpStatus": 401,
"latencyMs": null
}
}
},
"jsonrpc": "2.0",
"id": 1
}Errors
- isError: No entry named <name>
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
report_outcome
After a task used an MCP server, report once per server whether it worked. Structured fields only; never task text, prompts or paths. The stdio bridge hides this tool when the user turned telemetry off.
Inputs
| name | type | required | meaning |
|---|---|---|---|
entry | string, 1-200 characters | yes | Registry name of the server that was used. |
success | boolean | yes | Whether the server did the job. |
capability_tag | enum: tag from lookupd's taxonomy | no | What the server was used for. |
latency_bucket | enum: lt1s | lt5s | lt30s | gte30s | no | How long the call took. |
runtime | enum: claude-code | codex | claude-desktop | cursor | vscode | generic | no | Caller's runtime. |
error_class | enum: auth | timeout | schema | tool_error | other | no | Why it failed, if it did. |
session | string, 8-64 of [A-Za-z0-9_-] | no | A random id the client makes up once per conversation and repeats on every report in it; never derived from the user, project or machine. |
step | integer >= 1 | no | Order in which this server was first used in the conversation. |
tool | string, 1-120 of [A-Za-z0-9_.-] | no | The tool used most on the server, by name. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
found_via | enum: lookupd | installed | no | Whether lookupd found the server or it was already installed. |
lookup_id | string, uuid | no | The lookup_id from the find response whose results led to this server, so the report ties to that exact search and the position the server was shown at. |
Output
JSON: accepted, ignored (unknown entry names are ignored), principal.
Example
curl -s -X POST https://api.lookupd.com/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"report_outcome","arguments":{"entry":"app.linear/linear","success":true,"latency_bucket":"lt1s","runtime":"generic"}}}'Output of the example
{
"result": {
"content": [
{
"type": "text",
"text": "(the structuredContent below, as a JSON string)"
}
],
"structuredContent": {
"accepted": 1,
"ignored": 0,
"principal": "anonymous"
}
},
"jsonrpc": "2.0",
"id": 1
}Errors
- Unknown fields are rejected, not dropped
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
REST API
Base URL https://api.lookupd.com. Lookups need no account. Limited endpoints: /v0.1/find, /v0.1/events and the MCP endpoint, 60 requests per minute per IP. Errors are RFC 9457 application/problem+json.
GET /v0.1/find
Find MCP servers for a task. Same engine as the find_capability tool.
Inputs
| name | type | required | meaning |
|---|---|---|---|
task | query string, 1-200 characters | yes | Short capability phrase. |
kind | enum: mcp_server | no | Only mcp_server in this release. |
runtime | enum: claude-code | codex | claude-desktop | cursor | vscode | generic | no | Selects the install snippet. |
verified_only | enum: true | false | 1 | 0 | no | Only verified (registered) publishers. |
limit | integer | no | Results to return; clamped to 1-10, default 5. |
capability | enum: tag from lookupd's taxonomy | no | Capability tag to prefer. |
session | string, 8-64 of A-Z a-z 0-9 _ - | no | The random id you make up once per conversation and repeat on every lookupd call in it, report_outcome included, so lookups and outcomes join up. Never derived from the user, project or machine. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
X-Lookupd-Install | header, uuid | no | The CLI's random install id, sent while telemetry is on (rotate it with lookupd telemetry reset), so repeat use can be counted. Never required. |
Output
200 JSON: results[] (organic; lookupd.verification and lookupd.publisher per result), featured[] (reserved for labeled placement; empty, since placement is not offered), ranking: provisional, and lookup_id (quote it in the outcome event so it ties to this search).
Example
curl -s "https://api.lookupd.com/v0.1/find?task=read%20Linear%20issues&limit=1"
Output of the example
{
"results": [
{
"name": "app.linear/linear",
"title": "Linear",
"description": "Find and manage issues, projects, and documents in your Linear workspace.",
"kind": "mcp_server",
"status": "active",
"version": "1.0.2",
"repositoryUrl": null,
"websiteUrl": "https://linear.app",
"transports": [
"streamable-http"
],
"install": [
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp\"\n }\n }\n}"
},
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp/readonly\"\n }\n }\n}"
}
],
"score": 2.8,
"summary": null,
"capabilityTags": [],
"health": {
"status": "auth_required",
"lastProbedAt": "2026-11-04T00:37:25.700Z",
"lastUpAt": "2026-11-04T00:37:25.700Z",
"uptime7d": 1,
"p50LatencyMs": null,
"toolsCount": null,
"toolsChangedAt": null
},
... (9 more lines)Errors
- 400 application/problem+json with detail naming the bad field
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
GET /v0.1/entries/{name}
Full details for one entry. The name contains one slash and goes in the path as is.
Inputs
| name | type | required | meaning |
|---|---|---|---|
name | path, registry name | yes | For example app.linear/linear. |
runtime | enum: claude-code | codex | claude-desktop | cursor | vscode | generic | no | Query string; selects install snippets. Default: generic. |
session | string, 8-64 of A-Z a-z 0-9 _ - | no | The random id you make up once per conversation and repeat on every lookupd call in it, report_outcome included, so lookups and outcomes join up. Never derived from the user, project or machine. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
Output
200 JSON: raw server.json, install snippets, lookupd metadata, setup facts and changes (as get_entry).
Example
curl -s "https://api.lookupd.com/v0.1/entries/app.linear/linear"
Output of the example
{
"entry": {
"name": "app.linear/linear",
"title": "Linear",
"description": "Find and manage issues, projects, and documents in your Linear workspace.",
"kind": "mcp_server",
"status": "active",
"version": "1.0.2",
"repositoryUrl": null,
"websiteUrl": "https://linear.app",
"transports": [
"streamable-http"
],
"install": [
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp\"\n }\n }\n}"
},
{
"runtime": "generic",
"kind": "config",
"label": "remote (streamable-http) → your MCP client config",
"value": "{\n \"mcpServers\": {\n \"linear\": {\n \"url\": \"https://mcp.linear.app/mcp/readonly\"\n }\n }\n}"
}
],
"score": 0,
"summary": null,
"capabilityTags": [],
"health": {
"status": "auth_required",
"lastProbedAt": "2026-11-04T00:37:25.700Z",
"lastUpAt": "2026-11-04T00:37:25.700Z",
"uptime7d": 1,
"p50LatencyMs": null,
"toolsCount": null,
"toolsChangedAt": null
},
"lookupd": {
... (65 more lines)Errors
- 404 No entry named <name>
GET /v0.1/entries/{name}/health
Probe status of one entry. Same as the health tool.
Inputs
| name | type | required | meaning |
|---|---|---|---|
name | path, registry name | yes | For example app.linear/linear. |
session | string, 8-64 of A-Z a-z 0-9 _ - | no | The random id you make up once per conversation and repeat on every lookupd call in it, report_outcome included, so lookups and outcomes join up. Never derived from the user, project or machine. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
Output
200 JSON: name, status, lastSeenAt, health, lastProbe.
Example
curl -s "https://api.lookupd.com/v0.1/entries/app.linear/linear/health"
Output of the example
{
"name": "app.linear/linear",
"status": "active",
"lastSeenAt": "2026-11-01T08:51:30.650Z",
"health": {
"status": "auth_required",
"lastProbedAt": "2026-11-04T00:37:25.700Z",
"lastUpAt": "2026-11-04T00:37:25.700Z",
"uptime7d": 1,
"p50LatencyMs": null,
"toolsCount": null,
"toolsChangedAt": null
},
"lastProbe": {
"startedAt": "2026-11-04T00:37:25.510Z",
"status": "auth_required",
"errorClass": "auth",
"httpStatus": 401,
"latencyMs": null
}
}Errors
- 404 No entry named <name>
GET /v0.1/servers
List servers in the Official MCP Registry list format, so tools that read that registry can read this mirror.
Inputs
| name | type | required | meaning |
|---|---|---|---|
limit | integer, 1-100 | no | Page size. Default 30. |
cursor | string | no | metadata.nextCursor from the previous page. |
search | string | no | Case-insensitive substring of the server name. |
version | string | no | latest, or an exact version. |
updated_since | RFC 3339 datetime | no | Only versions updated since then; deleted entries are included. |
include_deleted | boolean | no | true includes deleted entries. |
Output
200 JSON: servers[] and metadata (count, nextCursor when more pages exist).
Example
curl -s "https://api.lookupd.com/v0.1/servers?limit=1&search=linear"
Output of the example
{
"servers": [
{
"server": {
"name": "app.linear/linear",
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
"remotes": [
{
"url": "https://mcp.linear.app/sse",
"type": "sse"
},
{
"url": "https://mcp.linear.app/mcp",
"type": "streamable-http"
}
],
"version": "1.0.0",
"repository": {},
"description": "MCP server for Linear project management and issue tracking"
},
"_meta": {
"com.lookupd/v1": {
"indexedAt": "2026-11-01T08:51:30.630Z",
"lastSeenAt": "2026-11-01T08:51:30.650Z",
"status": "active",
"verification": "unverified",
"health": {
"status": "auth_required",
"lastProbedAt": "2026-11-04T00:37:25.700Z",
"lastUpAt": "2026-11-04T00:37:25.700Z",
"uptime7d": 1,
"p50LatencyMs": null,
"toolsCount": null,
"toolsChangedAt": null
},
"enrichment": null
},
"io.modelcontextprotocol.registry/official": {
"status": "active",
"isLatest": false,
... (12 more lines)Errors
- 400 Invalid limit, Invalid updated_since or Invalid cursor
GET /v0.1/servers/{serverName}/versions
Every known version of one server.
Inputs
| name | type | required | meaning |
|---|---|---|---|
serverName | path, registry name | yes | For example app.linear/linear. |
Output
200 JSON: servers[] and metadata.count.
Example
curl -s "https://api.lookupd.com/v0.1/servers/app.linear%2Flinear/versions"
Output of the example
{
"servers": [
{
"server": {
"name": "app.linear/linear",
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
"remotes": [
{
"url": "https://mcp.linear.app/sse",
"type": "sse"
},
{
"url": "https://mcp.linear.app/mcp",
"type": "streamable-http"
}
],
"version": "1.0.0",
"repository": {},
"description": "MCP server for Linear project management and issue tracking"
},
"_meta": {
"com.lookupd/v1": {
"indexedAt": "2026-11-01T08:51:30.630Z",
"lastSeenAt": "2026-11-01T08:51:30.650Z",
"status": "active",
"verification": "unverified",
"health": {
"status": "auth_required",
"lastProbedAt": "2026-11-04T00:37:25.700Z",
"lastUpAt": "2026-11-04T00:37:25.700Z",
"uptime7d": 1,
"p50LatencyMs": null,
"toolsCount": null,
"toolsChangedAt": null
},
"enrichment": null
},
"io.modelcontextprotocol.registry/official": {
"status": "active",
"isLatest": false,
... (113 more lines)Errors
- 404 Server not found
GET /v0.1/servers/{serverName}/versions/{version}
One version of one server. Use latest for the newest.
Inputs
| name | type | required | meaning |
|---|---|---|---|
serverName | path, registry name | yes | For example app.linear/linear. |
version | path | yes | An exact version, or latest. |
Output
200 JSON: one server entry.
Example
curl -s "https://api.lookupd.com/v0.1/servers/app.linear%2Flinear/versions/latest"
Output of the example
{
"server": {
"name": "app.linear/linear",
"icons": [
{
"src": "https://static.linear.app/integrations/mcp/icon.svg",
"sizes": [
"any"
],
"mimeType": "image/svg+xml"
},
{
"src": "https://static.linear.app/integrations/mcp/icon-256.png",
"sizes": [
"256x256"
],
"mimeType": "image/png"
}
],
"title": "Linear",
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"remotes": [
{
"url": "https://mcp.linear.app/mcp",
"type": "streamable-http"
},
{
"url": "https://mcp.linear.app/mcp/readonly",
"type": "streamable-http"
}
],
"version": "1.0.2",
"websiteUrl": "https://linear.app",
"description": "Find and manage issues, projects, and documents in your Linear workspace."
},
"_meta": {
"com.lookupd/v1": {
"indexedAt": "2026-11-01T08:51:30.630Z",
"lastSeenAt": "2026-11-01T08:51:30.650Z",
"status": "active",
... (21 more lines)Errors
- 404 Server version not found
POST /v0.1/events
Send 1 to 100 outcome, install or call events in one JSON body. Structured fields only; unknown fields are rejected.
Inputs
| name | type | required | meaning |
|---|---|---|---|
events | array of 1-100 objects | yes | Outcome or install: kind, entry, success (required for outcome), and optional capability_tag, latency_bucket, runtime, error_class, session, step, tool, domain, found_via, lookup_id, as in report_outcome. Call (what the opt-in hook sends after a tool call): kind call, entry, tool, ok, and optional latency_ms, runtime, session, lookup_id. |
X-Lookupd-Install | header, uuid | no | The CLI's random install id, sent while telemetry is on (rotate it with lookupd telemetry reset), so repeat use can be counted. Never required. |
Output
202 JSON: accepted, ignored (unknown entry names), principal.
Example
curl -s -X POST https://api.lookupd.com/v0.1/events -H 'content-type: application/json' -d '{"events":[{"kind":"outcome","entry":"app.linear/linear","success":true,"latency_bucket":"lt1s","runtime":"generic"}]}'Output of the example
{
"accepted": 1,
"ignored": 0,
"principal": "anonymous"
}Errors
- 400 Body must be JSON
- 400 with detail naming the bad field
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
GET /v0.1/resolve
The listing behind a server already in an MCP config: pass its remote url, or its npm or PyPI package as typed after npx -y or uvx, and get the registry name to use on events. The call hook asks this once per server and caches the answer.
Inputs
| name | type | required | meaning |
|---|---|---|---|
url | query string, 1-500 characters | no | Remote URL from the MCP config. |
package | query string, 1-200 characters | no | npm or PyPI package from the MCP config, for example @acme/pdf-mcp or pdf-mcp@1.2.0. |
session | string, 8-64 of A-Z a-z 0-9 _ - | no | The random id you make up once per conversation and repeat on every lookupd call in it, report_outcome included, so lookups and outcomes join up. Never derived from the user, project or machine. |
domain | enum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | other | no | What the conversation is about. |
X-Lookupd-Install | header, uuid | no | The CLI's random install id, sent while telemetry is on (rotate it with lookupd telemetry reset), so repeat use can be counted. Never required. |
Output
200 JSON: name (the most likely registry name, or null) and matches (every candidate, most likely first).
Example
curl -s "https://api.lookupd.com/v0.1/resolve?url=https://mcp.linear.app/mcp"
Output of the example
{"name":"app.linear/linear","matches":["app.linear/linear"]}Errors
- 400 neither url nor package given
GET /v0.1/version
API version, upstream registry and data attribution.
Inputs
| name | type | required | meaning |
|---|---|---|---|
| none | |||
Output
200 JSON: version, upstream, attribution.
Example
curl -s https://api.lookupd.com/v0.1/version
Output of the example
{
"version": "0.1.0",
"upstream": "https://registry.modelcontextprotocol.io",
"attribution": "Data from the Official MCP Registry (CC0). lookupd is an independent sub-registry and is not affiliated with the MCP project."
}Errors
- none specific to this item
GET /v0.1/health
Whether the API and its database are up.
Inputs
| name | type | required | meaning |
|---|---|---|---|
| none | |||
Output
200 JSON {status: ok, db: ok}.
Example
curl -s https://api.lookupd.com/v0.1/health
Output of the example
{
"status": "ok",
"db": "ok"
}Errors
- 503 JSON {status: error, db: error}: the database is unreachable
GET /v0.1/ping
Liveness check that does not touch the database.
Inputs
| name | type | required | meaning |
|---|---|---|---|
| none | |||
Output
200 JSON {status: ok}.
Example
curl -s https://api.lookupd.com/v0.1/ping
Output of the example
{
"status": "ok"
}Errors
- none specific to this item
POST /v1/registrations
Claim one listing. Claiming a listing is free: prove you control it and it is yours, with no expiry and nothing to pay. Answers 201 with the claim (an order of offer claim and amount 0, status pending_verification), its order_token (shown once; it is the only way back to the claim) and verify (challenge, expires_at, instructions). Prove control within 30 days or the claim closes. The first claim to prove control holds the listing.
Inputs
| name | type | required | meaning |
|---|---|---|---|
listing | JSON string | yes | Registry name, for example com.acme/server. |
email | JSON string, email | yes | Contact for the claim: alerts and the weekly digest go there. |
Output
201 JSON: order_token, order (offer claim, amount 0, status pending_verification), verify (challenge, expires_at, instructions per proof method).
Example
curl -si -X POST https://api.lookupd.com/v1/registrations -H 'content-type: application/json' -d '{"listing":"com.acme/server","email":"dev@acme.com"}'Output of the example
HTTP/2 201
{"order_token":"q9Z…","order":{"id":"0b6f…","listing":"com.acme/server","offer":"claim","amount":0,"status":"pending_verification"},"receipt":null,"verify":{"challenge":"Jd2…","expires_at":"2026-12-11T00:00:00.000Z","instructions":[{"method":"dns","record":{"name":"_lookupd.acme.com","value":"lookupd-verify=Jd2…"}},{"method":"well-known","url":"https://acme.com/.well-known/lookupd.json"}]}}Errors
- 400 invalid listing or email; 404 unknown listing; 413 body over 16 KB
- 409 already claimed: another publisher holds this listing
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
GET /v1/registrations/{id}
Status of one claim, for the holder of its order token.
Inputs
| name | type | required | meaning |
|---|---|---|---|
id, Authorization | path, header | yes | order_id; Bearer <order token>. |
Output
200 JSON: order, receipt (null for a claim), verify (while the claim can still be proven).
Example
curl -s https://api.lookupd.com/v1/registrations/ORDER_ID -H 'authorization: Bearer ORDER_TOKEN'
Output of the example
{"order":{"id":"0b6f…","offer":"claim","status":"pending_verification","amount":0},"receipt":null,"verify":{"challenge":"Jd2…","expires_at":"2026-12-11T00:00:00.000Z"}}Errors
- 404 Order not found: unknown id or wrong token
POST /v1/registrations/{id}/verify
Prove control of the namespace as verify.instructions says: com.acme/* by DNS TXT or .well-known/lookupd.json on acme.com, io.github.<owner>/* by GitHub Actions OIDC here (audience exactly https://lookupd.com/v1/registrations/<order id>), or by GitHub sign-in in a browser (the claim page posts to /register/github/start, not to this route). OIDC is a weaker proof than sign-in: any repository writer with id-token: write in a repository of <owner> can pass it. The first claim to prove control holds the listing; the others close, as does a claim unproven after 30 days. A claim does not expire once it holds the listing.
Inputs
| name | type | required | meaning |
|---|---|---|---|
id, Authorization | path, header | yes | order_id; Bearer <order token>. |
method | JSON enum: dns | well-known | github-oidc | yes | Proof to check. |
token | JSON string | no | github-oidc: the OIDC ID token. |
Output
200 JSON: order with status active and period_end. Verifying again replays it.
Example
curl -s -X POST https://api.lookupd.com/v1/registrations/ORDER_ID/verify -H 'authorization: Bearer ORDER_TOKEN' -H 'content-type: application/json' -d '{"method":"dns"}'Output of the example
{"order":{"id":"0b6f…","offer":"claim","status":"active","period_end":"2999-12-31T00:00:00.000Z"}}Errors
- 400 wrong method for the namespace; 404 unknown claim or wrong token; 409 proof not found, another claim won, or the claim closed (body has order, with status)
- 429 Too Many Requests: 60 requests per minute per IP; wait and retry once
GET /v1/registrations/{id}/analytics
An active registration's listing over the last 7, 30, 90 or 365 days, aggregates only: searches it showed in (organic, average position, featured), the same counts for the window before (previous), a daily series, top queries (queries searched by at least 3 different callers; the text is typed by searchers, so untrusted), server-page views, outcome success rate and the median of other listings with its tag, how agents used it (runtimes, domains, tools, found via lookupd or already installed, first or later in the conversation, error classes, latency, other listings used in the same conversations), and lost_queries: queries where it ranked below 3 and who held the top positions. The same numbers reach the owner by email every 7 days unless paused on the order page.
Inputs
| name | type | required | meaning |
|---|---|---|---|
id, Authorization | path, header | yes | order_id; Bearer <order token>. |
days | enum: 7 | 30 | 90 | 365 | no | The window; default 30. |
Output
200 JSON: analytics (window_days, searches, previous, series, top_queries, page_views, outcomes, usage, lost_queries), note, lost_note.
Example
curl -s 'https://api.lookupd.com/v1/registrations/ORDER_ID/analytics?days=90' -H 'authorization: Bearer ORDER_TOKEN'
Output of the example
{
"analytics": {
"searches": {
"organic": 412,
"featured": 37,
"average_position": 2.4
},
"top_queries": {
"min_callers": 3,
"query_text": "typed by searchers: untrusted text, shown as plain text",
"items": [
{
"query": "acme invoices",
"count": 58
}
]
},
"page_views": 96,
"outcomes": {
"reports": 21,
"success_rate": 0.905,
"capability_tag": "billing",
"peer_median_success_rate": 0.82
}
}
}Errors
- 400 days is not one of 7, 30, 90, 365
- 404 Order not found: unknown id or wrong token
- 409 Not registered: the order's registration is not active
- 62033 servers
- Last crawl: 2026-11-11T15:17:20.593Z
- API base:
https://api.lookupd.com - MCP URL:
https://api.lookupd.com/mcp