Repository navigation
Description
Problem
WebMCP has two surfaces that diverge on I/O shapes. Code green in the headless postMessage stub is red in flagged Chrome (chrome://flags/#enable-webmcp-testing, allow="tools" + exposedTo/fromOrigins), and vice versa. Found in one checkout flow, but the bug lives in the kit:
-
Schema is stringified on native —
document.modelContext.getTools()returnsRegisteredTool.inputSchemaas JSON string ("{\"type\":\"object\",…}") perskills/webmcpify/templates/webmcp.d.ts:97+skills/webmcpify/templates/webmcp.spec.ts:67. Forwarding it asparametersto an OpenAI-compatible LLM (Groq/OpenAI) →400 'tools.0.function.parameters' must be an object→ agent loop 502. Stub returnsobject, so same code is green in CI. -
Execution contract differs — stub:
tool.execute(object). Native:RegisteredToolhas no.execute(skills/webmcpify/templates/webmcp.d.ts:93), must bedocument.modelContext.executeTool(tool, JSON.stringify(args))(skills/webmcpify/templates/webmcp.spec.ts:88). Passing object to native throwsUnknownError: Failed to parse input arguments; passing string to stub fails the other way. -
Result is stringified on native — native returns
result: "{\"ok\":true,…}"(string); stub returns object.isinstance(result, dict)/typeof result === 'object'treats native success as empty (last='{}'), stallingsearch-catalog → show-product.
Headless postMessage bridge hides all three — only flagged Chrome surfaces them.
Proposed fix (small, backwards-compat, no new deps)
Principle: handle both shapes everywhere, keep surfaces in sync:
- Tool defs expose both
parameters(OpenAI/LLM) +inputSchema(WebMCP). On nativeinputSchemamust be minimal (type:object+properties/required, nodescriptioninsidepropertieson strict validators). Seeskills/webmcpify/references/integrate.mdexample. - Runner dual-path —
executeTool: tryctx.executeTool(m, JSON.stringify(args))on native, fallback toargsobject onFailed to parse, elsem.execute(object)for stub;resultOk/search resulthelpers handleresultas object or JSON string viaJSON.parsefallback;serializableToolsdoesJSON.parseon stringifiedinputSchemabefore sendingparametersto LLM. - Docs —
references/integrate.mdnotesregisterToolmust useinputSchemaforvalidate:trueon native;references/verify.mddocuments 400 recipe (missingtoolswithtool_choice:none→tool_use_failed; stringifiedparameters) and fixdisable_tool_validation:truewith no forcedtool_choice.
Verification
- Flagged Chrome manual: keyword search →
/search→ product page → cart badge → payment link chip viadocument.modelContext. Previously failing queries nowcount:1,showreceives parsedsku. - Headless stub stays green (object path unchanged) — no regression for
postMessage+page.frameLocator('#agent-iframe')CI.
Files to touch
templates/webmcp.d.ts (optional parameters alias), templates/webmcp.spec.ts (parseResult guard), references/integrate.md, references/verify.md.
Activity
arnabwithab commentedon Sep 3, 2026
Upstream spec clarification: webmachinelearning/webmcp#287 — tracks whether
RegisteredTool.inputSchema/executeTool/ result should be normed as string or object inindex.bs.fix(webmcp): handle native stringified I/O vs stub object (closes Tue…
fix(webmcp): stable string/object shim for native vs stub (closes Tue…