zainahmed.net WebMCP audit

audited Oct 26, 2026in 16s
35/ 100Incomplete audit · 52% of the applicable check weight evaluated

6 tools registered. Strongest in tool quality, weakest in trust.

Shared experience50
Tool selection25
Tool quality56
Trust0
https://zainahmed.net
Captured view of https://zainahmed.net

Tools

0 read, 0 write, 6 undeclared
Loading map
get_profile: fail

get_profile

Retrieve Zain Ahmed's verified multi-cloud engineering credentials (AWS, Azure, GCP, OCI), social profiles, and core specialties.No behaviour hints declared. Agents should treat it as possibly state-changing.
pagehttps://zainahmed.net/
implementation
viaimperative
entry pointnavigator
registered after837ms
executepresent
api surface
sectionoptional
annotations
read onlynot declared
untrusted contentnot declared
titlenot declared
4 findings
warningCanonical entry point
weight 3
Every tool registers through the deprecated navigator.modelContext alias; move them to document.modelContext before the alias is removed.
fix
// document.modelContext is the canonical entry point - the navigator.modelContext alias is deprecated.
document.modelContext.registerTool({ /* ... */ });
warningSchema quality
weight 4
6 of 6 tool schemas are harder for an agent to use than they need to be: get_profile 1 parameter has no description (section).
get_profile: 1 parameter has no description (section); get_projects: 3 parameters have no description (category, limit, offset); get_articles: 3 parameters have no description (category, limit, offset
fix
{
  name: "get_profile",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string", description: "What to search for" }
    },
    required: ["query"]
  }
}
failAnnotations present
weight 4
5 of 5 read-shaped tools do not declare readOnlyHint: true, so an agent has to treat them as possible writes and ask before calling. (Declaring readOnlyHint: false earns nothing - it is the default.)
get_profile, get_projects, get_articles, get_services, calculate_project_cost
fix
{
  name: "get_profile",
  // Declare readOnlyHint: true on tools that truly have no side effects -
  // that is the claim that lets an agent relax confirmation on reads.
  // (false is the default, so declaring it adds no information.)
  annotations: { readOnlyHint: true }
}
warningHuman parity
weight 8
6 tools run through the JavaScript API and the page itself was not graded on this run, so parity could not be confirmed. A visible effect in your existing UI when a tool runs closes the gap.
get_profile, get_projects, get_articles, get_services, submit_contact
fix
// Make the tool's effect visible on the page the person is looking at:
// update the same UI your existing human flow uses when get_profile runs,
// so the person co-browsing sees what the agent just did.
execute: async (args, { signal }) => {
  const result = await performAction(args, signal);
  renderResultInPage(result); // the human-visible half of the same action
  return result;
}
tool json
{
  "name": "get_profile",
  "description": "Retrieve Zain Ahmed's verified multi-cloud engineering credentials (AWS, Azure, GCP, OCI), social profiles, and core specialties.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "section": {
        "type": "string",
        "enum": [
          "all",
          "credentials",
          "bio",
          "contacts"
        ],
        "default": "all"
      }
    }
  },
  "annotations": {}
}
Showing get_profile

Findings

Shared experience

50 / 100 · weight 30
not applicableVisible effect
weight 6
Not invoked on this run: this audit did not call any tool. Scheduled re-audits only read the registry; a live audit from the report page calls the tools that declare readOnlyHint: true and not consequentialHint: true.
not measuredPage experience
weight 16
The page-experience model hop returned no usable result, so the page was not graded.
warningHuman parity
weight 8
6 tools run through the JavaScript API and the page itself was not graded on this run, so parity could not be confirmed. A visible effect in your existing UI when a tool runs closes the gap.
toolget_profile
get_profile, get_projects, get_articles, get_services, submit_contact
fix
// Make the tool's effect visible on the page the person is looking at:
// update the same UI your existing human flow uses when get_profile runs,
// so the person co-browsing sees what the agent just did.
execute: async (args, { signal }) => {
  const result = await performAction(args, signal);
  renderResultInPage(result); // the human-visible half of the same action
  return result;
}

Tool selection

