{
  "markdown": "# webmcp-sdk\n\n> **AI Disclosure:** This README was written with AI assistance and reviewed for accuracy.\n\n## The developer toolkit for W3C WebMCP -- the standard shipping in Chrome 146\n\n**Make any website agent-ready in 10 minutes. Built for navigator.modelContext.**\n\n[![W3C Draft](https://img.shields.io/badge/W3C-Draft%20Spec-blue)](https://webmachinelearning.github.io/webmcp/)\n[![Chrome 146 Compatible](https://img.shields.io/badge/Chrome%20146-Compatible-green)](https://chromestatus.com/feature/webmcp)\n[![npm version](https://img.shields.io/npm/v/webmcp-sdk)](https://www.npmjs.com/package/webmcp-sdk)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)\n\n---\n\n## ✅ Google + W3C Validated — Why Now Is the Moment\n\n**March 2026 update:** Google shipped WebMCP in Chrome 146 Canary. Google, Microsoft, and W3C co-authored the specification. This is not a startup experiment — it's Big Tech stamping a new web standard.\n\n### Why Now?\n\n- **Chrome 146 Canary** shipped WebMCP in February 2026. Broad stable release expected mid-to-late 2026.\n- **Google + Microsoft + W3C** co-authored the spec. Three institutions that don't move together unless something matters.\n- **Real implementations are live.** LocalPlate (restaurant booking) shipped WebMCP on Astro. Existing HTML form sites become agent-compatible with minimal changes.\n- **The adoption curve is early.** Developers who ship WebMCP integrations now own the search results, the tutorials, and the mindshare when the stable release lands.\n- **`webmcp-sdk` is the only TypeScript-first implementation toolkit.** We built it before the spec finalized and we maintain it as the standard evolves.\n\nIf you're building for the agentic web, the window to establish yourself as an early implementer is right now.\n\n---\n\n## Why webmcp-sdk?\n\nGoogle and Microsoft co-authored the W3C WebMCP specification. The standard shipped in Chrome 146 Canary (February 2026). **We built the implementation toolkit.**\n\nThe raw `navigator.modelContext` API is low-level. `webmcp-sdk` gives developers a TypeScript-first, production-ready layer on top of it:\n\n- **Zero to agent-ready in 10 minutes** -- declarative HTML attributes or imperative JavaScript\n- **Security middleware built in** -- rate limiting, input sanitization, audit logging\n- **React hooks** -- `useWebMCPTool()` registers on mount, cleans up on unmount\n- **Testing utilities** -- mock browser context, test runner, quality scorer\n- **agentwallet-sdk compatible** -- plug in x402 agent payments with 2 lines of code\n- **50/50 compatibility tests passing** on Chrome 146 Canary\n\nIf you are building for the agentic web, this is the toolkit.\n\n---\n\n## Quick Install\n\n```bash\nnpm i webmcp-sdk\n```\n\n## Fastest Path to First Verified Success\n\n```typescript\nimport { createKit, defineTool } from 'webmcp-sdk';\n\nconst kit = createKit({ prefix: 'demo' });\n\nkit.register(defineTool(\n  'hello',\n  'Return a greeting for the supplied name.',\n  {\n    type: 'object',\n    properties: {\n      name: { type: 'string', description: 'Name to greet' }\n    },\n    required: ['name']\n  },\n  async ({ name }) => {\n    return { message: `Hello, ${name}!` };\n  }\n));\n\nconst result = await kit.invoke('demo.hello', { name: 'Bill' });\nconsole.log(result);\n// { message: 'Hello, Bill!' }\n```\n\nThis works in Node or tests with no browser setup.\n\nWhen `navigator.modelContext` is available in the browser, `kit.register(...)` also registers the tool there automatically. There is no separate `init()` step.\n\n## Browser Registration\n\nCanonical docs and example in this repo:\n- `docs/browser-hello-quickstart.md`\n- `examples/browser-hello/`\n\n```typescript\nimport { createKit, defineTool } from 'webmcp-sdk';\n\nconst kit = createKit({ prefix: 'myshop' });\n\nkit.register(defineTool(\n  'search',\n  'Search products by keyword. Returns matching products with prices and availability.',\n  {\n    type: 'object',\n    properties: {\n      query: { type: 'string', description: 'Search term' },\n      limit: { type: 'number', description: 'Max results' }\n    },\n    required: ['query']\n  },\n  async ({ query, limit = 10 }) => {\n    const results = await db.products.search(query, limit);\n    return { products: results, count: results.length };\n  }\n));\n```\n\nIf WebMCP is available, your tool is now agent-readable.\n\nFor the full browser proof path, including build, local serve, visible result, and auto-registration checks, follow `docs/browser-hello-quickstart.md` and use `examples/browser-hello/`.\n\n---\n\n## React Integration\n\n```tsx\nimport { useWebMCPTool } from 'webmcp-sdk/react';\n\nfunction ProductSearch() {\n  useWebMCPTool({\n    name: 'search_products',\n    description: 'Search the product catalog',\n    inputSchema: {\n      type: 'object',\n      properties: { query: { type: 'string' } },\n      required: ['query']\n    },\n    handler: async ({ query }) => searchProducts(query)\n  });\n\n  return <SearchUI />;\n}\n```\n\n---\n\n## Security Middleware (Express)\n\n```typescript\nimport { webmcpDiscovery } from 'webmcp-sdk/middleware/express';\n\napp.use(webmcpDiscovery({\n  serverName: 'My API',\n  manifestPath: '/mcp'\n}));\n```\n\n---\n\n## Testing\n\n```typescript\nimport { defineTool } from 'webmcp-sdk';\nimport { createMockContext, testTool, formatTestResults } from 'webmcp-sdk/testing';\n\nconst searchTool = defineTool(\n  'search_products',\n  'Search the product catalog by keyword.',\n  {\n    type: 'object',\n    properties: {\n      query: { type: 'string', description: 'Search keyword' }\n    },\n    required: ['query']\n  },\n  async ({ query }) => ({ results: [{ name: `Product for ${query}` }], total: 1 })\n);\n\nconst { context, invoke } = createMockContext();\ncontext.registerTool(searchTool);\n\nconst result = await invoke('search_products', { query: 'laptop' });\nconsole.log(result);\n// { results: [{ name: 'Product for laptop' }], total: 1 }\n\nconst results = await testTool(searchTool, [\n  {\n    name: 'basic search',\n    input: { query: 'laptop' },\n    expectSuccess: true,\n    validate: (value) => Array.isArray(value.results)\n  }\n]);\n\nconsole.log(formatTestResults(results));\n```\n\n---\n\n## agentwallet-sdk Integration (x402 Payments)\n\nPair with `agent-wallet-sdk` to accept x402 micropayments inside your WebMCP tools:\n\n```typescript\nimport { createKit, defineTool } from 'webmcp-sdk';\nimport { AgentWallet } from 'agent-wallet-sdk';\n\nconst kit = createKit({ prefix: 'api' });\nconst wallet = new AgentWallet({ chain: 'base', privateKey: process.env.AGENT_KEY });\n\nkit.register(defineTool(\n  'premium_data',\n  'Fetch premium market data (0.01 USDC per call)',\n  {\n    type: 'object',\n    properties: {\n      symbol: { type: 'string', description: 'Market symbol to fetch' },\n      agentAddress: { type: 'string', description: 'Payer address to charge' }\n    },\n    required: ['symbol', 'agentAddress']\n  },\n  async ({ symbol, agentAddress }) => {\n    await wallet.receiveX402Payment(agentAddress, '0.01');\n    return fetchPremiumData(symbol);\n  }\n));\n```\n\n---\n\n## The W3C WebMCP Specification\n\nWebMCP is a W3C draft specification that adds a `navigator.modelContext` API to browsers. It lets AI agents interact with web pages through a standardized interface — registering tools, reading structured context, and calling functions declared by the page.\n\n**Key links:**\n- [W3C Spec Draft](https://webmachinelearning.github.io/webmcp/)\n- [Chrome Status](https://chromestatus.com/feature/webmcp)\n- [awesome-webmcp](https://github.com/up2itnow0822/awesome-webmcp)\n\n---\n\n## Claude Code Compatibility\n\nCompanion note in this repo:\n- `docs/claude-code-polyfill-bridge.md`\n\n`webmcp-sdk` works with Claude Code's Chrome Extension through the `@mcp-b/global` polyfill. Here's how the pieces connect:\n\n**How it works:** When Claude Code's Chrome Extension visits a page that has `webmcp-sdk` tool registration code on it, the extension detects `navigator.modelContext` (provided by the polyfill in pre-stable Chrome, or natively in Chrome 146+). Claude discovers your registered tools and can invoke them directly from the chat interface.\n\n**Setup for site owners:**\n\nYou can also start from the repo example in `examples/browser-hello/` and swap its `demo.hello` tool for your real tool.\n\n```html\n<!-- Load the polyfill for browsers without native navigator.modelContext -->\n<script src=\"https://unpkg.com/@mcp-b/global\"></script>\n\n<!-- Your webmcp-sdk tool registration -->\n<script type=\"module\">\n  import { createKit, defineTool } from 'webmcp-sdk';\n\n  const kit = createKit({ prefix: 'mysite' });\n  kit.register(defineTool(\n    'search',\n    'Search this site',\n    { type: 'object', properties: { q: { type: 'string' } }, required: ['q'] },\n    async ({ q }) => siteSearch(q)\n  ));\n</script>\n```\n\n**What Claude Code users get:** When visiting your page with the Claude Chrome Extension active, your site's tools appear alongside Claude's built-in MCP tools. No configuration needed on the user's side - discovery is automatic through `navigator.modelContext`.\n\n**Tracking native support:** GitHub Issue [#30645](https://github.com/anthropics/claude-code/issues/30645) on `anthropics/claude-code` tracks native WebMCP support in the Claude Chrome Extension. The polyfill bridges the gap until that ships.\n\n**Compatibility matrix:**\n\n| Browser | WebMCP Support | Notes |\n|---|---|---|\n| Chrome 146 Canary | Native `navigator.modelContext` | Full support, no polyfill needed |\n| Chrome stable (pre-146) | Via `@mcp-b/global` polyfill | Works with Claude Chrome Extension |\n| Edge | Expected (Chromium-based) | Tracking W3C spec adoption |\n| Firefox / Safari | Not yet | W3C working group stage |\n\n## Proxy Relay — Reach Private Endpoints From the Browser Sandbox\n\nChrome's Content Security Policy blocks tool handlers from calling private APIs directly. The **Proxy Relay** routes those calls through a local HTTP server (or a Service Worker) so your tools can reach authenticated, internal, or CORS-restricted endpoints without opening up your CSP.\n\n### Quick Start\n\n```typescript\nimport { createKit, defineTool } from 'webmcp-sdk';\n\n// Pass the relay endpoint once — it's available on kit.proxy everywhere\nconst kit = createKit({ proxyEndpoint: 'http://localhost:3001' });\n\nkit.register(defineTool(\n  'internal-data',\n  'Fetch data from a private internal API',\n  { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] },\n  async ({ id }) => {\n    const res = await kit.proxy!.get<{ name: string }>(\n      `https://internal-api.company.com/records/${id}`\n    );\n    if (!res.ok) throw new Error(`Upstream error: ${res.status}`);\n    return res.data;\n  }\n));\n```\n\n### ProxyRelay Standalone\n\n```typescript\nimport { ProxyRelay } from 'webmcp-sdk';\n\nconst relay = new ProxyRelay({\n  relayUrl: 'http://localhost:3001',\n  auth: { type: 'bearer', token: process.env.MY_API_KEY! },\n  defaultTimeoutMs: 10_000,\n});\n\n// GET\nconst { data } = await relay.get<User[]>('https://api.private.com/users');\n\n// POST\nconst { data: created } = await relay.post('https://api.private.com/users', {\n  name: 'Alice',\n  role: 'admin',\n});\n```\n\n### Auth Strategies\n\n```typescript\n// API key header\nnew ProxyRelay({ relayUrl: '...', auth: { type: 'apiKey', header: 'X-Api-Key', key: 'secret' } });\n\n// Bearer token\nnew ProxyRelay({ relayUrl: '...', auth: { type: 'bearer', token: 'my-jwt' } });\n\n// Custom headers\nnew ProxyRelay({ relayUrl: '...', auth: { type: 'custom', headers: { 'X-Tenant': 'acme' } } });\n```\n\n### Service Worker Bridge\n\nFor zero-infrastructure setups, the relay can use a `BroadcastChannel` to dispatch requests through a registered Service Worker:\n\n```typescript\nconst relay = new ProxyRelay({\n  relayUrl: '/sw-proxy',\n  useServiceWorker: true,\n});\n```\n\nYour Service Worker listens on the `'webmcp-proxy'` BroadcastChannel, forwards the request, and posts back the response.\n\n---\n\n## Tamper-Evident Audit Logging\n\nEvery tool invocation can be recorded in a cryptographic hash chain. Any post-hoc modification to the log is immediately detectable — each entry commits to the previous entry's hash, forming an append-only audit trail.\n\n### Enable With One Line\n\n```typescript\nconst kit = createKit({ audit: true });\n\nkit.register(defineTool(\n  'search',\n  'Search products',\n  { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] },\n  async ({ query }) => searchProducts(query)\n));\n\nawait kit.invoke('search', { query: 'headphones' });\nawait kit.invoke('search', { query: 'laptop' });\n\n// Inspect the log\nconst entries = kit.getAuditLog();\nconsole.log(entries[0]);\n// {\n//   index: 0,\n//   timestamp: '2026-03-11T10:30:00.000Z',\n//   timestampMs: 1741691400000,\n//   toolName: 'search',\n//   inputHash:  'a3f2...', // SHA-256 of JSON.stringify(input)\n//   outputHash: 'b8c1...', // SHA-256 of JSON.stringify(output)\n//   error: null,\n//   prevHash: '',          // empty for genesis entry\n//   entryHash: 'e4d9...'   // SHA-256 over all fields above\n// }\n\n// Verify the full chain hasn't been tampered with\nconst isValid = kit.verifyAuditLog();\nconsole.log(isValid); // true\n```\n\n### AuditLog Standalone\n\n```typescript\nimport { AuditLog } from 'webmcp-sdk';\n\nconst log = new AuditLog();\n\nlog.record('my-tool', { query: 'hello' }, { result: 'world' });\nlog.recordError('my-tool', { query: 'bad' }, new Error('upstream timeout'));\n\nconst result = log.verify();\nif (!result.valid) {\n  console.error(`Chain broken at entry ${result.index}: ${result.reason}`);\n}\n\n// Export for persistence\nconst json = log.export();\nlocalStorage.setItem('audit-log', json);\n\n// Re-import and re-verify\nconst log2 = new AuditLog();\nlog2.import(json);\nconsole.log(log2.verify().valid); // true (or false if storage was tampered with)\n```\n\n### How the Hash Chain Works\n\n```\nEntry 0: { inputHash, outputHash, timestamp, toolName, prevHash: \"\" }\n         → entryHash = SHA256(canonical(entry 0))\n\nEntry 1: { inputHash, outputHash, timestamp, toolName, prevHash: entryHash(0) }\n         → entryHash = SHA256(canonical(entry 1))\n\nEntry N: { ..., prevHash: entryHash(N-1) }\n         → entryHash = SHA256(canonical(entry N))\n```\n\n`verifyAuditLog()` walks the chain and recomputes every `entryHash`. If any field in any entry was changed after recording, the recomputed hash won't match and verification returns `false`.\n\n---\n\n## Security\n\n**MCP security is an active concern.** The [OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/) documents the primary attack surfaces for Model Context Protocol implementations, including tool poisoning, prompt injection via tool output, and covert channel abuse.\n\nwebmcp-sdk includes security helpers under `webmcp-sdk/security`, including `withSecurity`, `RateLimiter`, and `sanitizeInput`. However, no SDK eliminates all MCP-related risks. Before deploying in production:\n\n- Review the [OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/) and assess which risks apply to your use case\n- Implement an MCP tool allowlist (deny-all by default, allow only what you need)\n- Enable audit logging for all tool calls\n- Monitor for abnormal call patterns (frequency spikes, oversized responses)\n- Keep webmcp-sdk updated - security patches are prioritized\n\nFor a full enterprise MCP allowlist template, see our guide: [Build Your Own MCP Allowlist](https://ai-agent-economy.hashnode.dev/build-your-own-mcp-allowlist-enterprise-security-template-2026).\n\nRecent vulnerabilities in MCP ecosystems (Azure CVE-2026-26118 SSRF CVSS 8.8, Atlassian CVE-2026-27825 RCE) reinforce that MCP security requires defense in depth, not just SDK-level protections.\n\n---\n\n## Contributing\n\nPRs welcome. Run `npm test` before submitting. The spec is evolving - if you find a Chrome 146 compatibility issue, open an issue with your Canary version.\n\n---\n\n## License\n\nMIT\n",
  "bytes": 15694,
  "sha": "36737d07d834b1af86293f0a13c3ce16fc404df8a43fbded0462ef3a222a3f1d",
  "repo_slug": "up2itnow0822/webmcp-sdk",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_up2itnow0822_webmcp_sdk_2bfb8b2c/readme"
}