docs

WebMCP

An agent in the browser can fill in a survey Form, or work the Studio's inbox, without clicking through the DOM. The ingest contract stays the same POST. WebMCP only describes the open page.

Where it applies

Two places register tools:

PageTools
/f/:handle — a survey Form's public page, hosted or embeddeddescribe_form, submit_form
studio.noonmark.dev — signed in, as that personreads: list_forms, get_form, list_submissions, get_submission, list_insights, list_workspaces; writes, each confirmed on screen: set_submission_status, create_form, create_workspace, update_workspace, switch_workspace
Everything else on noonmark.dev — the landing, these docsnone

That is what "WebMCP ready" on the landing means, and all it means.

Use with your AI assistant

There are two ways to submit a response:

  • From your app: use the Form's API key with the HTTP API or SDK.
  • From an open browser tab: open the public survey with a WebMCP-aware browser agent. It can read the Fields and submit through the page's tools. You do not need to paste the Form's API key into your assistant.

For ChatGPT, Claude or Gemini, check the browser or client you are using. Opening a link in an assistant does not automatically enable WebMCP; the browser agent must support it. The normal form remains usable without it.

To work with Forms and responses outside an open tab, use the remote MCP setup guide. Remote MCP uses a Workspace token, not the public Form API key. Client support and authentication options vary; Gemini CLI is an example of an MCP client in the Gemini family.

What it is

WebMCP is a draft from the W3C Web Machine Learning CG. The page registers tools on document.modelContext. The spec moved the getter from navigator to document in May 2026; Noonmark reads both. The browser's agent discovers and calls those functions in the tab, with the person watching.

It is not Anthropic's MCP on the wire. It replaces neither the SDK, the HTTP ingest nor a remote MCP server. Without a tab on the origin, there is nothing to discover.

Chrome: an origin trial in versions 149–156, or the local flag chrome://flags/#enable-webmcp-testing. It is not on by default; shipping is estimated for Chrome 157. Noonmark sends the trial token on /f/:handle and on every page of studio.noonmark.dev, so Chrome 149–156 exposes the API there without the flag. In a browser without the API, the page works as it always did.

What Noonmark registers

Public survey pages — /f/:handle — register two tools, with feature detection. A feedback Form has no page on Noonmark: the screen lives in your own app, so the POST via SDK or HTTP remains the path.

ToolWhat it does
describe_formRead-only. Returns name, kind and the list of Fields.
submit_formThe same validation as the screen. POSTs to /api/v1/f/:publicKey/page, the same endpoint the public page uses.
describe_form.ts
await modelContext.registerTool({
  name: "describe_form",
  description: "Returns this survey's name and Field list.",
  inputSchema: { type: "object", properties: {} },
  annotations: { readOnlyHint: true },
  execute() {
    return { name, kind: "survey", fields };
  },
});
submit_form.ts
await modelContext.registerTool({
  name: "submit_form",
  description: "Submit this survey. Keys match Field.key.",
  inputSchema: fieldInputSchema(fields),
  async execute(input) {
    const response = await fetch(`/api/v1/f/${encodeURIComponent(apiKey)}/page`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(input),
    });
    return response.json();
  },
});

Success and error appear on the page, so the person can see what the agent did. Rate limits and Field 400s stay the same.

Field → JSON Schema

The Field's key is the property. The label becomes the description.

FieldSchema
text, textareastring
emailstring with format: email
urlstring with format: uri
numbernumber
scalenumber with the Field's min/max
satisfactionnumber 1 to 5
selectstring enum of the options
multiselectarray of string enum
emojistring enum of the options
whenthe Field is left optional in the schema; the rule is appended to its description
requiredgoes into schema.required
defaultgoes into the property's default
hiddenstays in the schema — an agent may set it, as the link would
lockedleft out of the schema — the server writes the Form's value

In the Studio

A signed-in Studio tab registers the MCP server's five reads, with the same names, inputs and answers, plus the person's Workspaces and five writes. They act as the person signed in, on the Workspace that is open.

ToolWhat it does
list_formsRead-only. Every Form in the Workspace.
get_formRead-only. One Form: Fields, Gate, status words.
list_submissionsRead-only, untrusted content. Newest first, with search, status and a cursor.
get_submissionRead-only, untrusted content. One Submission with its Timeline.
list_insightsRead-only. The numbers the Insights page shows: arrivals, doors, status movement, what is open.
list_workspacesRead-only. The person's Workspaces, and which one is open.
set_submission_statusMoves a Submission to another of its Form's words, with a note.
create_formA Form in the open Workspace: name, feedback or survey, Fields.
create_workspaceA Workspace with the person as its first member; the tab opens it.
update_workspaceThe open Workspace's name and identifier.
switch_workspaceOpens another of the person's Workspaces, like the Workspace menu.

Every write is marked consequentialHint and waits on the person: the Studio shows what the agent asked for — the Submission and the word, the Form and every Field, the Workspace by name — and only Confirm makes the change. Decline, Escape or the agent cancelling all leave things as they were. A status change lands on the Timeline under the person's name, the same as the status menu. Fields go through the same checks as the Form editor.

The two Submission reads carry untrustedContentHint: a payload is whatever a stranger typed, and an agent should read it as data, not instructions.

What stays out of the tools

Nothing that deletes or reconfigures: rotating the API key, deleting a Form or a Submission, creating or deleting webhooks, Integrations, the slug, tokens. Those stay clicks.

Headless agents (a script, a GitHub Action, another server) use POST /api/v1/submit. WebMCP is not for that.

A widget on another origin

The tools Permissions Policy defaults to self. A cross-origin iframe only registers tools if the embed carries allow="tools" — see Embed a Form. HTTPS is required (Secure Context).

The page must also be origin-keyed: WebMCP is disabled when document.domain is enabled, for example by Origin-Agent-Cluster: ?0. A site can opt out entirely with Permissions-Policy: tools=(). Noonmark sends neither header.

What did you think of this content?

On this page