Skip to content

Comments

Adapt to the latest WebMCP spec#5

Merged
igrigorik merged 1 commit intoigrigorik:mainfrom
madmath:main
Jan 28, 2026
Merged

Adapt to the latest WebMCP spec#5
igrigorik merged 1 commit intoigrigorik:mainfrom
madmath:main

Conversation

@madmath
Copy link
Contributor

@madmath madmath commented Jan 27, 2026

Align WebMCP polyfill with Chrome Canary's native implementation

Tested in 146.0.7652.0 canary

  • Separated page-side and agent-side APIs to match Chrome's WebMCP spec: navigator.modelContext for pages to register tools (registerTool, unregisterTool, provideContext, clearContext) and navigator.modelContextTesting for agents to discover/execute tools (listTools, executeTool, registerToolsChangedCallback)

  • Fixed Chrome native API compatibility: executeTool() now accepts args as JSON string (Chrome's format), and inputSchema returned from listTools() is automatically parsed from JSON string to object in lifecycle.ts

  • Added CSP-safe Ajv shim (src/lib/ajv-csp-safe.js) to replace real Ajv which uses new Function() that violates Chrome extension CSP, also fixing the ESM default export issue

  • Updated page-bridge.js to use spec-aligned method names (executeTool, registerToolsChangedCallback) and removed dead fallback code that referenced non-existent methods on the separated APIs

  • Maintained backward compatibility via window.agent which combines both page-side and agent-side methods for existing scripts, while new code should use the separated modelContext/modelContextTesting APIs

'@types': path.resolve(__dirname, './src/types'),
// Use CSP-safe Ajv shim - real Ajv uses new Function() which violates extension CSP
// Also fixes ESM import issue (ajv doesn't have default export in ESM)
ajv: path.resolve(__dirname, 'src/lib/ajv-csp-safe.js'),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clever.

Copy link
Owner

@igrigorik igrigorik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice work!

@igrigorik igrigorik merged commit c770fcf into igrigorik:main Jan 28, 2026
2 checks passed
Copy link

@beaufortfrancois beaufortfrancois left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I've tried it locally and it works great!

name: 'my_tool',
description: 'Does something useful',
inputSchema: { type: 'object', properties: {} },
execute: async (args, agent) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: async is optional there.

- `unregisterTool(name)` - Remove a tool by name
- `clearContext()` - Remove all tools
- `listTools()` - Get current tool definitions (without execute functions)
- `callTool(name, args)` - Invoke a tool (used by the agent, not typically by tools)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be renamed to executeTool?

// Create agent context for this tool execution
const agentContext = createAgentContext();
// Per WebMCP spec: execute(params, agent)
return await Promise.resolve(tool.execute(params, agentContext));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naive question: Why not return await tool.execute(params, agentContext); only?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants