{"_id":"@napster-corp/edge-mcp","_rev":"16-dd03c6321f7fef04329f5d626f5699c1","name":"@napster-corp/edge-mcp","dist-tags":{"latest":"0.2.0"},"versions":{"1.0.1":{"name":"@napster-corp/edge-mcp","version":"1.0.1","keywords":["webmcp","model-context","document.modelContext","agent","ai-agent","mcp","polyfill","in-browser","tools"],"license":"MIT","_id":"@napster-corp/edge-mcp@1.0.1","maintainers":[{"name":"dima-napster","email":"dima@napster.com"},{"name":"bratumarius2005","email":"marius.bratu@napster.com"},{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"}],"homepage":"https://github.com/napster-corp/edge-mcp#readme","bugs":{"url":"https://github.com/napster-corp/edge-mcp/issues"},"bin":{"edge-mcp":"bin/edge-mcp.mjs"},"dist":{"shasum":"df5cc4062e63961eb96c9f6f3a6f389d056e3ac9","tarball":"https://registry.npmjs.org/@napster-corp/edge-mcp/-/edge-mcp-1.0.1.tgz","fileCount":48,"integrity":"sha512-hJ15aXnb/poDwr0YLu+VwRXDAQ5joAqUPnIedS4qgEa2v4MFY/h3tbeuRroSqjwBSXWzTLcGtiq4TV08kdHP6w==","signatures":[{"sig":"MEQCIBRNEqhvp6ovhYZvM8zOV4ajLfEqHWp0FqnPBYUxzLlZAiA5fvZq2RNfGxjmMI/MVbAV4/QYlhBqtkDd5qWthPgKyQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":293666},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","browser":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dev-panel":{"types":"./dist/dev-panel.d.ts","import":"./dist/dev-panel.js"}},"gitHead":"2a862de6bd068ed59474a6b18514357a868ffa3d","scripts":{"test":"tsx --test tests/*.test.ts","build":"tsc","clean":"rm -rf dist","generate":"node ./bin/edge-mcp.mjs generate","install-hook":"node ./bin/edge-mcp.mjs install-hook","prepublishOnly":"npm run clean && npm run build && npm test"},"_npmUser":{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"},"deprecated":"Pre-release iteration — use the 0.x line instead.","repository":{"url":"git+https://github.com/napster-corp/edge-mcp.git","type":"git"},"_npmVersion":"11.9.0","description":"Napster Edge MCP — polyfills the WebMCP standard (document.modelContext) cross-browser and adds live state, safety tiers, and dev tooling. Write standard registerTool calls; any compatible agent (including Napster's) can operate your app.","directories":{},"sideEffects":["./dist/index.js","./src/index.ts"],"_nodeVersion":"24.14.0","dependencies":{"@mcp-b/webmcp-polyfill":"3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","typescript":"^5.4.0"},"peerDependencies":{"@anthropic-ai/claude-agent-sdk":"^0.3.0"},"peerDependenciesMeta":{"@anthropic-ai/claude-agent-sdk":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/edge-mcp_1.0.1_1782390563200_0.9487098454526799","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@napster-corp/edge-mcp","version":"1.1.0","keywords":["webmcp","model-context","document.modelContext","agent","ai-agent","mcp","polyfill","in-browser","tools"],"license":"MIT","_id":"@napster-corp/edge-mcp@1.1.0","maintainers":[{"name":"dima-napster","email":"dima@napster.com"},{"name":"bratumarius2005","email":"marius.bratu@napster.com"},{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"}],"homepage":"https://bitbucket.org/touchcastllc/napster-edge-mcp","bugs":{"url":"https://bitbucket.org/touchcastllc/napster-edge-mcp/issues"},"bin":{"edge-mcp":"bin/edge-mcp.mjs"},"dist":{"shasum":"7e14656f72a19c61b6b6b4d4749b943b80737663","tarball":"https://registry.npmjs.org/@napster-corp/edge-mcp/-/edge-mcp-1.1.0.tgz","fileCount":47,"integrity":"sha512-FPYXDbqj8yHOQFx9G9WzJxfzjOvO2GNpqbeNz++uVxW7z/ZiD79xvNbwDLzt9RLXLFUQ7UE4qtFWagVDi1J5Mw==","signatures":[{"sig":"MEYCIQDeLQihhT/pcc8CDFL3N0Xk86VMdyLU8wD838UakG+vHAIhAIZWYNOnbnYmybFPIR1fy945dkq8WrEwbTd0MWfgrFU5","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":321278},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","browser":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dev-panel":{"types":"./dist/dev-panel.d.ts","import":"./dist/dev-panel.js"}},"gitHead":"fbca74fd7f4007c1f628b9bab2afa2bc751633e9","scripts":{"test":"tsx --test tests/*.test.ts","build":"tsc","clean":"rm -rf dist","generate":"node ./bin/edge-mcp.mjs generate","install-hook":"node ./bin/edge-mcp.mjs install-hook","install-rule":"node ./bin/edge-mcp.mjs install-rule","prepublishOnly":"npm run clean && npm run build && npm test"},"_npmUser":{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"},"deprecated":"Pre-release iteration — use the 0.x line instead.","repository":{"url":"git+https://bitbucket.org/touchcastllc/napster-edge-mcp.git","type":"git"},"_npmVersion":"11.9.0","description":"Napster Edge MCP — polyfills the WebMCP standard (document.modelContext) cross-browser and adds live state and dev tooling. Write standard registerTool calls with standard annotations; any compatible agent (including Napster's) can operate your app.","directories":{},"sideEffects":["./dist/index.js","./src/index.ts"],"_nodeVersion":"24.14.0","dependencies":{"@cfworker/json-schema":"4.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","typescript":"^5.4.0","@mcp-b/webmcp-types":"3.0.0","@standard-schema/spec":"^1.1.0"},"peerDependencies":{"@anthropic-ai/claude-agent-sdk":"^0.3.0"},"peerDependenciesMeta":{"@anthropic-ai/claude-agent-sdk":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/edge-mcp_1.1.0_1782820732377_0.9702604509915895","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@napster-corp/edge-mcp","version":"1.1.1","keywords":["webmcp","model-context","document.modelContext","agent","ai-agent","mcp","polyfill","in-browser","tools"],"license":"MIT","_id":"@napster-corp/edge-mcp@1.1.1","maintainers":[{"name":"dima-napster","email":"dima@napster.com"},{"name":"bratumarius2005","email":"marius.bratu@napster.com"},{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"}],"homepage":"https://bitbucket.org/touchcastllc/napster-edge-mcp","bugs":{"url":"https://bitbucket.org/touchcastllc/napster-edge-mcp/issues"},"bin":{"edge-mcp":"bin/edge-mcp.mjs"},"dist":{"shasum":"4240fe0cbdce85078a1515e423f8a2cff7e57376","tarball":"https://registry.npmjs.org/@napster-corp/edge-mcp/-/edge-mcp-1.1.1.tgz","fileCount":47,"integrity":"sha512-M8FFik0JQFhKcZQXprtJn3rdwrUcMK/Qc4eFKMudx4fyMGu8apdswwS7CBNJcGwUATr5WsEEv/E5wU4XoDEg9w==","signatures":[{"sig":"MEUCIQCmAyyqVJOKG7rxH1ozGHwC3x5YkO58derCT+BH0itIVgIgYe9HtaKcXpcXj5VYIUfoO7+YFTX/FMoyIcVHLxFXbDg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":321271},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","browser":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dev-panel":{"types":"./dist/dev-panel.d.ts","import":"./dist/dev-panel.js"}},"gitHead":"00fc631d9256fa5d69edbe7e0f42d036bdfeadf2","scripts":{"test":"tsx --test tests/*.test.ts","build":"tsc","clean":"rm -rf dist","generate":"node ./bin/edge-mcp.mjs generate","install-hook":"node ./bin/edge-mcp.mjs install-hook","install-rule":"node ./bin/edge-mcp.mjs install-rule","prepublishOnly":"npm run clean && npm run build && npm test"},"_npmUser":{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"},"deprecated":"Pre-release iteration — use the 0.x line instead.","repository":{"url":"git+https://bitbucket.org/touchcastllc/napster-edge-mcp.git","type":"git"},"_npmVersion":"11.9.0","description":"Napster Edge MCP — polyfills the WebMCP standard (document.modelContext) cross-browser and adds live state and dev tooling. Write standard registerTool calls with standard annotations; any compatible agent (including Napster's) can operate your app.","directories":{},"sideEffects":["./dist/index.js","./src/index.ts"],"_nodeVersion":"24.14.0","dependencies":{"@cfworker/json-schema":"4.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","typescript":"^5.4.0","@mcp-b/webmcp-types":"3.0.0","@standard-schema/spec":"^1.1.0"},"peerDependencies":{"@anthropic-ai/claude-agent-sdk":"^0.3.0"},"peerDependenciesMeta":{"@anthropic-ai/claude-agent-sdk":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/edge-mcp_1.1.1_1782828826068_0.9679718278976179","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@napster-corp/edge-mcp","version":"0.1.0","keywords":["webmcp","model-context","document.modelContext","agent","ai-agent","mcp","polyfill","in-browser","tools"],"license":"MIT","_id":"@napster-corp/edge-mcp@0.1.0","maintainers":[{"name":"dima-napster","email":"dima@napster.com"},{"name":"bratumarius2005","email":"marius.bratu@napster.com"},{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"}],"homepage":"https://developers.napster.com","bin":{"edge-mcp":"bin/edge-mcp.mjs"},"dist":{"shasum":"afa2b41db0145359ca72a5372351584d71dadaa9","tarball":"https://registry.npmjs.org/@napster-corp/edge-mcp/-/edge-mcp-0.1.0.tgz","fileCount":49,"integrity":"sha512-yEoc4QhzwtlZvg2M5PV4k9uJnW99J9ISBnLE72cq2LGMkoHW5W4kOGeBEHFnoM3Dwvn14YCT2T41TyxjoRmJaA==","signatures":[{"sig":"MEQCICO5Pj2A33uI6YgyiJM1DrPlV2jZeBdyN9tCYmBrh1vRAiAyRXG1jW3Lw2tPwveUqXPiJzKKVbR/kROlXNH8YS6MRw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":460844},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","browser":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dev-panel":{"types":"./dist/dev-panel.d.ts","import":"./dist/dev-panel.js"}},"gitHead":"97062f85e03fb82f3959c488c52e1a3dcea814c8","scripts":{"test":"tsx --test tests/*.test.ts","build":"tsc && npm run build:browser","clean":"rm -rf dist","generate":"node ./bin/edge-mcp.mjs generate","install-hook":"node ./bin/edge-mcp.mjs install-hook","install-rule":"node ./bin/edge-mcp.mjs install-rule","build:browser":"esbuild src/index.ts --bundle --minify --format=iife --global-name=EdgeMCP --target=es2019 --outfile=dist/edge-mcp.iife.min.js && esbuild src/dev-panel.ts --bundle --minify --format=iife --global-name=EdgeMcpDevPanel --target=es2019 --outfile=dist/edge-mcp-dev-panel.iife.min.js","prepublishOnly":"npm run clean && npm run build && npm test"},"_npmUser":{"name":"bratumarius2005","email":"marius.bratu@napster.com"},"_npmVersion":"10.8.2","description":"Napster Edge MCP — polyfills the WebMCP standard (document.modelContext) cross-browser and adds live state and dev tooling. Write standard registerTool calls with standard annotations; any compatible agent (including Napster's) can operate your app.","directories":{},"sideEffects":["./dist/index.js","./src/index.ts"],"_nodeVersion":"20.20.1","dependencies":{"@cfworker/json-schema":"4.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","esbuild":"^0.28.1","typescript":"^5.4.0","@standard-schema/spec":"^1.1.0"},"peerDependencies":{"@anthropic-ai/claude-agent-sdk":"^0.3.0"},"peerDependenciesMeta":{"@anthropic-ai/claude-agent-sdk":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/edge-mcp_0.1.0_1783497404668_0.0851118928219885","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@napster-corp/edge-mcp","version":"0.1.1","keywords":["webmcp","model-context","document.modelContext","agent","ai-agent","mcp","polyfill","in-browser","tools"],"license":"MIT","_id":"@napster-corp/edge-mcp@0.1.1","maintainers":[{"name":"dima-napster","email":"dima@napster.com"},{"name":"bratumarius2005","email":"marius.bratu@napster.com"},{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"}],"homepage":"https://developers.napster.com","bin":{"edge-mcp":"bin/edge-mcp.mjs"},"dist":{"shasum":"d7bd127a87daec3a7abcf908344319224a21fde8","tarball":"https://registry.npmjs.org/@napster-corp/edge-mcp/-/edge-mcp-0.1.1.tgz","fileCount":48,"integrity":"sha512-aTWPESA2xPeqUGCknmLAczuSKpIlDNQIOiDCilHcIgXIfL+9uyCe4vjfzgWzH2kCOcXSfn/7jeGhlW3yCfhYTQ==","signatures":[{"sig":"MEUCIQC5VWWDsl+0FwSCBOKOX8/FEvHrd/q7VDJv4pTq+VPr7wIgKWp3YG4RHgYx9BYbQ0iwaumdLIY8UPmOuWF4KGL1niU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":458732},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","browser":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dev-panel":{"types":"./dist/dev-panel.d.ts","import":"./dist/dev-panel.js"}},"gitHead":"dba99986d53f856cc7dbf899a2f345c4316c2e67","scripts":{"test":"tsx --test tests/*.test.ts","build":"tsc && npm run build:browser","clean":"rm -rf dist","generate":"node ./bin/edge-mcp.mjs generate","install-hook":"node ./bin/edge-mcp.mjs install-hook","build:browser":"esbuild src/index.ts --bundle --minify --format=iife --global-name=EdgeMCP --target=es2019 --outfile=dist/edge-mcp.iife.min.js && esbuild src/dev-panel.ts --bundle --minify --format=iife --global-name=EdgeMcpDevPanel --target=es2019 --outfile=dist/edge-mcp-dev-panel.iife.min.js","prepublishOnly":"npm run clean && npm run build && npm test"},"_npmUser":{"name":"bratumarius2005","email":"marius.bratu@napster.com"},"_npmVersion":"10.8.2","description":"Napster Edge MCP — polyfills the WebMCP standard (document.modelContext) cross-browser and adds live state and dev tooling. Write standard registerTool calls with standard annotations; any compatible agent (including Napster's) can operate your app.","directories":{},"sideEffects":["./dist/index.js","./src/index.ts"],"_nodeVersion":"20.20.1","dependencies":{"@cfworker/json-schema":"4.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","esbuild":"^0.28.1","typescript":"^5.4.0","@standard-schema/spec":"^1.1.0"},"peerDependencies":{"@anthropic-ai/claude-agent-sdk":"^0.3.0"},"peerDependenciesMeta":{"@anthropic-ai/claude-agent-sdk":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/edge-mcp_0.1.1_1783594479722_0.5804363062650546","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@napster-corp/edge-mcp","version":"0.2.0","description":"Napster Edge MCP — polyfills the WebMCP standard (document.modelContext) cross-browser and adds live state and dev tooling. Write standard registerTool calls with standard annotations; any compatible agent (including Napster's) can operate your app.","type":"module","main":"./dist/index.js","module":"./dist/index.js","browser":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dev-panel":{"types":"./dist/dev-panel.d.ts","import":"./dist/dev-panel.js"}},"bin":{"edge-mcp":"bin/edge-mcp.mjs"},"scripts":{"build":"tsc && npm run build:browser","build:browser":"esbuild src/index.ts --bundle --minify --format=iife --global-name=EdgeMCP --target=es2019 --outfile=dist/edge-mcp.iife.min.js && esbuild src/dev-panel.ts --bundle --minify --format=iife --global-name=EdgeMcpDevPanel --target=es2019 --outfile=dist/edge-mcp-dev-panel.iife.min.js","clean":"rm -rf dist","test":"tsx --test tests/*.test.ts","generate":"node ./bin/edge-mcp.mjs generate","install-hook":"node ./bin/edge-mcp.mjs install-hook","prepublishOnly":"npm run clean && npm run build && npm test"},"keywords":["webmcp","model-context","document.modelContext","agent","ai-agent","mcp","polyfill","in-browser","tools"],"license":"MIT","homepage":"https://developers.napster.com","engines":{"node":">=18"},"publishConfig":{"access":"public"},"sideEffects":["./dist/index.js","./src/index.ts"],"dependencies":{"@cfworker/json-schema":"4.1.1"},"peerDependencies":{"@anthropic-ai/claude-agent-sdk":"^0.3.0"},"peerDependenciesMeta":{"@anthropic-ai/claude-agent-sdk":{"optional":true}},"devDependencies":{"@standard-schema/spec":"^1.1.0","esbuild":"^0.28.1","tsx":"^4.19.0","typescript":"^5.4.0"},"_id":"@napster-corp/edge-mcp@0.2.0","gitHead":"2bef07dcccbf388cfa4297a39af088fb455e5d37","_nodeVersion":"20.20.1","_npmVersion":"10.8.2","dist":{"integrity":"sha512-kyvmVOstAMo8cLBN8EWTdgf6f+iQ7+V++GEVYUmbB5NiExKHFjmwsEUZm0oPlvX8bCZTac9XSEDF3N3FsvUxHA==","shasum":"a82da43310720d6bacaee44425ce0260806050ed","tarball":"https://registry.npmjs.org/@napster-corp/edge-mcp/-/edge-mcp-0.2.0.tgz","fileCount":48,"unpackedSize":491733,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHenf0nJmoQ+pjyqqdR9RAsIEeIkVZ3VAnBIlLOznN6qAiBsRiXPmpCk71iCyXTeszZBS9T6kTK4G2SUngGcVMf/0Q=="}]},"_npmUser":{"name":"bratumarius2005","email":"marius.bratu@napster.com"},"directories":{},"maintainers":[{"name":"dima-napster","email":"dima@napster.com"},{"name":"bratumarius2005","email":"marius.bratu@napster.com"},{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"},{"name":"serhii_kitchenkov","email":"sergey.kitchenkov@touchcast.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/edge-mcp_0.2.0_1784803001455_0.3792155673499715"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-25T12:29:23.035Z","modified":"2026-07-23T10:36:41.824Z","1.0.0":"2026-06-12T07:56:18.457Z","1.0.1":"2026-06-25T12:29:23.355Z","1.1.0":"2026-06-30T11:58:52.585Z","1.1.1":"2026-06-30T14:13:46.220Z","1.2.0":"2026-07-06T15:22:33.766Z","1.2.1":"2026-07-07T10:01:01.292Z","1.3.0":"2026-07-07T12:22:34.258Z","0.1.0":"2026-07-08T07:56:44.826Z","0.1.1":"2026-07-09T10:54:39.859Z","0.2.0":"2026-07-23T10:36:41.609Z"},"license":"MIT","homepage":"https://developers.napster.com","keywords":["webmcp","model-context","document.modelContext","agent","ai-agent","mcp","polyfill","in-browser","tools"],"description":"Napster Edge MCP — polyfills the WebMCP standard (document.modelContext) cross-browser and adds live state and dev tooling. Write standard registerTool calls with standard annotations; any compatible agent (including Napster's) can operate your app.","maintainers":[{"name":"dima-napster","email":"dima@napster.com"},{"name":"bratumarius2005","email":"marius.bratu@napster.com"},{"name":"llya.s","email":"ilya.smiyukha@touchcast.com"},{"name":"serhii_kitchenkov","email":"sergey.kitchenkov@touchcast.com"}],"readme":"# @napster-corp/edge-mcp\n\n> Let an AI agent actually operate your web app — by exposing the app's real operations as tools the agent can call, on top of the WebMCP standard.\n\n[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n[![standard: WebMCP](https://img.shields.io/badge/standard-WebMCP-purple.svg)](https://github.com/webmachinelearning/webmcp)\n\nMost AI agents on websites today are observers. A voice-and-video assistant on\nyour homepage, or a chatbot in the corner, can answer questions about your\nproduct, read off pricing, maybe file a support ticket. But when the user says\n\"add the 65-inch OLED to my cart and check out,\" the agent's answer is\nsomething like \"sure, click the Add to Cart button.\" It can't actually do it.\nThe user still drives the UI by hand.\n\nWebMCP closes that gap. Your app declares which of its real operations an\nagent is allowed to run — `products.search`, `cart.add`,\n`checkout.placeOrder`, whatever you choose to expose — and any compatible\nagent running in the same page can call them. The agent doesn't simulate your\napp; it operates the app, using the same functions your buttons and forms\nalready call. The cart drawer slides open. The product page navigates. The\norder gets placed.\n\nThis is **the Model Context Protocol, but for the browser.** The original MCP\nexposes server-side tools to an AI client over a wire protocol; WebMCP exposes\nthe app's in-browser tools to whichever agent is running on the same page,\nthrough `document.modelContext`. A compatible agent SDK finds the app's tools\nat runtime and wires itself up — no glue code, nothing to dispatch by hand.\n\nThe **Napster Edge MCP** is a thin layer on top of that standard. It\n**polyfills** WebMCP so `document.modelContext` exists in every browser\n(including carrying tool `annotations` through `getTools()`), and it **adds\nvalue** on top — live-state resources and a dev panel — without changing how you\nregister tools. Your `registerTool` code is standard WebMCP: remove the toolkit\nand it still works against the native browser API. Safety levels are expressed\nwith the standard annotation hints, not a proprietary tier.\n\n```bash\nnpm install @napster-corp/edge-mcp\n```\n\nNo npm or build step in your site? There's a [pre-bundled script-tag build](#no-build-step-the-script-tag-build) too.\n\n---\n\n## Why this exists\n\nEven when teams try to make a website agent that *does* things instead of\njust talking, the usual path is to build a second, parallel system next to\nthe app: copy your data into a vector store, hand-wrap your APIs as agent\ntools, write a workflow mapping layer, and keep all of it in sync with the\nreal application every time it ships. The parallel system drifts. The agent\nmakes confident, wrong claims based on stale knowledge — and when it does\ntry to act, it acts on a copy of the app, not the app itself.\n\nWebMCP inverts this. Instead of duplicating your app for the agent, you\npoint the agent **at** the live app. You expose an approved set of operations\nthe agent is allowed to invoke and an approved set of state slices the agent\nis allowed to observe. The agent calls the same functions the UI calls; the\napp stays the source of truth.\n\nTwo consequences worth stating up front:\n\n- **The UI stays in sync automatically.** An agent's `cart.add` updates the\n  one cart store, and every component bound to it re-renders. You don't write\n  sync code.\n- **The agent runs as the signed-in user.** The toolkit doesn't grant new\n  permissions; it picks a subset of the user's existing rights and makes them\n  callable through the agent. Auth, validation, and authorization stay\n  exactly where they already are.\n\nAnd one that's specific to building on a standard:\n\n- **Zero lock-in.** Tools are registered through the native\n  `document.modelContext.registerTool` API. If the customer removes this\n  toolkit, their tool code keeps working against the browser's own WebMCP\n  implementation — and any standards-compliant WebMCP agent can already drive\n  them. The toolkit's extras (tiers, resources, dev panel) layer on top\n  without owning the call site.\n\n---\n\n## What importing the package does\n\nImporting `@napster-corp/edge-mcp` is a **browser-only side effect**. On\nimport it does two things:\n\n1. **Polyfills WebMCP.** It initializes the vendored WebMCP polyfill — a fork of\n   [`@mcp-b/webmcp-polyfill`](https://www.npmjs.com/package/@mcp-b/webmcp-polyfill)\n   whose source lives in `src/webmcp-polyfill/` (**not** a runtime dependency),\n   patched to surface tool `annotations` through `getTools()` — so\n   `document.modelContext` exists cross-browser. The polyfill installs\n   **unconditionally**: a pre-existing `document.modelContext` — a native\n   browser implementation or a foreign polyfill — is **replaced**, because\n   current native surfaces drop tool `annotations` from `getTools()` and reject\n   foreign tool objects in `executeTool()` (the replaced implementation is\n   retained internally, see `getReplacedModelContext()`). Only a prior install\n   of this same fork is left in place, so double imports and HMR are safe.\n2. **Installs the resource extension.** It adds an MCP-shaped live-state\n   \"resource extension\" onto `document.modelContext` (see\n   [Live state](#live-state--the-eyes)).\n\nOutside a browser — SSR (Next.js / Nuxt / Remix / SvelteKit), web workers, edge\nruntimes — importing the package **does nothing and touches no globals**. The\nreal surface comes up in the browser when the bundle hydrates. You don't need\nto add any guards in your own code; the package handles it.\n\n```ts\n// src/edge-mcp/index.ts\nimport '@napster-corp/edge-mcp';   // polyfill + resource extension (side effect)\nimport './tools';                         // tools/ — one descriptor file per tool; tools/index.ts registers them\nimport './resources';                     // your registerResource calls\n```\n\n---\n\n## No build step? The script-tag build\n\nNot every website has npm and a bundler — WordPress themes, server-rendered\ntemplates (Rails, Django, PHP), static HTML sites. For those, the package ships\na pre-bundled, minified browser build (`dist/edge-mcp.iife.min.js`, all\ndependencies inlined, ~38 KB before gzip). Because it's published inside the\nnpm package, any npm CDN serves it — no separate CDN infrastructure:\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/@napster-corp/edge-mcp@0.1/dist/edge-mcp.iife.min.js\"></script>\n```\n\nLoading the script has the **identical side effect** as importing the package:\nit polyfills `document.modelContext` and installs the resource extension. From\nthere, everything is the standard surface — plain inline scripts, zero imports:\n\n```html\n<script>\n  document.modelContext.registerTool({\n    name: 'contact.submit',\n    description: 'Submit the contact form.',\n    inputSchema: { type: 'object', properties: { email: { type: 'string' } }, required: ['email'] },\n    annotations: { destructiveHint: true },\n    async execute({ email }) {\n      // calls the site's real code, same as the form's own submit handler\n      return submitContactForm(email);\n    },\n  });\n</script>\n```\n\nDetails:\n\n- **Pin the version** in the URL (`@0.1`, not `@latest`) so your site doesn't\n  silently pick up future majors.\n- The module's helper exports are available on a **`window.EdgeMCP`** global\n  (`EdgeMCP.registerResource`, `EdgeMCP.getModelContext`, `EdgeMCP.setDebug`, …).\n  You rarely need them — `registerResource` is also installed directly on\n  `document.modelContext`.\n- The dev panel has its own bundle, `dist/edge-mcp-dev-panel.iife.min.js`,\n  exposing **`window.EdgeMcpDevPanel.installDevPanel()`**. Load it only in\n  development.\n- Load the script (and any registrations) **before** your agent SDK initializes,\n  so the tools are registered by the time the agent reads `document.modelContext`.\n- `unpkg.com/@napster-corp/edge-mcp@0.1/dist/edge-mcp.iife.min.js` works the\n  same way if you prefer unpkg over jsDelivr; self-hosting the file is fine too.\n\n---\n\n## Quick example\n\nThe website developer writes **standard WebMCP tools** — there's no\nNapster-specific call required to register a tool:\n\n```ts\n// src/edge-mcp/tools/cart-add.ts — one tool per file in the recommended layout\nimport type { ToolDescriptor } from '@napster-corp/edge-mcp';\n\nexport const tool: ToolDescriptor = {\n  name: 'cart.add',\n  description: 'Add a product to the cart.',\n  inputSchema: {\n    type: 'object',\n    properties: { productId: { type: 'string' } },\n    required: ['productId'],\n  },\n  // Safety rides on the STANDARD annotation hints. A reversible write sets\n  // neither readOnlyHint nor destructiveHint. (read → readOnlyHint: true;\n  // needs-confirmation → destructiveHint: true.) See \"Safety annotations\" below.\n  annotations: { readOnlyHint: false },\n  async execute({ productId }) {\n    cartStore.add(productId as string);\n    return { content: [{ type: 'text', text: 'Added to cart' }] };   // standard MCP result shape\n  },\n};\n\n// src/edge-mcp/tools/index.ts registers it on the standard surface:\n//   import { tool as cartAdd } from './cart-add';\n//   document.modelContext.registerTool(cartAdd);\n```\n\nThat's the entire integration for a tool — pure standard WebMCP, no\nNapster-specific registration call. A WebMCP-aware agent SDK\ndetects `document.modelContext`, reads the tool list, and wires itself up — no\nglue code, nothing to dispatch by hand.\n\n> `cartStore` is a stand-in for your app's own code — the same functions your\n> UI's buttons and forms already call. The toolkit doesn't replace any of\n> them; it exposes the ones you choose to a connected agent.\n\nSee [`examples/app-side.ts`](./examples/app-side.ts) for the full app-side\npattern.\n\n### Safety, and two value-adds\n\nSafety is **not** a Napster invention — it rides on the standard annotation\nhints, so it stays portable. The two genuine add-ons live **off** the standard\ncall site:\n\n| Concern | How | Standard? |\n| --- | --- | --- |\n| Safety / confirmation | `registerTool({ ..., annotations: { readOnlyHint, destructiveHint, idempotentHint } })` | ✅ standard MCP annotation hints |\n| Live state | `registerResource({ uri, get, subscribe })` | ✗ WebMCP hasn't formalized resources yet; consumed over Napster's own path |\n| Dev panel | `installDevPanel()` | ✗ Dev-only inspector, not part of the runtime contract |\n\n---\n\n## Have a coding agent set it up for you\n\nIf you'd rather not work through tool and state design by hand, the public\n**Napster Omniagent skills** hub ships composing skills that any Agent\nSkills-compatible tool (Claude Code, Cursor, Codex, OpenCode, etc.) can load.\n\n```bash\nnpx skills add Napster/omniagent-api-skills\n```\n\nThe skills that set up this toolkit (alongside the rest of the Omniagent API\nskills in that hub):\n\n- **`edge-mcp-setup`** — the main entry point and orchestrator. Runs the\n  skills below in order and walks the developer through sign-off.\n- **`edge-mcp-plan`** — invoked by `edge-mcp-setup` as its first\n  step. Analyzes the codebase, proposes a curated starter plan (tools, live-state\n  resources, and deliberate withholds), walks the developer through it until\n  approved. No file output — the plan lives in the conversation, the code is the\n  record.\n- **`edge-mcp-implement`** — turns the approved plan into code: installs the\n  package, registers the agreed tools and resources against the app's real\n  code, and verifies them at runtime.\n- **`edge-mcp-dev-panel`** *(opt-in)* — installs a small dev-only floating\n  panel for testing by hand: a form-based runner for every tool (fields rendered\n  from each tool's `inputSchema`), a live view of every resource, and an event\n  log. `edge-mcp-setup` offers it at the end; run it directly any time after\n  setup.\n\nIn your project, just say what you want in plain language — \"set up WebMCP\",\n\"agentify this app\", \"what should I expose to the agent?\", \"add a panel for\ntesting\" — and the matching skill fires.\n\nThese skills stop once your WebMCP surface is built. Connecting an actual agent\n(Napster's Omniagent, or any other WebMCP-compatible vendor) is a separate step\nhandled by that vendor's own SDK or skills. The same `Napster/omniagent-api-skills`\nhub covers the Napster Omniagent end (personas, agents, deploy channels); its Web\nSDK auto-attaches to `document.modelContext` at runtime.\n\n---\n\n## Core concepts\n\n### Tools — the hands\n\nWhat the agent can do. One tool per real operation you choose to expose. Name\nthem in your app's own domain terms (`products.search`, `cart.add`,\n`orders.cancel`), not in agent-product terms.\n\n`execute` calls your app's **real** code — the same function the UI's own\nbutton or form submits to. Composing several real operations into one tool is\nfine (and often necessary). What's forbidden is re-deriving business logic the\napp already owns; if you find yourself recomputing a price the app already\ncalculates, stop.\n\nRegister with the standard `document.modelContext.registerTool(...)`. Express\nhow carefully the agent should commit a tool with the standard `annotations`\nhints (see [Safety annotations](#safety-annotations) below).\n\n### Live state — the eyes\n\nWhat the agent can perceive that it didn't get back from a tool. Resources are\nthe **exception, not the rule**. Most things don't need one — if a tool returns\nits result, the agent already knows.\n\nAdd a resource only for state that changes **out of band**:\n\n- The user edits something by hand (cart quantity, filter, navigation)\n- The server changes state over time (an order moves from `processing` to\n  `shipped` mid-conversation)\n\nPure pull state — something you could just read on demand — is better modeled\nas a read-only tool than as a resource. And if a tool already returns the\nanswer, do **not** add a resource that mirrors it. A search that returns its\nresults inline needs no `searchResults` resource; the agent has the data\nalready.\n\n### Safety annotations\n\nExpress how carefully a tool should be committed with the **standard** WebMCP /\nMCP annotation hints — no proprietary field. Consumers (the Web SDK / agent)\nread these off `getTools()` to gate confirmation flows.\n\n| Level | `annotations` | Example | Confirmation |\n| --- | --- | --- | --- |\n| read | `{ readOnlyHint: true }` | search, look up, compare | None — call freely |\n| reversible | `{}` (neither hint) | add to cart, save draft, apply filter | Brief announce |\n| needs confirmation | `{ destructiveHint: true }` | place order, cancel, send | Explicit user confirmation, wait for consent |\n\nSet the safer level when in doubt. **The consumer enforces confirmation — never\nthe model.** A tool with no annotations is treated as reversible.\n\nBy convention here, **`destructiveHint: true` means \"confirm with the user\nfirst.\"** MCP defines `destructiveHint` as a non-additive/destructive update,\nwhich is slightly narrower — so also set it for additive-but-final actions\n(submit, send, place order) where you still want a confirmation gate.\n\nSet `idempotentHint: true` when the underlying operation tolerates safe retries\n(e.g. via an idempotency key on the server), and `untrustedContentHint: true`\nwhen the tool returns content that may carry injected instructions.\n\n---\n\n## API\n\n### Registering a tool (standard)\n\nThere is **no** Napster registration wrapper. Register on the standard surface\nand express safety with the standard `annotations` hints. The polyfill (vendored\nhere) surfaces those annotations through `getTools()`, so any consumer — the\nNapster Web SDK or any WebMCP agent — reads them the standard way.\n\n```ts\nconst unregister = document.modelContext.registerTool({\n  name: 'checkout.placeOrder',\n  description: 'Submit the cart for purchase.',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      paymentMethodId: { type: 'string' },\n      addressId: { type: 'string' },\n    },\n    required: ['paymentMethodId', 'addressId'],\n  },\n  annotations: {\n    readOnlyHint: false,\n    destructiveHint: true,    // ⇒ consumer confirms with the user before calling\n    idempotentHint: true,     // safe to retry\n    // untrustedContentHint: true   // if output may carry injected instructions\n  },\n  async execute({ paymentMethodId, addressId }) {\n    const order = await placeOrder(paymentMethodId, addressId);\n    return { content: [{ type: 'text', text: `Order ${order.id} placed` }] };\n  },\n});\n\n// pass { signal } to registerTool and abort it to unregister.\n```\n\n**Standard annotation hints** (all optional, read off `getTools()` by the consumer):\n\n| Hint | Meaning |\n| --- | --- |\n| `readOnlyHint` | the tool only reads state — call freely |\n| `destructiveHint` | **by our convention: confirm with the user before calling** |\n| `idempotentHint` | safe to retry with the same args |\n| `untrustedContentHint` | output may carry untrusted / injected content |\n\nA tool with no annotations is treated as reversible (announce-then-run).\n\n### Reading tools back — `getTools()` / `executeTool()` (consumer side)\n\nIf you build anything that *consumes* the surface — an agent bridge, a custom\ndev panel, an inspector — two wire-contract details will bite you if you don't\nknow them:\n\n**1. `getTools()` returns each tool's `inputSchema` as a JSON *string*, not an\nobject.** That is Chromium's native `getTools()` contract, and the polyfill\nmatches it for interoperability (you *register* an object; you *read back* a\nstring). Parse before use:\n\n```ts\nconst tools = await document.modelContext.getTools();\nconst schema = JSON.parse(tools[0].inputSchema ?? '{\"type\":\"object\"}');\n```\n\n**2. `executeTool(tool, argsJson)` resolves with a JSON *string* of the standard\nresult envelope** — `JSON.stringify({ content: [{ type: 'text', text: '…' }] })`.\nUnwrap it to render the output (and note the `text` may itself be JSON if the\ntool stringified data into it):\n\n```ts\nconst raw = await document.modelContext.executeTool(tool, JSON.stringify({ query: 'laptop' }));\nconst text = raw === null ? null : JSON.parse(raw).content?.[0]?.text;\n```\n\nIt resolves with `null` when the tool's `execute` returned `undefined`, and\nrejects on an unknown tool, argument-validation failure, or an aborted\n`options.signal`. Portability note: the polyfill resolves the tool by `name`,\nbut Chromium's native implementation requires the exact object `getTools()`\nreturned — always pass the `getTools()` handle, never a hand-built object.\n\n**TypeScript:** the package ships an ambient declaration for\n`document.modelContext` (typed with the resource extension included), so\n`document.modelContext.registerTool(...)` and `.registerResource(...)`\ntype-check as soon as `@napster-corp/edge-mcp` is imported anywhere in the\ncompilation. Delete any hand-written `webmcp.d.ts` — a local re-declaration of\n`Document.modelContext` will now conflict.\n\n### `registerResource(resource)`\n\nRegister a live-state resource, modeled on MCP resources. Use it only for\n[out-of-band state](#live-state--the-eyes).\n\n```ts\nimport { registerResource } from '@napster-corp/edge-mcp';\n\nregisterResource({\n  uri: 'state://cart',\n  name: 'cart',\n  description: 'The current shopping cart',   // optional\n  mimeType: 'application/json',               // optional\n  get: () => cartStore.getCurrent(),\n  subscribe: (onChange) => cartStore.subscribe(onChange),   // optional; return an unsubscribe fn\n});\n```\n\nThe consumer-side surface lives on `document.modelContext` (installed by the\nimport side effect):\n\n| Member | Purpose |\n| --- | --- |\n| `getResources()` | List registered resources |\n| `readResource(uri)` | Read the current value of one resource |\n| `subscribeResource(uri, handler)` | Subscribe to changes for one resource |\n| `resourceupdated` event | `CustomEvent` with `detail = { uri, value }` |\n| `resourcelistchanged` event | Fired when the resource list changes |\n\n> This resource channel is consumed by the Napster agent over its own path. It\n> is **not interoperable** with third-party WebMCP agents until the standard\n> formalizes resources. The standard tool surface, by contrast, is fully\n> interoperable today.\n\n### `installDevPanel(options?)`\n\nA dev-only in-page inspector. Imported from a subpath so it never ships in your\nproduction bundle if you don't reference it.\n\n```ts\nimport { installDevPanel } from '@napster-corp/edge-mcp/dev-panel';\n\nconst uninstall = installDevPanel({ shortcut: 'cmd+shift+e', startOpen: false });\n```\n\nIt reads `document.modelContext` directly — **it takes no instance argument**.\nToggle with **Cmd+Shift+E** (**Ctrl+Shift+E** on non-Mac).\n\nOptions (all optional):\n\n| Option | Default | Effect |\n| --- | --- | --- |\n| `shortcut` | `'Cmd+Shift+E'` | Toggle combo (`Ctrl+Shift+E` on non-Mac). |\n| `startOpen` | `false` | Mount the panel open instead of hidden. |\n| `font` | the app's font | Panel UI font. Defaults to your app's font (read from `document.body`) so the panel matches your typography; pass a CSS `font-family` to override. Code/JSON always render mono. |\n| `height` | `600` | Panel height in px, clamped to the viewport. The panel holds this height and scrolls its content internally, so it never resizes as content changes. |\n\nBy default the panel: holds a **fixed height** with internal scroll; **matches\nyour app's font**; renders tool results, live-state values, and log payloads as\n**collapsible JSON trees**; picks a tool via a **single searchable dropdown**\n(one tool's form at a time); and **dedupes chatty resource echoes** so a store\nthat fires several `set()`s per operation logs one state change, not several.\n\n### Adapter exports\n\nThe single swap-point over the polyfill, for code that wants the model-context\nobject directly instead of reaching for the global:\n\n| Export | Returns |\n| --- | --- |\n| `getModelContext()` | `document.modelContext` (with a deprecated `navigator.modelContext` fallback) |\n| `getModelContextWithResources()` | the same object, with the resource extension surface |\n| `isBrowserEnvironment()` | `true` only in a real browser |\n\n---\n\n## How an agent discovers your app\n\nA WebMCP agent — or the Napster Companion Web SDK — attaches with no\ncoordination from you:\n\n1. **Detect** by the presence of `document.modelContext`.\n2. **Read tools** via `getTools()`.\n3. **Invoke** via `executeTool(toolInfo, JSON.stringify(args))`.\n4. **Observe tool changes** via the `toolchange` event — a bare `Event` with no\n   `detail`; re-read `getTools()` when it fires.\n5. **Relay live state** via `subscribeResource` / the `resourceupdated` event.\n\nBecause every one of those steps is standard, **the agent attaches to any\nWebMCP-enabled site** — even one that never installed this toolkit. Safety\nannotations travel on the standard tools, so they work anywhere; the Napster\nlive-state resource extension simply lights up when the toolkit is present and\nis absent otherwise; nothing breaks either way.\n\n---\n\n## Hosting\n\nThe toolkit is browser-only and runs in the same module graph as your UI. A few\nnotes worth knowing up front:\n\n- **Recommended file layout.** Keep your WebMCP wiring in a `src/edge-mcp/`\n  folder: `index.ts` imports the toolkit and wires everything up, a `tools/`\n  folder holds one descriptor file per tool with `tools/index.ts` as the\n  registrar that `document.modelContext.registerTool`s them all, and\n  `resources.ts` holds your `registerResource` calls. (A `handles.ts` joins them\n  only if a tool's `execute` needs framework context like a router hook.)\n- **Imperative actions from outside the component tree.** A tool's `execute`\n  lives in a plain module. Things like navigation often only exist inside the\n  framework (e.g. React Router's `useNavigate` hook). Register a module-level\n  handle from an in-tree component at mount and have `execute` call through\n  that; otherwise it has no way to drive navigation.\n- **Server-side rendering is a no-op.** Outside the browser (SSR, workers, edge\n  runtimes), importing the package does nothing and touches no globals. This is\n  deliberate: the toolkit connects an in-browser agent to in-browser state;\n  running it on the server would bleed per-user state through the Node\n  process's shared globals. The real surface comes up in the browser when the\n  bundle hydrates.\n\n---\n\n## Automation — keep your tools folder in sync\n\nYour tool list is hand-curated, but it drifts as the app changes — a route gets\nrenamed, an operation is removed, a new one becomes worth exposing. The package\nships an **opt-in agent** that re-analyzes the app and reconciles your tools\nfolder (e.g. `src/edge-mcp/tools/` — adding, updating, and removing one\ndescriptor file per tool and keeping `tools/index.ts` in sync) to match the\ncurrent code — runnable from a post-commit hook locally, or from CI on a pull\nrequest. It produces **uncommitted** changes you review.\n\nIt uses the `edge-mcp-plan` / `edge-mcp-implement` skills from the\npublic `Napster/omniagent-api-skills` hub as the methodology (fetched at run\ntime), and by default runs on the **Claude Agent SDK**\n(`@anthropic-ai/claude-agent-sdk`, Claude Opus 4.8).\n\n### Setup (in the host app)\n\n```bash\nnpm install @napster-corp/edge-mcp\nnpm install -D @anthropic-ai/claude-agent-sdk   # the default engine's runtime\nnpx edge-mcp install-hook                        # the marker-gated [edge-mcp] post-commit hook\nexport ANTHROPIC_API_KEY=...                      # local: your key; CI: a secret\n```\n\nPut your engine's key where the CLI can read it — exported, in CI as a secret,\nor in the app's gitignored `.env.local`.\n\nThe **default** way to keep the surface in sync needs no automation at all: the\nagent that changes your app reconciles the tools — and flags resource changes —\nas part of the same work (see the `edge-mcp-setup` / `edge-mcp-sync` skills, which\nalso drop a keep-in-sync note into your repo's `CLAUDE.md` / `AGENTS.md`). The CLI\nbelow is the **opt-in automation**, for changes that land *outside* an agent\n(hand commits, teammates, CI).\n\n### Opt-in marker (plain git hook) — `install-hook`\n\nFor commits made outside Claude Code, the post-commit hook runs **only** when a\ncommit message contains the marker `[edge-mcp]`:\n\n```bash\ngit commit -m \"feat(cart): add bulk remove  [edge-mcp]\"\n```\n\nEvery other commit is untouched — no agent run, no token cost. When the marker\nis present, the agent analyzes the app and leaves **uncommitted** changes to\nyour tools folder — a post-commit hook can't amend the commit, so you review the\ndiff and commit it separately:\n\n```\n✎ src/edge-mcp/tools/ (unstaged)\n  + cart-bulk-remove.ts → cart.bulkRemove (reversible) — src/store/cart.ts:bulkRemove\n  ~ checkout-place-order.ts → checkout.placeOrder (signature changed) — src/api/checkout.ts:placeOrder\n  + tools/index.ts (registrar updated)\n→ review & commit when ready\n```\n\n### Run it manually / in CI\n\n`edge-mcp generate` is the same command the hook calls — run it anywhere:\n\n```bash\nnpx edge-mcp generate          # regenerate now, against the current working tree\n```\n\nOn CI (e.g. a GitHub Action on `pull_request`), set the engine's key as a\nsecret and run `npx edge-mcp generate`, then open/update a PR with the result.\nIt auto-detects the tools folder (`src/edge-mcp/tools/`, `lib/edge-mcp/tools/`, …);\noverride with `--file path` if needed.\n\n### What the agent may touch\n\nLocked down by design: the agent is restricted to `Read` / `Grep` / `Glob` /\n`Edit` / `Write`, with no shell — it reads the app to find real operations and\nedits **only** files in your tools folder (the per-tool descriptors and\n`tools/index.ts`). It does **not** edit live-state resources (`resources.ts`) —\nthose are subtler to get right unattended, so it flags them for a human/in-chat\npass instead. It cannot run commands, install packages, or touch git.\n\n### Engines\n\nPluggable — pick with `--engine` or `EDGE_MCP_ENGINE`:\n\n| Engine | Default | Needs | Notes |\n| --- | --- | --- | --- |\n| `anthropic` | ✅ | `ANTHROPIC_API_KEY` + `@anthropic-ai/claude-agent-sdk` | Claude Agent SDK (Opus 4.8); restricted to read/edit tools (no shell) |\n| `copilot` | | the GitHub **Copilot CLI** + a Copilot subscription | Shells out to the CLI; no Anthropic key |\n\n```bash\nEDGE_MCP_ENGINE=copilot npx edge-mcp generate     # or: npx edge-mcp generate --engine copilot\n```\n\nThe skills, prompt, path detection, opt-in marker, and uncommitted-output\npolicy are identical across engines — only the agent runtime changes.\n\n> The Copilot CLI's non-interactive flags evolve, so the exact invocation is\n> env-overridable rather than hardcoded — set `EDGE_MCP_COPILOT_BIN` and\n> `EDGE_MCP_COPILOT_ARGS` to match your installed `copilot --help`.\n\n### Commands\n\n| Command | What it does |\n| --- | --- |\n| `edge-mcp install-hook` | Install/refresh the opt-in `[edge-mcp]` post-commit hook (idempotent; composes with an existing hook) |\n| `edge-mcp generate [--engine anthropic\\|copilot]` | Analyze the app and reconcile your tools folder — one file per tool + registrar (local or CI) |\n\n---\n\n## License\n\n[MIT](./LICENSE).\n","readmeFilename":"README.md"}