lookupd

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

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

nametyperequiredmeaning
taskstring (positional, one or more words)yesShort capability phrase, for example read Linear issues.
--runtimeenum: claude-code | codex | claude-desktop | cursor | vscode | genericnoRuntime that selects the install snippet. Default: detected from the environment.
--limitintegernoNumber of results to ask for (the API allows 1 to 10, default 5).
--jsonflagnoPrint 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

nametyperequiredmeaning
modeenum: on | off | statusyeson 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

nametyperequiredmeaning
--keystring, lk_ followed by letters and digitsyesThe 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

nametyperequiredmeaning
actionenum: install | remove | statusyesWhat to do.
--clientenum: claude-code | codexnoWhose 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

nametyperequiredmeaning
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

nametyperequiredmeaning
taskstring, 1-200 charactersyesShort capability phrase.
kindenum: mcp_servernoOnly mcp_server in this release.
runtimeenum: claude-code | codex | claude-desktop | cursor | vscode | genericnoCaller's runtime; selects the install snippet.
verified_onlybooleannoOnly verified (registered) publishers.
max_resultsinteger, 1-10noDefault 5.
capabilityenum: tag from lookupd's taxonomynoCapability tag to prefer, for example issue-tracking.
sessionstring, 8-64 of A-Z a-z 0-9 _ -noThe 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.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat 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

nametyperequiredmeaning
namestring, 1-200 charactersnoRegistry name, for example app.linear/linear.
urlstring, 1-500 charactersnoRemote URL from the MCP config.
packagestring, 1-200 charactersnonpm or PyPI package from the MCP config.
runtimeenum: claude-code | codex | claude-desktop | cursor | vscode | genericnoRuntime for install snippets. Default: generic.
sessionstring, 8-64 of A-Z a-z 0-9 _ -noThe 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.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat 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

nametyperequiredmeaning
namestring, 1-200 charactersyesRegistry name.
sessionstring, 8-64 of A-Z a-z 0-9 _ -noThe 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.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat 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

nametyperequiredmeaning
entrystring, 1-200 charactersyesRegistry name of the server that was used.
successbooleanyesWhether the server did the job.
capability_tagenum: tag from lookupd's taxonomynoWhat the server was used for.
latency_bucketenum: lt1s | lt5s | lt30s | gte30snoHow long the call took.
runtimeenum: claude-code | codex | claude-desktop | cursor | vscode | genericnoCaller's runtime.
error_classenum: auth | timeout | schema | tool_error | othernoWhy it failed, if it did.
sessionstring, 8-64 of [A-Za-z0-9_-]noA random id the client makes up once per conversation and repeats on every report in it; never derived from the user, project or machine.
stepinteger >= 1noOrder in which this server was first used in the conversation.
toolstring, 1-120 of [A-Za-z0-9_.-]noThe tool used most on the server, by name.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat the conversation is about.
found_viaenum: lookupd | installednoWhether lookupd found the server or it was already installed.
lookup_idstring, uuidnoThe 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

nametyperequiredmeaning
taskquery string, 1-200 charactersyesShort capability phrase.
kindenum: mcp_servernoOnly mcp_server in this release.
runtimeenum: claude-code | codex | claude-desktop | cursor | vscode | genericnoSelects the install snippet.
verified_onlyenum: true | false | 1 | 0noOnly verified (registered) publishers.
limitintegernoResults to return; clamped to 1-10, default 5.
capabilityenum: tag from lookupd's taxonomynoCapability tag to prefer.
sessionstring, 8-64 of A-Z a-z 0-9 _ -noThe 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.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat the conversation is about.
X-Lookupd-Installheader, uuidnoThe 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

nametyperequiredmeaning
namepath, registry nameyesFor example app.linear/linear.
runtimeenum: claude-code | codex | claude-desktop | cursor | vscode | genericnoQuery string; selects install snippets. Default: generic.
sessionstring, 8-64 of A-Z a-z 0-9 _ -noThe 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.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat 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

nametyperequiredmeaning
namepath, registry nameyesFor example app.linear/linear.
sessionstring, 8-64 of A-Z a-z 0-9 _ -noThe 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.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat 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

nametyperequiredmeaning
limitinteger, 1-100noPage size. Default 30.
cursorstringnometadata.nextCursor from the previous page.
searchstringnoCase-insensitive substring of the server name.
versionstringnolatest, or an exact version.
updated_sinceRFC 3339 datetimenoOnly versions updated since then; deleted entries are included.
include_deletedbooleannotrue 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

nametyperequiredmeaning
serverNamepath, registry nameyesFor 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

nametyperequiredmeaning
serverNamepath, registry nameyesFor example app.linear/linear.
versionpathyesAn 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

nametyperequiredmeaning
eventsarray of 1-100 objectsyesOutcome 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-Installheader, uuidnoThe 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

nametyperequiredmeaning
urlquery string, 1-500 charactersnoRemote URL from the MCP config.
packagequery string, 1-200 charactersnonpm or PyPI package from the MCP config, for example @acme/pdf-mcp or pdf-mcp@1.2.0.
sessionstring, 8-64 of A-Z a-z 0-9 _ -noThe 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.
domainenum: software-engineering | devops-cloud | data-analytics | finance | legal-compliance | sales-crm | marketing | customer-support | hr-recruiting | operations | research | education | healthcare | ecommerce | design-media | personal | othernoWhat the conversation is about.
X-Lookupd-Installheader, uuidnoThe 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

nametyperequiredmeaning
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

nametyperequiredmeaning
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

nametyperequiredmeaning
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

nametyperequiredmeaning
listingJSON stringyesRegistry name, for example com.acme/server.
emailJSON string, emailyesContact 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

nametyperequiredmeaning
id, Authorizationpath, headeryesorder_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

nametyperequiredmeaning
id, Authorizationpath, headeryesorder_id; Bearer <order token>.
methodJSON enum: dns | well-known | github-oidcyesProof to check.
tokenJSON stringnogithub-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

nametyperequiredmeaning
id, Authorizationpath, headeryesorder_id; Bearer <order token>.
daysenum: 7 | 30 | 90 | 365noThe 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