From scan to fix
Read your WebMCP report.
Scan one public page, understand what was captured, then review the fixes that matter for that page.
1. Start with the page people use
Enter its public URL on the scanner. This is a page check, not a crawl of your whole website. Query strings and fragments are removed; private networks, logins and URLs containing credentials are refused.
The scanner requests the page and discovery files, then observes it in a sandboxed browser when rendering is available. It does not invoke tools or submit forms. The page's own scripts may run during rendering.
2. Read the capture method first
- Native WebMCP: registration was observed while the browser API was available.
- Recording stand-in: the browser lacked native WebMCP, so registration was recorded with an explicit stand-in. This does not prove native execution works.
- HTML only: JavaScript registrations may be missing. The report marks JavaScript registration as not tested; zero observed tools receive no score.
A browser verification challenge or HTTP error is not graded. A failure to observe a protected page is not evidence that the website has no tools. Use Explorer in your own browser when access or authentication is required.
3. Review the highest-priority fixes
Each finding includes evidence, its contribution to the published ruleset and an implementation example where useful. Inspect the evidence before changing code. Examples are starting points: adapt routes, schemas and authorization to your application.
Read-only annotations are declarations, not a proof of behavior. Security headers are observations, not a security certification. The score reviews observed WebMCP contracts; it does not predict Google rankings or guarantee an agent will use your tools.
After deploying a reviewed change, run a new scan. Test actual tool behavior in your own environment with Explorer; scanner results alone cannot verify server-side authorization.
Bounded interactive examples
A catalogue filter can be read-only. An order or support request needs explicit authorization and human approval bound to the exact arguments; a hint is never that approval. These inert templates define no working transaction.
Catalogue lookup
// Inert example: review before calling registerCatalogTool().
async function registerCatalogTool(signal) {
return document.modelContext.registerTool({
name: "filter_catalog",
description: "Find catalogue items matching a category and a maximum price.",
inputSchema: {
type: "object", additionalProperties: false,
properties: {
category: { type: "string", enum: ["books", "games"], description: "Catalogue category." },
maxPrice: { type: "number", minimum: 0, maximum: 10000, description: "Maximum price in EUR." }
}, required: ["category"]
},
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },
async execute(args) {
throw new Error("Implement validated catalogue lookup first");
}
}, { signal });
}
// No function is called. Abort the supplied signal to unregister.Human-reviewed support request
<!-- Illustrative application form: no toolautosubmit. -->
<form id="support" toolname="submit_support_ticket"
tooldescription="Submit a customer support request after human review.">
<label>Subject <input name="subject" required maxlength="120"></label>
<label>Details <textarea name="details" required maxlength="2000"></textarea></label>
<button type="submit">Review request</button>
</form>
<!-- Place the following JavaScript in your own CSP-approved file. -->
const form = document.querySelector("#support");
form.addEventListener("submit", event => {
event.preventDefault(); // No network or state change in this template.
const fromAgent = event.agentInvoked === true;
// agentInvoked indicates the initiator, NOT approval.
// Show the exact request to the human for either initiation path.
// Your server must validate input, session, object authorization, CSRF,
// approval binding and at-most-once request identity before any mutation.
const result = Promise.reject(new Error("Human review and server authorization required"));
if (fromAgent && typeof event.respondWith === "function") event.respondWith(result);
else result.catch(() => { /* Render your review UI; this example remains inert. */ });
});SubmitEvent.agentInvoked identifies an agent initiation; it is not consent. Keep a real confirmation boundary and enforce authorization on the server. Current Chrome guidance uses consequentialHint for high-impact actions; destructiveHint and idempotentHint are advisory MCP conventions.
For content-heavy sites, Corsen Context is an optional open-source starter. Its presence is never a benchmark or a shortcut to a score; this scanner evaluates the same observed contracts regardless of framework or publisher.
4. Share only the result you intend
Reports are available by link for at most one hour and are not indexed by search engines. The creator can delete a report; closing its page requests deletion. Browser shutdown delivery is best effort, so the one-hour expiry is the hard limit. Shared readers cannot delete it.
Download Markdown, SARIF 2.1.0 or JSON before the report expires. SARIF uses logical runtime locations; repository annotations need a real source mapping. For automation, use the JSON API. Respect its limits and error responses. See the privacy policy for stored data and scanner access and limits to manage scans of your domain.