25 / 100 · weight 25
not applicableInvoke success rate
weight 6
Not invoked on this run: this audit did not call any tool. Scheduled re-audits only read the registry; a live audit from the report page calls the tools that declare readOnlyHint: true and not consequentialHint: true.
not measuredTool selection
weight 12
The tool-selection model hop returned no usable result.
failCoverage vs. site type
weight 7
The tool set covers 1 of the 4 things an agent needs on a saas site; it cannot search or browse the catalog or create a record or start a job or update or move an existing record.

Tool quality

56 / 100 · weight 25
warningRegistration timing
weight 1
The slowest tool took 1136ms to register, past the 1000ms an agent reading the registry at first paint would wait for.
toolcalculate_project_cost
calculate_project_cost: registered at 1136ms
fix
// Register tools as soon as they're ready, not behind a deferred/async chunk.
document.modelContext.registerTool({ /* ... */ });
warningCanonical entry point
weight 3
Every tool registers through the deprecated navigator.modelContext alias; move them to document.modelContext before the alias is removed.
toolget_profile
fix
// document.modelContext is the canonical entry point - the navigator.modelContext alias is deprecated.
document.modelContext.registerTool({ /* ... */ });
passSchema validity
weight 4
All 6 declared input schemas are structurally valid object schemas.
warningSchema quality
weight 4
6 of 6 tool schemas are harder for an agent to use than they need to be: get_profile 1 parameter has no description (section).
toolget_profile
get_profile: 1 parameter has no description (section); get_projects: 3 parameters have no description (category, limit, offset); get_articles: 3 parameters have no description (category, limit, offset
fix
{
  name: "get_profile",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string", description: "What to search for" }
    },
    required: ["query"]
  }
}
passNaming quality
weight 2
All 6 tool names are consistent, verb-led, and within Chrome's size guidance.
passStub detection
weight 4
All 6 tools declare an execute handler.
failRegistration errors
weight 2
16 tool registrations threw during the capture, so the registry an agent reads is incomplete.
duplicate tool name registered: get_profile
fix
document.modelContext.registerTool({ /* ... */ }).catch(function (err) {
  console.error("WebMCP registration failed", err);
});
not measuredDescription quality
weight 5
The description-quality model hop returned no usable result, so descriptions were not rated.

Trust

0 / 100 · weight 20
failAnnotations present
weight 4
5 of 5 read-shaped tools do not declare readOnlyHint: true, so an agent has to treat them as possible writes and ask before calling. (Declaring readOnlyHint: false earns nothing - it is the default.)
toolget_profile
get_profile, get_projects, get_articles, get_services, calculate_project_cost
fix
{
  name: "get_profile",
  // Declare readOnlyHint: true on tools that truly have no side effects -
  // that is the claim that lets an agent relax confirmation on reads.
  // (false is the default, so declaring it adds no information.)
  annotations: { readOnlyHint: true }
}
not applicableAnnotation mismatch
weight 4
No tool declares a readOnlyHint, so there is no safety claim to contradict.
not applicableUntrusted content hint
weight 3
No tool's contract suggests it returns text written by somebody other than the site, so there is nothing to flag as untrusted.
not applicableConsequential hint
weight 3
No tool name reads like a consequential action (a purchase, a booking, a payment, a transfer, a deletion), so there is no consequentialHint to expect.
not applicableHint vs. observed
weight 3
Not invoked on this run: this audit did not call any tool. Scheduled re-audits only read the registry; a live audit from the report page calls the tools that declare readOnlyHint: true and not consequentialHint: true.
not measuredInjection surface
weight 3
The injection-surface model hop returned no usable result, so tool contracts were not reviewed for injection surface.

Tool selection

The tool-selection model hop returned no usable result.

Add the tools this site is missing

Our scanner reads your website and suggests the right WebMCP tools for it.
Reads the site's public pages; takes a few seconds.
The open source webmcp plugin teaches your coding agent to audit a site, implement tools on document.modelContext, and verify them in a real browser. npx @ora-ai/webmcp-verify runs the verification on its own. No signup, no hosted service.
how this was captured
observed via
native modelContext
chrome
151.0.7922.34
capture shim
v3
spec snapshot
2026-10-16
mode
fast
pages
1 - entry page only
tools
6
invoked
not invoked; a live audit calls them
run time
16s
finished
Oct 26, 2026
Checked the way in-browser agents discover tools: the top-level document's modelContext registry, read after the page settles.