{"_id":"@ashraf009/webmcp-kit","name":"@ashraf009/webmcp-kit","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ashraf009/webmcp-kit","version":"0.1.0","description":"Typed helpers for building WebMCP tool surfaces: registration, React hooks for scoped/dynamic tools, an activity log, and confirmation gating.","type":"module","license":"MIT","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js"}},"scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit","prepare":"tsc -p tsconfig.json"},"peerDependencies":{"react":">=18"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/react":"^18.3.12","react":"^18.3.1","typescript":"^5.6.3"},"_id":"@ashraf009/webmcp-kit@0.1.0","gitHead":"9d5959c7ec2759b3ae7adbf3700eb5d04b79a84d","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-REpP1BhjlcGJD8aiNgIu3VTTFxvhT32cbbO0oeQEpOlPcWj1N/gxAnE4+LdCLYq4/otUFZBUjAxmUwN4LSc7pQ==","shasum":"d3b21b19cb38dee3050a30d82a2ecefc9d4de6b4","tarball":"https://registry.npmjs.org/@ashraf009/webmcp-kit/-/webmcp-kit-0.1.0.tgz","fileCount":24,"unpackedSize":31502,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDpu+bncTfIbKj3I4YN9+aqlNG3JCPq1N+Uz+irLbzX9QIhALVjBnS7jlug95SvU2m1r94N7QWCKCJVULjGhMkuPHTT"}]},"_npmUser":{"name":"ashraf009","email":"ashrafahmed1232@gmail.com"},"directories":{},"maintainers":[{"name":"ashraf009","email":"ashrafahmed1232@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webmcp-kit_0.1.0_1788426114914_0.7950625088862797"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-03T09:01:54.625Z","0.1.0":"2026-09-03T09:01:55.038Z","modified":"2026-09-03T09:01:55.305Z"},"maintainers":[{"name":"ashraf009","email":"ashrafahmed1232@gmail.com"}],"description":"Typed helpers for building WebMCP tool surfaces: registration, React hooks for scoped/dynamic tools, an activity log, and confirmation gating.","license":"MIT","readme":"# webmcp-kit\n\nTyped helpers for building [WebMCP](https://github.com/webmachinelearning/webmcp) tool surfaces: schema-inferred tool definitions, React hooks for dynamic/scoped tool sets, an activity log, and confirmation gating for consequential actions.\n\nBuilt while implementing three apps for the OpenAI WebMCP Challenge ([Cadence](../../apps/cadence), [Consequence](../../apps/consequence), [Relay](../../apps/relay)). All three needed the same registration, lifecycle, and confirmation logic, so it got pulled out here instead of copy-pasted three times.\n\n## Install\n\n```bash\nnpm install @ashraf009/webmcp-kit\n```\n\n## Core idea\n\nA tool's logic is a plain async function: `handler(input) => output`, no WebMCP-specific code inside it. `defineTool` is the only place that knows about the `{ content: [...] }` result shape:\n\n```ts\nimport { defineTool } from \"@ashraf009/webmcp-kit\";\n\nexport const searchIssues = defineTool({\n  name: \"search_issues\",\n  description: \"Search issues by title and body text.\",\n  inputSchema: {\n    type: \"object\",\n    properties: {\n      query: { type: \"string\", description: \"Search text\" },\n      limit: { type: \"number\" },\n    },\n    required: [\"query\"],\n    additionalProperties: false,\n  } as const,\n  annotations: { readOnlyHint: true },\n  async handler({ query, limit }) {\n    // fully typed: query: string, limit: number | undefined\n    return searchIssuesInStore(query, limit);\n  },\n});\n```\n\nBecause the handler returns a plain value instead of a wrapped WebMCP result, the *same* function drives both the real `document.modelContext.registerTool` call and a simulated-agent fallback UI. That's what keeps an app fully explorable in a browser without WebMCP support. Put the logic inside a raw `execute` closure instead, and now you're maintaining two implementations that can quietly drift apart.\n\n## Registering tools\n\n```ts\nimport { registerTools } from \"@ashraf009/webmcp-kit\";\n\nconst controller = new AbortController();\nregisterTools([searchIssues, createIssue], { signal: controller.signal });\n// controller.abort() unregisters everything registered in this call\n```\n\nNo-ops cleanly when `document.modelContext` isn't present. Callers never need to branch on `isWebMCPAvailable()` themselves.\n\n## Dynamic, scoped tool sets (React)\n\n```tsx\nimport { useScopedTools } from \"@ashraf009/webmcp-kit/react\";\n\nfunction IssueDetail({ issue }: { issue: Issue }) {\n  useScopedTools(\n    true,\n    () => [addComment(issue.id), splitIssue(issue.id), setEstimate(issue.id)],\n    {},\n    [issue.id],\n  );\n  // ...\n}\n```\n\nThe tool set is registered only while `active` is true, and unregisters the moment it becomes false or a dependency changes. This is the primitive behind every dynamic tool surface in this repo: an issue selected, a filter applied, a reviewer role granted, each exposing a different tool set. A static server-side MCP tool list can't do that. The set here is a function of live page state.\n\n## Confirmation gating\n\n```ts\nimport { withConfirmation } from \"@ashraf009/webmcp-kit\";\n\nexport const bulkUpdate = withConfirmation(bulkUpdateDefinition, async (input) => {\n  return await showConfirmDialog(`Apply this change to ${input.issueIds.length} issues?`);\n});\n```\n\nIf the human declines, the handler never runs and the agent receives a clear refusal rather than a silent no-op.\n\n## Activity log\n\n```ts\nimport { createActivityLog } from \"@ashraf009/webmcp-kit\";\n\nconst log = createActivityLog();\nregisterTools(tools, { onInvoke: (entry) => log.log({ ...entry, actor: \"agent\" }) });\nlog.subscribe((entry, all) => renderFeed(all));\n```\n\nFeed this into a visible \"agent activity feed.\" It's the thing that makes an invisible protocol legible to a person watching over the agent's shoulder.\n\n## API\n\n- `defineTool(definition)`: typed tool definition with schema-inferred handler input.\n- `registerTools(tools, options?)`: batch registration with feature detection and an `onInvoke` hook.\n- `withConfirmation(tool, confirm)`: wraps a tool to require human approval before it runs.\n- `createActivityLog(options?)`: subscribable store of tool invocations.\n- `text(value)` / `json(value)` / `refusal(reason)`: WebMCP result-shape helpers, for tools written against the raw API directly.\n- `isWebMCPAvailable()`: feature detection.\n- React: `useWebMCPTool`, `useWebMCPTools`, `useScopedTools`. Lifecycle-managed registration hooks.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-f9f52b58209f15d2b4fa88efe2ca921a"}