API for Agents
Query the WebMCP directory.
Read-only JSON API for agents. List WebMCP-enabled sites, fetch their tools and input schemas, or check whether a given URL exposes any.
TL;DR
Base URL https://webmcp.com. Directory endpoints return JSON, with no auth,
CORS open (Access-Control-Allow-Origin: *). For a one-shot
probe of an arbitrary URL, use /api/v1/lookup?url=….
Deprecation (2026-07-03). Tool kind values
were renamed read/write/action →
answer/act/transact — displayed on
webmcp.com as Answer, Action, and Sensitive Action. The old values
are no longer emitted or accepted by the kind filter. See the
OpenAPI changelog and
Tool categories.
Question
How can my agent find websites that support WebMCP?
Use this API. /api/v1/lookup?url=… tells you whether a page
exposes WebMCP tools, /api/v1/sites lists every site in the
directory, and /api/v1/sites/{host} returns one site's tools
with their input schemas. Shopify stores have a separate index: read their
shared tools at /api/v1/platforms/shopify and search stores at
/api/v1/platforms/shopify/stores?q=…. The OpenAPI spec is at
/api/openapi.json.
Probe an arbitrary URL
Given any URL, check the stored directory and Shopify index. A directory
match returns supported: true and its site record.
An index-only Shopify match returns platform: "shopify",
platformUrl, and the shared toolCount, without a
site record. Follow platformUrl for shared schemas;
stores may add tools. This does not perform a live verification.
The host is extracted, www. stripped, and
path-scoped demos (e.g. googlechromelabs.github.io/webmcp-tools/demos/*)
are matched by URL prefix.
| Param | Type | Description |
|---|---|---|
| url | string | Any URL on the page being probed. The host is extracted; path-scoped demos match by prefix. |
| host | string | Alternative to url. www. is stripped before matching. |
GEThttps://webmcp.com/api/v1/lookup?url=https://store.nekuda.ai/checkout
GEThttps://webmcp.com/api/v1/lookup?url=https://example.com
List & filter sites
Returns directory entries. All params are optional and combinable. Use
fields to control response size: full includes
every tool's inputSchema, summary drops schemas,
minimal returns only name/kind/impl/description.
Curated Shopify entries remain in this directory. Search the additional store index with the Shopify store endpoint; it is excluded from bulk directory and tool listings.
| Param | Type | Description |
|---|---|---|
| type | live | demo | all | Filter by site type. Defaults to all. |
| q | string | Substring search across host, description, URL, and every tool name/description. |
| tool | string | Return only sites that expose a tool whose name contains this substring. |
| kind | answer | act | transact | Filter sites by tool category (Answer / Action / Sensitive Action). Repeat to OR (e.g. kind=answer&kind=act). |
| impl | imperative | declarative | Filter by tool implementation style. |
| apiSurface | spec | polyfill | mixed | Filter by which API surface the site uses to register tools. spec = WICG registerTool or declarative DOM. polyfill = @mcp-b/webmcp-polyfill provideContext extension. mixed = both. Repeat to OR. |
| fields | full | summary | minimal | Response shape. Defaults to full. |
| limit | integer | Max sites to return. Default 100, max 500. |
| offset | integer | Pagination offset. |
GEThttps://webmcp.com/api/v1/sites?type=live&fields=summary
GEThttps://webmcp.com/api/v1/sites?tool=checkout&fields=minimal
Get a single site
Returns the full record for one directory entry, including every tool
with its JSON Schema. host is the directory key —
www. is stripped before matching.
GEThttps://webmcp.com/api/v1/sites/store.nekuda.ai
List tools for a site
Returns the tools array only — no surrounding site metadata.
GEThttps://webmcp.com/api/v1/sites/store.nekuda.ai/tools
Get one tool definition
Returns a single tool's full record including its inputSchema.
GEThttps://webmcp.com/api/v1/sites/store.nekuda.ai/tools/add_to_cart
Search every tool across every site
Flat search across all tools in the directory. Each result carries the host and URL it belongs to.
| Param | Type | Description |
|---|---|---|
| q | string | Substring match against tool name and description. |
| kind | answer | act | transact | Filter by category (Answer / Action / Sensitive Action). Repeat to OR. |
| impl | imperative | declarative | Filter by implementation style. |
| limit / offset | integer | Pagination — default 100, max 500. |
GEThttps://webmcp.com/api/v1/tools?q=cart&kind=act
Aggregate directory stats
Useful for status dashboards. Returns totals plus a breakdown by tool
kind and implementation, and the top 10 sites by tool count.
sites, tools, and breakdowns cover directory records.
platforms.shopify counts indexed stores; totalSites
adds both sets and removes overlapping hosts. When the index is unavailable,
the imported count is used and overlap assumes the importer included all
curated Shopify stores. These counts describe index coverage.
GEThttps://webmcp.com/api/v1/stats
One shared Shopify toolkit
Shopify stores share a core WebMCP implementation and may add their own
tools. This endpoint returns the shared tools with input
schemas, apiSurface, sentinelHost, and
storeCount. Tools follow the latest directory snapshot of the
reference store, falling back to the imported tool snapshot.
updatedAt is the store index import date.
toolsUpdatedAt is when the reference tools were captured,
or null if unknown. The count describes indexed hosts,
not individual live verification. Returns 404 if platform
metadata is unavailable.
source records the import provenance separately;
indexSha256 identifies the artifact and indexReady
reports whether it is available. The
September 30, 2026 snapshot contains 2,375,833 hosts, combining
historical and recent positive WebMCP findings. The shared Alo Yoga
toolkit was captured again on September 30; this does not mean every
indexed store was rechecked then.
GEThttps://webmcp.com/api/v1/platforms/shopify
Find a Shopify store
Pass q with 3-100 characters to search indexed hostnames by
substring, ignoring case. Queries are trimmed. Returns up to 20 hosts in
results, plus query, matchCount,
matchCountTruncated, and limit. The match count
stops at 5,000; matchCountTruncated: true means 5,000 or more.
There is no pagination or bulk export. Curated Shopify records remain in
the regular directory APIs. Index membership is not a live verification;
use /api/v1/lookup?host=… for a stored record and the shared toolkit link.
Non-directory lookups share the search quotas below.
Invalid queries return 400; an unavailable index returns
503. Search and non-directory lookups share limits: 30 requests per IP per 10
minutes, 50 per IP per UTC day, and 1,000 globally per UTC day.
Operators can lower these ceilings. Invalid and cached searches count.
Limits persist across restarts and instances; if quota storage is unavailable, requests return 503. A 429 response includes
Retry-After and JSON retryAfter in seconds.
The OpenAPI spec reports the configured limit.
GEThttps://webmcp.com/api/v1/platforms/shopify/stores?q=alo
Start a private implementation review
Your coding agent can send selected WebMCP source code, read the findings,
fix the implementation, and submit an updated version. This preview is
enabled separately from the directory API. Before sending code, check that
POST /api/code-reviews appears in this deployment's
live OpenAPI contract.
Availability has not been confirmed. Check the live OpenAPI contract before submitting code.
Create a session by sending an empty JSON object, or only the anonymous
handoffId your copied prompt includes (it links the prompt to
this session in our analytics and carries nothing else) and, when the prompt
was copied on a site's page, that site's hostname as site (it
labels this session's notifications and is not verified). Save the returned
sessionId, credential, and expiresAt privately.
Use Authorization: Bearer <credential> to submit code and read reports.
Session creation is rate-limited; it does not submit a review.
POST /api/review-sessions
Content-Type: application/json
{}
A successful request returns 201 with
{sessionId, credential, expiresAt}. The default session lifetime is
seven days; use the returned expiry. Source is retained privately until the
session expires. When factual checks pass, it is sent to the review model for static analysis. The
service does not execute the submitted code. Keep credentials out of URLs,
shared prompts, logs, and version control.
Submit the approved implementation
Include the selected tool definitions and the source that registers and
implements them. A public URL is optional context for local work and is not
part of this request. Show the user exactly which files and content will be
shared, then set sharingApproved: true after approval. Include only
relevant source from that project, without secrets, credentials, personal
data, or unrelated files.
| Field | Type | Description |
|---|---|---|
| protocolVersion | integer | Required: 2. |
| projectId | string | Stable identifier for the local project: 1-80 letters, digits, periods, underscores or hyphens. Keep it the same for the whole loop. |
| sharingApproved | boolean | Required: true, following the user's approval of the shared selection. |
| tools | array | 1-100 complete tool definitions with unique names. Supported fields: name, title, description, inputSchema, outputSchema, annotations, availability, page, kind, impl, apiSurface. Source belongs in files. |
| files | array | 1-20 objects containing path and content. Unique relative POSIX paths of at most 240 characters, inside the approved selection. No traversal, absolute paths, .env, .git, node_modules, secret files, or private keys. |
| expectedTools | array | Optional: 1-100 declarations of name, optional page (default /), and optional fields. Declare the exact intended fields, including name, to detect missing definition fields. |
| expectedFiles | array | Optional: 1-20 declarations of exactly path, sha256, and bytes. Hash complete selected files as UTF-8 using lowercase SHA-256; count bytes, not characters. Unique paths; ordering does not matter. |
| withheldFiles | array | Optional: 1-20 relevant files you deliberately did not send, each with path (not also in files), reason (secret, too-large, third-party or other) and an optional one-line note of up to 300 characters, such as a package name and version. Never put a secret value in a note. The review treats their content as unknown, covers the rest, and names the gap; the receipt and assessment.scope.withheldFiles list them. |
| previousReviewId | string | Omit for the first review. For every updated submission, send the latest review ID from this session and project. |
Limits are 50 KiB per file, 100 KiB of source total, and 256 KiB for
the complete JSON request, measured in UTF-8 bytes. Object-form
schemas support at most 64 levels. Optional output schemas may also be boolean
JSON Schemas. Explicit null is accepted by transport but fails factual
validation; omit an absent optional schema instead. Preserve complete definitions and code;
explicitly revise the selection if it does not fit, rather than silently
dropping files or cutting schemas.
Build the optional manifests from the approved selection before assembling the payload. Otherwise the manifest could repeat the same omission. Compare the received receipt against this independent selection. A match proves only that the declared selection arrived; it never establishes full repository coverage. If a request does not fit, revise the approved scope explicitly and rebuild the manifests.
Authored example only - not a request to upload your repository{
"protocolVersion": 2,
"projectId": "page-title-demo",
"sharingApproved": true,
"tools": [{
"name": "get_page_title",
"description": "Return the current page title as text.",
"inputSchema": { "type": "object", "properties": {} }
}],
"expectedTools": [{ "name": "get_page_title", "fields": ["name", "description", "inputSchema"] }],
"files": [{
"path": "src/tools.js",
"content": "navigator.modelContext.registerTool({\n name: 'get_page_title',\n description: 'Return the current page title as text.',\n inputSchema: { type: 'object', properties: {} },\n execute: async () => ({ content: [{ type: 'text', text: document.title }] })\n});\n"
}],
"expectedFiles": [{ "path": "src/tools.js", "sha256": "12a2edc5c8ebf3392c0be202f4906e88d43b1fc4954aacb19d792ac879bb0ac1", "bytes": 255 }]
}
Send Content-Type: application/json, the session's
Authorization header, and an Idempotency-Key of
16-128 letters, digits, hyphens or underscores. Use the SHA-256 hex digest
of the exact JSON bytes you will transmit, and save those bytes and the
key privately before submitting. Changed JSON gets a new key.
The review ID is the lowercase hex SHA-256 of the UTF-8 string
sessionId + NUL + idempotencyKey, where NUL is byte 0.
Compute and save it before POST. If the response is lost, recover the known
report with authenticated GET /api/reviews/{id}. Never blindly
repeat a submission or create a new session to recover an uncertain POST.
If GET cannot recover the report, stop and report the uncertainty.
The response also includes server-generated factualChecks (omitted
from the shape above for brevity). Compare receivedTools and
receivedFiles with the manifests. Source receipt fields exclude
name, so compare ["name", ...receivedTools[i].fields]
with the declared fields; use page || "/" for tool identity.
Compare every file path, hash and byte count. toolsCompleteness and
filesCompleteness are matches-declared-tools and
matches-declared-files when declared, otherwise not-declared.
repositoryCompleteness is always not-verified.
Recovering the same accepted submission does not add a review call.
Reusing its key for different content returns 409.
Manifest mismatches reject the request before accepting a review. Read
fields and nextAction: "fix-request":
review_scope_mismatch identifies missing or unexpected tools,
review_fields_mismatch identifies changed definition fields,
source_selection_mismatch returns missingFiles/unexpectedFiles,
and source_content_mismatch returns mismatchedFiles with
expected and received hashes/bytes. Restore the complete approved selection;
do not silently shrink it to make the request pass.
Read the findings and continue the loop
factualChecks contains server-generated definition checks;
advisory describes model advice separately. Factual checks run first.
If they find issues or cannot fully validate supplied schemas, the service skips
the model and finishes with no assessment and
advisory: {status: "not-requested", reason: "factual-checks-need-attention"}.
This can be a fixable result: follow loop.canContinue and nextAction.
Factual statuses are checks-passed, issues-found, or
insufficient-evidence. Read checkVersion, scope,
checks, tools, and counts. Repair entries in
factualChecks.fields have path, code,
status (fail or not-assessed), and message.
The path is a JSON Pointer into your request, for example
/tools/0/inputSchema/properties/count/minimum; property names escape
~ as ~0 and / as ~1.
Supplied schemas use their supported declared dialect (draft-07, 2019-09 or 2020-12),
with 2020-12 assumed when absent. Unsupported dialects and unresolved external references
remain unknown. These checks validate definitions, not actual arguments, results,
design quality or execution; implementationGrade remains null.
Read the report with the same session credential. Honor
pollAfterSeconds while it is running. When model advice completes,
advisory.status is complete. A completed source assessment
has assessment.reviewType: "source" and
rubricVersion: "webmcp-source-implementation-v2". It includes the
project ID, file hashes, and findings with path,
startLine, endLine, and an exact source
quote in each finding's evidence.
WebMCP.com derives the technical implementation grade from findings grounded
in the submitted source. Use grade only when the assessment is
complete. Read nextAction and loop before another
submission; a stale report may point to latestReviewId.
The loop stops after three accepted reviews, including factual-only
results, or when current factual checks pass and a complete review earns A+,
whichever comes first. Best-grade requires zero factual failures,
fully validated supplied schemas, and complete model advice. Intentional unknowns
about design or execution do not block it. Read-only report polling does not count,
and neither does a review the service could not finish: the daily budget was reached
or could not be checked, a restart interrupted it, or the model returned no usable
review (at most two retries per step). Its answer says nextAction: "wait"
with retryAfterSeconds; after that, send the same step again with that
review as previousReviewId and a new Idempotency-Key.
Within the limit, the agent fixes useful findings, runs focused tests, and
submits the updated approved code with the latest previousReviewId.
Keep the same session and projectId; never replace either to
bypass the limit. Get approval before adding files to the shared selection.
Stop earlier if the API says to stop, a review fails, tests cannot run,
access is blocked, no useful findings remain, or the last pass made no progress.
Otherwise an incomplete or unavailable advisory stops the loop;
preserve factual findings and do not infer a grade. Legacy reports without current
factual checks cannot establish the best grade.
This is a private static review of the submitted implementation.
targetUrl is null and scope.execution is
not-tested. It does not change your directory listing or verify
deployment, discoverability, site coverage, or agent task success. After the
user confirms deployment, a live rescan is a separate, rate-limited action.
Connecting tools to AgentLane is an optional next step.
| Status | Meaning | Next action |
|---|---|---|
| 400 / 413 | Invalid request | Read field and size errors. A rejected request is not an accepted review; never silently shrink the approved selection. |
| 401 | Session unavailable | Stop if the credential is missing, invalid or expired. |
| 404 | Review unavailable | Stop if the known report cannot be recovered in this session. |
| 409 | Conflict or stopped loop | Follow the returned nextAction, reviewId and loop. A pending review must finish before another submission. |
| 429 | Rate limited | Stop the autonomous loop. Honor Retry-After and retryAfterSeconds before any later user-requested attempt. |
| 503 | Service unavailable | An uncertain POST may have been accepted. Read its known report, without repeating POST. Stop if recovery is unavailable. |
The older POST /api/reviews accepts tool definitions and a site
URL only. It rejects source files. Use the separately enabled code-review
route above for implementation source.
OpenAPI 3.1 spec
The full machine-readable contract for this API. Works with Swagger UI, OpenAPI codegen, or a ChatGPT action.
GEThttps://webmcp.com/api/openapi.json
Built and maintained by nekuda. Missing a site? Submit it on the directory.