[{"data":1,"prerenderedAt":2400},["ShallowReactive",2],{"navigation_docs":3,"-modules-features-mcp":587,"-modules-features-mcp-surround":2395},[4,50,155,441,504],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":49},"Get Started","i-lucide-rocket","\u002Fget-started","1.get-started",[10,15,20,25,30,35,40,45],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fget-started\u002Fintroduction","1.get-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Project structure","\u002Fget-started\u002Fproject-structure","1.get-started\u002F3.project-structure","i-lucide-folder-tree",{"title":26,"path":27,"stem":28,"icon":29},"Configuration","\u002Fget-started\u002Fconfiguration","1.get-started\u002F4.configuration","i-lucide-settings",{"title":31,"path":32,"stem":33,"icon":34},"Authentication","\u002Fget-started\u002Fauthentication","1.get-started\u002F5.authentication","i-lucide-lock",{"title":36,"path":37,"stem":38,"icon":39},"Adding modules","\u002Fget-started\u002Fadding-modules","1.get-started\u002F6.adding-modules","i-lucide-puzzle",{"title":41,"path":42,"stem":43,"icon":44},"Database","\u002Fget-started\u002Fdatabase","1.get-started\u002F7.database","i-lucide-database",{"title":46,"path":47,"stem":48,"icon":6},"Deployment","\u002Fget-started\u002Fdeployment","1.get-started\u002F8.deployment",false,{"title":51,"icon":52,"path":53,"stem":54,"children":55,"page":49},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[56,90,115,125],{"title":57,"icon":49,"path":58,"stem":59,"children":60,"page":49},"Concepts","\u002Fguide\u002Fconcepts","2.guide\u002F1.concepts",[61,66,71,76,80,85],{"title":62,"path":63,"stem":64,"icon":65},"Architecture","\u002Fguide\u002Fconcepts\u002Farchitecture","2.guide\u002F1.concepts\u002F1.architecture","i-lucide-blocks",{"title":67,"path":68,"stem":69,"icon":70},"Access control","\u002Fguide\u002Fconcepts\u002Fauth-and-scopes","2.guide\u002F1.concepts\u002F2.auth-and-scopes","i-lucide-shield-check",{"title":72,"path":73,"stem":74,"icon":75},"Extension points","\u002Fguide\u002Fconcepts\u002Fextension-points","2.guide\u002F1.concepts\u002F3.extension-points","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":44},"Database extensions","\u002Fguide\u002Fconcepts\u002Fdatabase-extensions","2.guide\u002F1.concepts\u002F4.database-extensions",{"title":81,"path":82,"stem":83,"icon":84},"Identity","\u002Fguide\u002Fconcepts\u002Fidentity","2.guide\u002F1.concepts\u002F5.identity","i-lucide-fingerprint",{"title":86,"path":87,"stem":88,"icon":89},"Glossary","\u002Fguide\u002Fconcepts\u002Fglossary","2.guide\u002F1.concepts\u002F6.glossary","i-lucide-book-a",{"title":91,"icon":49,"path":92,"stem":93,"children":94,"page":49},"UX patterns","\u002Fguide\u002Fux-patterns","2.guide\u002F2.ux-patterns",[95,100,105,110],{"title":96,"path":97,"stem":98,"icon":99},"Layouts and navigation","\u002Fguide\u002Fux-patterns\u002Flayouts-and-navigation","2.guide\u002F2.ux-patterns\u002F1.layouts-and-navigation","i-lucide-layout-template",{"title":101,"path":102,"stem":103,"icon":104},"Pages","\u002Fguide\u002Fux-patterns\u002Fpages","2.guide\u002F2.ux-patterns\u002F2.pages","i-lucide-table",{"title":106,"path":107,"stem":108,"icon":109},"Forms and actions","\u002Fguide\u002Fux-patterns\u002Fforms-and-actions","2.guide\u002F2.ux-patterns\u002F3.forms-and-actions","i-lucide-square-pen",{"title":111,"path":112,"stem":113,"icon":114},"Text and formatting","\u002Fguide\u002Fux-patterns\u002Ftext-and-formatting","2.guide\u002F2.ux-patterns\u002F4.text-and-formatting","i-lucide-type",{"title":116,"icon":49,"path":117,"stem":118,"children":119,"page":49},"Best practices","\u002Fguide\u002Fbest-practices","2.guide\u002F3.best-practices",[120],{"title":121,"path":122,"stem":123,"icon":124},"HTTP routes","\u002Fguide\u002Fbest-practices\u002Fhttp-routes","2.guide\u002F3.best-practices\u002F1.http-routes","i-lucide-route",{"title":126,"icon":49,"path":127,"stem":128,"children":129,"page":49},"Going further","\u002Fguide\u002Fgoing-further","2.guide\u002F4.going-further",[130,135,140,145,150],{"title":131,"path":132,"stem":133,"icon":134},"Use your own OAuth server","\u002Fguide\u002Fgoing-further\u002Fown-oauth-server","2.guide\u002F4.going-further\u002F1.own-oauth-server","i-lucide-key-round",{"title":136,"path":137,"stem":138,"icon":139},"Create an OAuth application","\u002Fguide\u002Fgoing-further\u002Foauth-application","2.guide\u002F4.going-further\u002F2.oauth-application","i-lucide-app-window",{"title":141,"path":142,"stem":143,"icon":144},"Signing keys","\u002Fguide\u002Fgoing-further\u002Fsigning-keys","2.guide\u002F4.going-further\u002F3.signing-keys","i-lucide-key-square",{"title":146,"path":147,"stem":148,"icon":149},"Stripe setup","\u002Fguide\u002Fgoing-further\u002Fstripe-setup","2.guide\u002F4.going-further\u002F4.stripe-setup","i-lucide-credit-card",{"title":151,"path":152,"stem":153,"icon":154},"Migrate to the permission model","\u002Fguide\u002Fgoing-further\u002Fmigrate-access-control","2.guide\u002F4.going-further\u002F5.migrate-access-control","i-lucide-arrow-right-left",{"title":156,"icon":157,"path":158,"stem":159,"children":160},"Modules","i-lucide-boxes","\u002Fmodules","3.modules",[161,163,244,273,320,375],{"title":156,"path":158,"stem":162},"3.modules\u002Findex",{"title":81,"icon":49,"path":164,"stem":165,"children":166,"page":49},"\u002Fmodules\u002Fidentity","3.modules\u002F1.identity",[167,190,194,198,220,224,240],{"title":168,"path":169,"stem":170,"children":171},"Auth","\u002Fmodules\u002Fidentity\u002Fauth","3.modules\u002F1.identity\u002F1.auth\u002Findex",[172,174,178,182,186],{"title":173,"path":169,"stem":170},"Overview",{"title":175,"path":176,"stem":177},"Server API","\u002Fmodules\u002Fidentity\u002Fauth\u002Fserver","3.modules\u002F1.identity\u002F1.auth\u002F2.server",{"title":179,"path":180,"stem":181},"Reference","\u002Fmodules\u002Fidentity\u002Fauth\u002Freference","3.modules\u002F1.identity\u002F1.auth\u002F3.reference",{"title":183,"path":184,"stem":185},"Client mode","\u002Fmodules\u002Fidentity\u002Fauth\u002Fclient-mode","3.modules\u002F1.identity\u002F1.auth\u002F4.client-mode",{"title":187,"path":188,"stem":189},"OAuth providers","\u002Fmodules\u002Fidentity\u002Fauth\u002Foauth-providers","3.modules\u002F1.identity\u002F1.auth\u002F5.oauth-providers",{"title":191,"path":192,"stem":193},"Users","\u002Fmodules\u002Fidentity\u002Fusers","3.modules\u002F1.identity\u002F2.users",{"title":195,"path":196,"stem":197},"Account","\u002Fmodules\u002Fidentity\u002Faccount","3.modules\u002F1.identity\u002F3.account",{"title":199,"path":200,"stem":201,"children":202},"Authorization","\u002Fmodules\u002Fidentity\u002Fauthorization","3.modules\u002F1.identity\u002F4.authorization\u002Findex",[203,204,208,212,216],{"title":173,"path":200,"stem":201},{"title":205,"path":206,"stem":207},"Roles and requirements","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Froles-and-requirements","3.modules\u002F1.identity\u002F4.authorization\u002F2.roles-and-requirements",{"title":209,"path":210,"stem":211},"Policies","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fpolicies","3.modules\u002F1.identity\u002F4.authorization\u002F3.policies",{"title":213,"path":214,"stem":215},"Client","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fclient","3.modules\u002F1.identity\u002F4.authorization\u002F4.client",{"title":217,"path":218,"stem":219},"Admin","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fadmin","3.modules\u002F1.identity\u002F4.authorization\u002F5.admin",{"title":221,"path":222,"stem":223},"Preferences","\u002Fmodules\u002Fidentity\u002Fpreferences","3.modules\u002F1.identity\u002F5.preferences",{"title":225,"path":226,"stem":227,"children":228},"OAuth Server","\u002Fmodules\u002Fidentity\u002Foauth-server","3.modules\u002F1.identity\u002F6.oauth-server\u002Findex",[229,230,233,237],{"title":173,"path":226,"stem":227},{"title":175,"path":231,"stem":232},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver","3.modules\u002F1.identity\u002F6.oauth-server\u002F2.server",{"title":234,"path":235,"stem":236},"Hooks","\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fhooks","3.modules\u002F1.identity\u002F6.oauth-server\u002F3.hooks",{"title":179,"path":238,"stem":239},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients","3.modules\u002F1.identity\u002F6.oauth-server\u002F4.routes-and-clients",{"title":241,"path":242,"stem":243},"OAuth Resource","\u002Fmodules\u002Fidentity\u002Foauth-resource","3.modules\u002F1.identity\u002F8.oauth-resource",{"title":245,"icon":49,"path":246,"stem":247,"children":248,"page":49},"Commerce","\u002Fmodules\u002Fcommerce","3.modules\u002F2.commerce",[249,253,257],{"title":250,"path":251,"stem":252},"Stripe","\u002Fmodules\u002Fcommerce\u002Fstripe","3.modules\u002F2.commerce\u002F1.stripe",{"title":254,"path":255,"stem":256},"Payments","\u002Fmodules\u002Fcommerce\u002Fpayments","3.modules\u002F2.commerce\u002F2.payments",{"title":258,"path":259,"stem":260,"children":261},"Subscriptions","\u002Fmodules\u002Fcommerce\u002Fsubscriptions","3.modules\u002F2.commerce\u002F3.subscriptions\u002Findex",[262,263,266,270],{"title":173,"path":259,"stem":260},{"title":175,"path":264,"stem":265},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fserver","3.modules\u002F2.commerce\u002F3.subscriptions\u002F2.server",{"title":267,"path":268,"stem":269},"App","\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fapp","3.modules\u002F2.commerce\u002F3.subscriptions\u002F3.app",{"title":179,"path":271,"stem":272},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Freference","3.modules\u002F2.commerce\u002F3.subscriptions\u002F4.reference",{"title":274,"icon":49,"path":275,"stem":276,"children":277,"page":49},"Features","\u002Fmodules\u002Ffeatures","3.modules\u002F3.features",[278,293,312,316],{"title":279,"path":280,"stem":281,"children":282},"Events","\u002Fmodules\u002Ffeatures\u002Fevents","3.modules\u002F3.features\u002F1.events\u002Findex",[283,284,287,290],{"title":173,"path":280,"stem":281},{"title":175,"path":285,"stem":286},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fserver","3.modules\u002F3.features\u002F1.events\u002F2.server",{"title":267,"path":288,"stem":289},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fapp","3.modules\u002F3.features\u002F1.events\u002F3.app",{"title":179,"path":291,"stem":292},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Freference","3.modules\u002F3.features\u002F1.events\u002F4.reference",{"title":294,"path":295,"stem":296,"children":297},"Forms","\u002Fmodules\u002Ffeatures\u002Fforms","3.modules\u002F3.features\u002F2.forms\u002Findex",[298,299,303,306,309],{"title":173,"path":295,"stem":296},{"title":300,"path":301,"stem":302},"Definition","\u002Fmodules\u002Ffeatures\u002Fforms\u002Fdefinition","3.modules\u002F3.features\u002F2.forms\u002F2.definition",{"title":175,"path":304,"stem":305},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fserver","3.modules\u002F3.features\u002F2.forms\u002F3.server",{"title":267,"path":307,"stem":308},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fapp","3.modules\u002F3.features\u002F2.forms\u002F4.app",{"title":179,"path":310,"stem":311},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Freference","3.modules\u002F3.features\u002F2.forms\u002F5.reference",{"title":313,"path":314,"stem":315},"Cookie Consent","\u002Fmodules\u002Ffeatures\u002Fcookie-consent","3.modules\u002F3.features\u002F3.cookie-consent",{"title":317,"path":318,"stem":319},"MCP","\u002Fmodules\u002Ffeatures\u002Fmcp","3.modules\u002F3.features\u002F4.mcp",{"title":321,"icon":49,"path":322,"stem":323,"children":324,"page":49},"Interface","\u002Fmodules\u002Finterface","3.modules\u002F4.interface",[325,350,353,357,361],{"title":326,"path":327,"stem":328,"children":329},"UI","\u002Fmodules\u002Finterface\u002Fui","3.modules\u002F4.interface\u002F1.ui\u002Findex",[330,331,335,339,343,347],{"title":173,"path":327,"stem":328},{"title":332,"path":333,"stem":334},"Page components","\u002Fmodules\u002Finterface\u002Fui\u002Fpage-components","3.modules\u002F4.interface\u002F1.ui\u002F2.page-components",{"title":336,"path":337,"stem":338},"App shell","\u002Fmodules\u002Finterface\u002Fui\u002Fapp-shell","3.modules\u002F4.interface\u002F1.ui\u002F3.app-shell",{"title":340,"path":341,"stem":342},"Form inputs","\u002Fmodules\u002Finterface\u002Fui\u002Fform-inputs","3.modules\u002F4.interface\u002F1.ui\u002F4.form-inputs",{"title":344,"path":345,"stem":346},"Composables and helpers","\u002Fmodules\u002Finterface\u002Fui\u002Fcomposables","3.modules\u002F4.interface\u002F1.ui\u002F5.composables",{"title":179,"path":348,"stem":349},"\u002Fmodules\u002Finterface\u002Fui\u002Freference","3.modules\u002F4.interface\u002F1.ui\u002F6.reference",{"title":217,"path":351,"stem":352},"\u002Fmodules\u002Finterface\u002Fadmin","3.modules\u002F4.interface\u002F2.admin",{"title":354,"path":355,"stem":356},"Menu","\u002Fmodules\u002Finterface\u002Fmenu","3.modules\u002F4.interface\u002F3.menu",{"title":358,"path":359,"stem":360},"Widget","\u002Fmodules\u002Finterface\u002Fwidget","3.modules\u002F4.interface\u002F4.widget",{"title":362,"path":363,"stem":364,"children":365},"Mobile","\u002Fmodules\u002Finterface\u002Fmobile","3.modules\u002F4.interface\u002F5.mobile\u002Findex",[366,367,371],{"title":173,"path":363,"stem":364},{"title":368,"path":369,"stem":370},"CLI and devices","\u002Fmodules\u002Finterface\u002Fmobile\u002Fcli-and-devices","3.modules\u002F4.interface\u002F5.mobile\u002F2.cli-and-devices",{"title":372,"path":373,"stem":374},"Splash screen","\u002Fmodules\u002Finterface\u002Fmobile\u002Fsplash-screen","3.modules\u002F4.interface\u002F5.mobile\u002F3.splash-screen",{"title":376,"icon":49,"path":377,"stem":378,"children":379,"page":49},"Platform","\u002Fmodules\u002Fplatform","3.modules\u002F5.platform",[380,402,406,423],{"title":381,"path":382,"stem":383,"children":384},"Module Kit","\u002Fmodules\u002Fplatform\u002Fmodule-kit","3.modules\u002F5.platform\u002F1.module-kit\u002Findex",[385,386,390,394,398],{"title":173,"path":382,"stem":383},{"title":387,"path":388,"stem":389},"Server toolkit","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fserver-toolkit","3.modules\u002F5.platform\u002F1.module-kit\u002F2.server-toolkit",{"title":391,"path":392,"stem":393},"Registries and menus","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fregistries-and-menus","3.modules\u002F5.platform\u002F1.module-kit\u002F3.registries-and-menus",{"title":395,"path":396,"stem":397},"Translations","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fi18n","3.modules\u002F5.platform\u002F1.module-kit\u002F4.i18n",{"title":399,"path":400,"stem":401},"Database helpers","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fdatabase","3.modules\u002F5.platform\u002F1.module-kit\u002F5.database",{"title":403,"path":404,"stem":405},"Notify","\u002Fmodules\u002Fplatform\u002Fnotify","3.modules\u002F5.platform\u002F2.notify",{"title":407,"path":408,"stem":409,"children":410},"Email Templates","\u002Fmodules\u002Fplatform\u002Femail-templates","3.modules\u002F5.platform\u002F3.email-templates\u002Findex",[411,412,416,419],{"title":173,"path":408,"stem":409},{"title":413,"path":414,"stem":415},"Email components","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fcomponents","3.modules\u002F5.platform\u002F3.email-templates\u002F2.components",{"title":175,"path":417,"stem":418},"\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fserver","3.modules\u002F5.platform\u002F3.email-templates\u002F3.server",{"title":420,"path":421,"stem":422},"Module emails","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fmodule-emails","3.modules\u002F5.platform\u002F3.email-templates\u002F4.module-emails",{"title":424,"path":425,"stem":426,"children":427},"Base Layer","\u002Fmodules\u002Fplatform\u002Fbase-layer","3.modules\u002F5.platform\u002F4.base-layer\u002Findex",[428,429,433,437],{"title":173,"path":425,"stem":426},{"title":430,"path":431,"stem":432},"Content collections","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcontent-collections","3.modules\u002F5.platform\u002F4.base-layer\u002F2.content-collections",{"title":434,"path":435,"stem":436},"Layouts and routing","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Flayouts-and-routing","3.modules\u002F5.platform\u002F4.base-layer\u002F3.layouts-and-routing",{"title":438,"path":439,"stem":440},"Composables and utils","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcomposables-and-utils","3.modules\u002F5.platform\u002F4.base-layer\u002F4.composables-and-utils",{"title":442,"icon":443,"path":444,"stem":445,"children":446,"page":49},"Examples","i-lucide-code-xml","\u002Fexamples","4.examples",[447,466,476],{"title":448,"icon":49,"path":449,"stem":450,"children":451,"page":49},"Starters","\u002Fexamples\u002Fstarters","4.examples\u002F1.starters",[452,456,461],{"title":453,"path":454,"stem":455,"icon":6},"Workspace starter","\u002Fexamples\u002Fstarters\u002Fworkspace","4.examples\u002F1.starters\u002F1.workspace",{"title":457,"path":458,"stem":459,"icon":460},"Mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile","4.examples\u002F1.starters\u002F2.mobile","i-lucide-smartphone",{"title":462,"path":463,"stem":464,"icon":465},"Standalone mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile-standalone","4.examples\u002F1.starters\u002F3.mobile-standalone","i-lucide-tablet-smartphone",{"title":467,"icon":49,"path":468,"stem":469,"children":470,"page":49},"Apps","\u002Fexamples\u002Fapps","4.examples\u002F2.apps",[471],{"title":472,"path":473,"stem":474,"icon":475},"Frigear website app","\u002Fexamples\u002Fapps\u002Ffrigear-nu-website","4.examples\u002F2.apps\u002F1.frigear-nu-website","i-lucide-layout-dashboard",{"title":477,"icon":49,"path":478,"stem":479,"children":480,"page":49},"Tasks","\u002Fexamples\u002Ftasks","4.examples\u002F3.tasks",[481,485,489,494,499],{"title":482,"path":483,"stem":484,"icon":70},"Protect a route","\u002Fexamples\u002Ftasks\u002Fprotect-a-route","4.examples\u002F3.tasks\u002F1.protect-a-route",{"title":486,"path":487,"stem":488,"icon":475},"Add an admin page","\u002Fexamples\u002Ftasks\u002Fadd-an-admin-page","4.examples\u002F3.tasks\u002F2.add-an-admin-page",{"title":490,"path":491,"stem":492,"icon":493},"Sell event tickets","\u002Fexamples\u002Ftasks\u002Fsell-event-tickets","4.examples\u002F3.tasks\u002F3.sell-event-tickets","i-lucide-ticket",{"title":495,"path":496,"stem":497,"icon":498},"Build a form","\u002Fexamples\u002Ftasks\u002Fbuild-a-form","4.examples\u002F3.tasks\u002F4.build-a-form","i-lucide-clipboard-list",{"title":500,"path":501,"stem":502,"icon":503},"Send an email","\u002Fexamples\u002Ftasks\u002Fsend-an-email","4.examples\u002F3.tasks\u002F5.send-an-email","i-lucide-mail",{"title":505,"icon":506,"path":507,"stem":508,"children":509,"page":49},"Contribute","i-lucide-git-pull-request","\u002Fcontribute","5.contribute",[510,513,518,544,549,552,556,571],{"title":173,"path":511,"stem":512,"icon":506},"\u002Fcontribute\u002Foverview","5.contribute\u002F1.overview",{"title":514,"path":515,"stem":516,"icon":517},"Local development","\u002Fcontribute\u002Flocal-development","5.contribute\u002F2.local-development","i-lucide-terminal",{"title":519,"icon":49,"path":520,"stem":521,"children":522,"page":49},"Writing a module","\u002Fcontribute\u002Fwriting-a-module","5.contribute\u002F3.writing-a-module",[523,527,532,536,541],{"title":524,"path":525,"stem":526,"icon":39},"Scaffold a module","\u002Fcontribute\u002Fwriting-a-module\u002Fscaffold","5.contribute\u002F3.writing-a-module\u002F1.scaffold",{"title":528,"path":529,"stem":530,"icon":531},"Setup checklist","\u002Fcontribute\u002Fwriting-a-module\u002Fsetup-checklist","5.contribute\u002F3.writing-a-module\u002F2.setup-checklist","i-lucide-list-checks",{"title":533,"path":534,"stem":535,"icon":44},"Database tables","\u002Fcontribute\u002Fwriting-a-module\u002Fdatabase-tables","5.contribute\u002F3.writing-a-module\u002F3.database-tables",{"title":537,"path":538,"stem":539,"icon":540},"Testing","\u002Fcontribute\u002Fwriting-a-module\u002Ftesting","5.contribute\u002F3.writing-a-module\u002F4.testing","i-lucide-flask-conical",{"title":67,"path":542,"stem":543,"icon":70},"\u002Fcontribute\u002Fwriting-a-module\u002Faccess-control","5.contribute\u002F3.writing-a-module\u002F5.access-control",{"title":545,"path":546,"stem":547,"icon":548},"Publishing","\u002Fcontribute\u002Fpublishing","5.contribute\u002F4.publishing","i-lucide-package-check",{"title":448,"path":550,"stem":551,"icon":6},"\u002Fcontribute\u002Fstarters","5.contribute\u002F5.starters",{"title":553,"path":554,"stem":555,"icon":52},"Documentation","\u002Fcontribute\u002Fdocumentation","5.contribute\u002F6.documentation",{"title":557,"icon":49,"path":558,"stem":559,"children":560,"page":49},"Tooling","\u002Fcontribute\u002Ftooling","5.contribute\u002F7.tooling",[561,566],{"title":562,"path":563,"stem":564,"icon":565},"CLI","\u002Fcontribute\u002Ftooling\u002Fcli","5.contribute\u002F7.tooling\u002F1.cli","i-lucide-square-terminal",{"title":567,"path":568,"stem":569,"icon":570},"ESLint config","\u002Fcontribute\u002Ftooling\u002Feslint-config","5.contribute\u002F7.tooling\u002F2.eslint-config","i-lucide-spell-check",{"title":572,"icon":49,"path":573,"stem":574,"children":575},"Decisions","\u002Fcontribute\u002Fdecisions","5.contribute\u002F8.decisions\u002Findex",[576,578,583],{"title":572,"path":573,"stem":574,"icon":577},"i-lucide-scale",{"title":579,"path":580,"stem":581,"icon":582},"Session lifetimes per OAuth client","\u002Fcontribute\u002Fdecisions\u002Foauth-token-lifetimes","5.contribute\u002F8.decisions\u002F1.oauth-token-lifetimes","i-lucide-timer",{"title":584,"path":585,"stem":586,"icon":70},"One permission model","\u002Fcontribute\u002Fdecisions\u002Fpermission-model","5.contribute\u002F8.decisions\u002F2.permission-model",{"id":588,"title":317,"body":589,"description":2389,"extension":2390,"links":2391,"meta":2392,"navigation":1454,"path":318,"seo":2393,"stem":319,"__hash__":2394},"docs\u002F3.modules\u002F3.features\u002F4.mcp.md",{"type":590,"value":591,"toc":2373},"minimark",[592,615,631,636,678,682,707,711,1109,1133,1137,1143,1185,1200,1204,1207,1211,1348,1366,1370,1377,1532,1563,1567,1581,1631,1794,1887,1894,2154,2157,2239,2246,2267,2270,2273,2340,2344,2369],[593,594,595,596,600,601,604,605,609,610,614],"p",{},"This module lets an AI agent work in your app for a ",[597,598,599],"a",{"href":87},"signed-in user",": list their tickets,\nsubmit a form or, for ",[597,602,603],{"href":87},"staff",", manage events. Your app serves one Model Context Protocol (MCP)\nendpoint at ",[606,607,608],"code",{},"\u002Fmcp",". Each agent sees only the tools its token allows, and other people's personal data stays hidden. Use\nit when users should reach your app through an agent. For scripts that call your HTTP routes directly, an\n",[597,611,613],{"href":612},"\u002Fmodules\u002Fidentity\u002Fauth\u002Fserver#user-api-tokens","API token"," is enough.",[593,616,617,618,621,622,630],{},"The package is ",[606,619,620],{},"@frigear-nu\u002Fmcp",", built on ",[597,623,627],{"href":624,"rel":625},"https:\u002F\u002Fmcp-toolkit.nuxt.dev",[626],"nofollow",[606,628,629],{},"@nuxtjs\u002Fmcp-toolkit",".",[632,633,635],"h2",{"id":634},"what-you-get","What you get",[637,638,639,657,667,672],"ul",{},[640,641,642,646,647,649,650,653,654,656],"li",{},[643,644,645],"strong",{},"Server routes"," (on by default): the MCP endpoint at ",[606,648,608],{},". Agents connect with an API token, an\n",[597,651,652],{"href":87},"access token"," or a session, as\n",[597,655,67],{"href":68}," explains.",[640,658,659,662,663,666],{},[643,660,661],{},"Tools from other modules"," (opt-in per module): each adds its tools when its ",[606,664,665],{},"settings.mcp"," is on.",[640,668,669,671],{},[643,670,344],{}," (on by default): definers for your own tools, each limited to the permission it declares.",[640,673,674,677],{},[643,675,676],{},"Agent instructions and an audit log"," (on by default): the agent is told its limits, and every call is logged\nwithout its arguments or result.",[679,680],"module-runtime",{":server":681},"true",[683,684,685,688,689,691,692,694,695,698,699,702,703,706],"note",{},[643,686,687],{},"Installed for you:"," ",[597,690,168],{"href":169},", ",[606,693,629],{}," (",[606,696,697],{},">=0.24.0",") and Module Kit.\n",[643,700,701],{},"You add:"," nothing.\n",[643,704,705],{},"Optional:"," the modules whose tools you want, listed in Quick setup.",[632,708,710],{"id":709},"quick-setup","Quick setup",[712,713,714,719,726,751,755,767,784,987,1095,1099],"steps",{},[715,716,718],"h3",{"id":717},"install-mcp","Install MCP",[593,720,721,722,725],{},"Events, Forms, OAuth Server, Payments and Subscriptions install MCP for you. Users installs it when\n",[606,723,724],{},"users.settings.mcp"," is on. To use it on its own:",[727,728,733],"pre",{"className":729,"code":730,"language":731,"meta":732,"style":732},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @frigear-nu\u002Fmcp\n","bash","",[606,734,735],{"__ignoreMap":732},[736,737,740,744,748],"span",{"class":738,"line":739},"line",1,[736,741,743],{"class":742},"sBMFI","pnpm",[736,745,747],{"class":746},"sfazB"," add",[736,749,750],{"class":746}," @frigear-nu\u002Fmcp\n",[715,752,754],{"id":753},"turn-on-the-tools-you-want","Turn on the tools you want",[593,756,757,758,760,761,763,764,630],{},"Each module adds its tools only when its ",[606,759,665],{}," is ",[606,762,681],{},". The default is ",[606,765,766],{},"false",[768,769,770,771,774,775,778,779,781,782,630],"warning",{},"MCP's own options go under ",[606,772,773],{},"mcpModules",", not ",[606,776,777],{},"mcp",". The ",[606,780,777],{}," key belongs to ",[606,783,629],{},[727,785,790],{"className":786,"code":787,"filename":788,"language":789,"meta":732,"style":732},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  users: { settings: { mcp: true } },\n  events: { settings: { mcp: true } },\n  forms: { settings: { mcp: true } },\n  payments: { settings: { mcp: true } },\n  subscriptions: { settings: { mcp: true } },\n  oauthServer: { settings: { mcp: true } },\n})\n","nuxt.config.ts","ts",[606,791,792,813,848,874,900,926,952,978],{"__ignoreMap":732},[736,793,794,798,801,805,809],{"class":738,"line":739},[736,795,797],{"class":796},"s7zQu","export",[736,799,800],{"class":796}," default",[736,802,804],{"class":803},"s2Zo4"," defineNuxtConfig",[736,806,808],{"class":807},"sTEyZ","(",[736,810,812],{"class":811},"sMK4o","{\n",[736,814,816,820,823,826,829,831,833,836,838,842,845],{"class":738,"line":815},2,[736,817,819],{"class":818},"swJcz","  users",[736,821,822],{"class":811},":",[736,824,825],{"class":811}," {",[736,827,828],{"class":818}," settings",[736,830,822],{"class":811},[736,832,825],{"class":811},[736,834,835],{"class":818}," mcp",[736,837,822],{"class":811},[736,839,841],{"class":840},"sfNiH"," true",[736,843,844],{"class":811}," }",[736,846,847],{"class":811}," },\n",[736,849,851,854,856,858,860,862,864,866,868,870,872],{"class":738,"line":850},3,[736,852,853],{"class":818},"  events",[736,855,822],{"class":811},[736,857,825],{"class":811},[736,859,828],{"class":818},[736,861,822],{"class":811},[736,863,825],{"class":811},[736,865,835],{"class":818},[736,867,822],{"class":811},[736,869,841],{"class":840},[736,871,844],{"class":811},[736,873,847],{"class":811},[736,875,877,880,882,884,886,888,890,892,894,896,898],{"class":738,"line":876},4,[736,878,879],{"class":818},"  forms",[736,881,822],{"class":811},[736,883,825],{"class":811},[736,885,828],{"class":818},[736,887,822],{"class":811},[736,889,825],{"class":811},[736,891,835],{"class":818},[736,893,822],{"class":811},[736,895,841],{"class":840},[736,897,844],{"class":811},[736,899,847],{"class":811},[736,901,903,906,908,910,912,914,916,918,920,922,924],{"class":738,"line":902},5,[736,904,905],{"class":818},"  payments",[736,907,822],{"class":811},[736,909,825],{"class":811},[736,911,828],{"class":818},[736,913,822],{"class":811},[736,915,825],{"class":811},[736,917,835],{"class":818},[736,919,822],{"class":811},[736,921,841],{"class":840},[736,923,844],{"class":811},[736,925,847],{"class":811},[736,927,929,932,934,936,938,940,942,944,946,948,950],{"class":738,"line":928},6,[736,930,931],{"class":818},"  subscriptions",[736,933,822],{"class":811},[736,935,825],{"class":811},[736,937,828],{"class":818},[736,939,822],{"class":811},[736,941,825],{"class":811},[736,943,835],{"class":818},[736,945,822],{"class":811},[736,947,841],{"class":840},[736,949,844],{"class":811},[736,951,847],{"class":811},[736,953,955,958,960,962,964,966,968,970,972,974,976],{"class":738,"line":954},7,[736,956,957],{"class":818},"  oauthServer",[736,959,822],{"class":811},[736,961,825],{"class":811},[736,963,828],{"class":818},[736,965,822],{"class":811},[736,967,825],{"class":811},[736,969,835],{"class":818},[736,971,822],{"class":811},[736,973,841],{"class":840},[736,975,844],{"class":811},[736,977,847],{"class":811},[736,979,981,984],{"class":738,"line":980},8,[736,982,983],{"class":811},"}",[736,985,986],{"class":807},")\n",[988,989,990,1003],"table",{},[991,992,993],"thead",{},[994,995,996,1000],"tr",{},[997,998,999],"th",{},"Module",[997,1001,1002],{},"Tools",[1004,1005,1006,1021,1034,1050,1065,1080],"tbody",{},[994,1007,1008,1014],{},[1009,1010,1011],"td",{},[606,1012,1013],{},"events",[1009,1015,1016,1017,630],{},"Events, tickets and staff catalogue tools. See ",[597,1018,1020],{"href":1019},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fserver#mcp-tools","MCP tools",[994,1022,1023,1028],{},[1009,1024,1025],{},[606,1026,1027],{},"forms",[1009,1029,1030,1031,630],{},"Forms, submitting and staff tools. See ",[597,1032,1020],{"href":1033},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fserver#mcp-tools",[994,1035,1036,1041],{},[1009,1037,1038],{},[606,1039,1040],{},"oauthServer",[1009,1042,1043,1046,1047,630],{},[606,1044,1045],{},"my-oauth-applications",", with the permission ",[606,1048,1049],{},"oauth:read",[994,1051,1052,1057],{},[1009,1053,1054],{},[606,1055,1056],{},"users",[1009,1058,1059,1046,1062,630],{},[606,1060,1061],{},"get-my-profile",[606,1063,1064],{},"profile:read",[994,1066,1067,1072],{},[1009,1068,1069],{},[606,1070,1071],{},"payments",[1009,1073,1074,1046,1077,630],{},[606,1075,1076],{},"my-payments",[606,1078,1079],{},"payments:read",[994,1081,1082,1087],{},[1009,1083,1084],{},[606,1085,1086],{},"subscriptions",[1009,1088,1089,1046,1092,630],{},[606,1090,1091],{},"my-subscriptions",[606,1093,1094],{},"subscriptions:read",[715,1096,1098],{"id":1097},"connect-an-agent","Connect an agent",[593,1100,1101,1102,1105,1106,630],{},"Create an API token with the scopes the agent needs. A tool appears only when the token carries its permission and the\nuser still holds it through their roles. Point the agent's MCP client at ",[606,1103,1104],{},"https:\u002F\u002F\u003Cyour app>\u002Fmcp",", with the\nheader ",[606,1107,1108],{},"Authorization: Bearer fnu_…",[1110,1111,1114,1117,1118,1121,1122,691,1125,1128,1129,1132],"callout",{"color":1112,"icon":1113},"success","i-lucide-check",[643,1115,1116],{},"What you should see:"," with a token that carries only ",[606,1119,1120],{},"tickets:read",", the agent lists ",[606,1123,1124],{},"list-events",[606,1126,1127],{},"get-event"," and\n",[606,1130,1131],{},"my-tickets",", and no staff tools.",[632,1134,1136],{"id":1135},"options","Options",[593,1138,1139,1140,1142],{},"Options go under the ",[606,1141,773],{}," key.",[988,1144,1145,1161],{},[991,1146,1147],{},[994,1148,1149,1152,1155,1158],{},[997,1150,1151],{},"Option",[997,1153,1154],{},"Type",[997,1156,1157],{},"Default",[997,1159,1160],{},"Purpose",[1004,1162,1163],{},[994,1164,1165,1170,1175,1179],{},[1009,1166,1167],{},[606,1168,1169],{},"route",[1009,1171,1172],{},[606,1173,1174],{},"string",[1009,1176,1177],{},[606,1178,608],{},[1009,1180,1181,1182,630],{},"The route of the MCP endpoint. It sets the toolkit's ",[606,1183,1184],{},"mcp.route",[593,1186,1187,1188,1191,1192,1195,1196,1199],{},"The module sets the toolkit's ",[606,1189,1190],{},"mcp.instructions",", unless your app sets its own. They tell the agent that it acts as the\nuser, that personal data needs a ",[606,1193,1194],{},"*:pii"," permission, that some settings change only in the admin area, and how money is\nwritten. The module also turns on Nitro's ",[606,1197,1198],{},"asyncContext",", which the definers use to reach the request.",[632,1201,1203],{"id":1202},"server","Server",[593,1205,1206],{},"Add tools, resources and prompts to MCP from a module. This section is for module authors.",[715,1208,1210],{"id":1209},"rules-every-tool-follows","Rules every tool follows",[988,1212,1213,1223],{},[991,1214,1215],{},[994,1216,1217,1220],{},[997,1218,1219],{},"Rule",[997,1221,1222],{},"What it means",[1004,1224,1225,1245,1265,1277,1292,1308,1316,1324,1332,1340],{},[994,1226,1227,1230],{},[1009,1228,1229],{},"Permission",[1009,1231,1232,1233,1236,1237,1240,1241,1244],{},"Every definition declares one ",[606,1234,1235],{},"permission",". The caller never sees a tool they are not allowed, and a direct call is refused. The check is ",[606,1238,1239],{},"allows"," on every listing and ",[606,1242,1243],{},"authorize"," on every call, so a token needs a scope that covers the permission and the user must hold it through a role.",[994,1246,1247,1250],{},[1009,1248,1249],{},"Staff tools",[1009,1251,1252,1253,1256,1257,1260,1261,1264],{},"They use a staff permission such as ",[606,1254,1255],{},"events:manage",", so roles, ",[597,1258,1259],{"href":210},"policies"," and the ",[606,1262,1263],{},"authorization:before"," hook apply on every listing and call.",[994,1266,1267,1270],{},[1009,1268,1269],{},"\"My\" tools",[1009,1271,1272,1273,1276],{},"They take no user id. They act on the signed-in user (",[606,1274,1275],{},"ctx.user",").",[994,1278,1279,1282],{},[1009,1280,1281],{},"Personal data",[1009,1283,1284,1285,1287,1288,1291],{},"Staff tools return ids, statuses and counts. Names, emails and answers need a personally identifiable information (PII) permission, ",[606,1286,1194],{},", which no wildcard grants. For now these permissions gate MCP tool output only: the admin HTTP API of the same data (attendees, submissions) is gated by the module's ",[606,1289,1290],{},":manage"," permission.",[994,1293,1294,1297],{},[1009,1295,1296],{},"Money",[1009,1298,1299,1300,1303,1304,1307],{},"Amounts are whole currency units next to a currency code: ",[606,1301,1302],{},"52.2"," with ",[606,1305,1306],{},"\"USD\""," is 52.20 dollars.",[994,1309,1310,1313],{},[1009,1311,1312],{},"No exfiltration",[1009,1314,1315],{},"Where form submissions are delivered can be neither read nor changed through MCP.",[994,1317,1318,1321],{},[1009,1319,1320],{},"Session-only areas",[1009,1322,1323],{},"User administration and OAuth application administration are not exposed.",[994,1325,1326,1329],{},[1009,1327,1328],{},"Unscoped definitions",[1009,1330,1331],{},"A definition not made with the scoped definers is dropped.",[994,1333,1334,1337],{},[1009,1335,1336],{},"Unserializable input",[1009,1338,1339],{},"A tool whose input cannot become JSON Schema is dropped and logged.",[994,1341,1342,1345],{},[1009,1343,1344],{},"Failing checks",[1009,1346,1347],{},"A permission check that throws hides the tool, and a call is refused. The module fails closed.",[593,1349,1350,1351,1354,1355,1358,1359,1362,1363,630],{},"Convert at the edge with ",[606,1352,1353],{},"fromCents"," and ",[606,1356,1357],{},"toCents"," from\n",[606,1360,1361],{},"@frigear-nu\u002Fmcp\u002Futils",", which know that JPY has no decimals, and describe money fields with ",[606,1364,1365],{},"MONEY_NOTICE",[715,1367,1369],{"id":1368},"add-tools-from-a-module","Add tools from a module",[593,1371,1372,1373,1376],{},"Register the tools from the module's ",[606,1374,1375],{},"setup()",", only when your app turned them on, as the built-in modules do:",[727,1378,1380],{"className":786,"code":1379,"language":789,"meta":732,"style":732},"import { registerAccess } from '@frigear-nu\u002Fauth\u002Futils'\nimport { addMcpDefinitions } from '@frigear-nu\u002Fmcp\u002Futils'\nimport { notesAccess } from '.\u002Fruntime\u002Faccess' \u002F\u002F defineAccess('notes', { permissions: { read, manage, pii }, scopes: { notes } })\n\n\u002F\u002F moduleDependencies: { '@frigear-nu\u002Fmcp': { version: '>=0.0.1' } }\nregisterAccess(nuxt, notesAccess) \u002F\u002F notes:read (implicit), notes:manage, notes:pii and the `notes` scope\nif (options.settings?.mcp === true) addMcpDefinitions(nuxt, resolver.resolve('.\u002Fruntime\u002Fserver\u002Fmcp'))\n",[606,1381,1382,1406,1425,1450,1456,1461,1478],{"__ignoreMap":732},[736,1383,1384,1387,1389,1392,1394,1397,1400,1403],{"class":738,"line":739},[736,1385,1386],{"class":796},"import",[736,1388,825],{"class":811},[736,1390,1391],{"class":807}," registerAccess",[736,1393,844],{"class":811},[736,1395,1396],{"class":796}," from",[736,1398,1399],{"class":811}," '",[736,1401,1402],{"class":746},"@frigear-nu\u002Fauth\u002Futils",[736,1404,1405],{"class":811},"'\n",[736,1407,1408,1410,1412,1415,1417,1419,1421,1423],{"class":738,"line":815},[736,1409,1386],{"class":796},[736,1411,825],{"class":811},[736,1413,1414],{"class":807}," addMcpDefinitions",[736,1416,844],{"class":811},[736,1418,1396],{"class":796},[736,1420,1399],{"class":811},[736,1422,1361],{"class":746},[736,1424,1405],{"class":811},[736,1426,1427,1429,1431,1434,1436,1438,1440,1443,1446],{"class":738,"line":850},[736,1428,1386],{"class":796},[736,1430,825],{"class":811},[736,1432,1433],{"class":807}," notesAccess",[736,1435,844],{"class":811},[736,1437,1396],{"class":796},[736,1439,1399],{"class":811},[736,1441,1442],{"class":746},".\u002Fruntime\u002Faccess",[736,1444,1445],{"class":811},"'",[736,1447,1449],{"class":1448},"sHwdD"," \u002F\u002F defineAccess('notes', { permissions: { read, manage, pii }, scopes: { notes } })\n",[736,1451,1452],{"class":738,"line":876},[736,1453,1455],{"emptyLinePlaceholder":1454},true,"\n",[736,1457,1458],{"class":738,"line":902},[736,1459,1460],{"class":1448},"\u002F\u002F moduleDependencies: { '@frigear-nu\u002Fmcp': { version: '>=0.0.1' } }\n",[736,1462,1463,1466,1469,1472,1475],{"class":738,"line":928},[736,1464,1465],{"class":803},"registerAccess",[736,1467,1468],{"class":807},"(nuxt",[736,1470,1471],{"class":811},",",[736,1473,1474],{"class":807}," notesAccess) ",[736,1476,1477],{"class":1448},"\u002F\u002F notes:read (implicit), notes:manage, notes:pii and the `notes` scope\n",[736,1479,1480,1483,1486,1488,1491,1494,1497,1500,1502,1505,1508,1510,1512,1515,1517,1520,1522,1524,1527,1529],{"class":738,"line":954},[736,1481,1482],{"class":796},"if",[736,1484,1485],{"class":807}," (options",[736,1487,630],{"class":811},[736,1489,1490],{"class":807},"settings",[736,1492,1493],{"class":811},"?.",[736,1495,1496],{"class":807},"mcp ",[736,1498,1499],{"class":811},"===",[736,1501,841],{"class":840},[736,1503,1504],{"class":807},") ",[736,1506,1507],{"class":803},"addMcpDefinitions",[736,1509,1468],{"class":807},[736,1511,1471],{"class":811},[736,1513,1514],{"class":807}," resolver",[736,1516,630],{"class":811},[736,1518,1519],{"class":803},"resolve",[736,1521,808],{"class":807},[736,1523,1445],{"class":811},[736,1525,1526],{"class":746},".\u002Fruntime\u002Fserver\u002Fmcp",[736,1528,1445],{"class":811},[736,1530,1531],{"class":807},"))\n",[593,1533,1534,1537,1538,1541,1542,1545,1546,1354,1549,1552,1553,1555,1556,1559,1560,630],{},[606,1535,1536],{},"addMcpDefinitions(nuxt, dir)"," takes a folder laid out like a project's ",[606,1539,1540],{},"server\u002Fmcp",", with optional ",[606,1543,1544],{},"tools\u002F",",\n",[606,1547,1548],{},"resources\u002F",[606,1550,1551],{},"prompts\u002F",". A subfolder of ",[606,1554,1544],{}," becomes a group: ",[606,1557,1558],{},"tools\u002Fadmin\u002F…"," is the group ",[606,1561,1562],{},"admin",[715,1564,1566],{"id":1565},"define-a-tool","Define a tool",[593,1568,1569,1570,1572,1573,1576,1577,1580],{},"Three auto-imported definers take the toolkit's options plus ",[606,1571,1235],{},", and pass a ",[606,1574,1575],{},"ScopedMcpContext"," to the\nhandler. For money and credential actions, use a ",[606,1578,1579],{},"sessionOnly"," permission, so a token never reaches the tool.",[988,1582,1583,1593],{},[991,1584,1585],{},[994,1586,1587,1590],{},[997,1588,1589],{},"Definer",[997,1591,1592],{},"Handler signature",[1004,1594,1595,1607,1619],{},[994,1596,1597,1602],{},[1009,1598,1599],{},[606,1600,1601],{},"defineScopedMcpTool",[1009,1603,1604],{},[606,1605,1606],{},"(args, ctx: ScopedMcpContext, extra) => result",[994,1608,1609,1614],{},[1009,1610,1611],{},[606,1612,1613],{},"defineScopedMcpResource",[1009,1615,1616],{},[606,1617,1618],{},"(ctx: ScopedMcpContext, ...toolkitResourceArgs) => result",[994,1620,1621,1626],{},[1009,1622,1623],{},[606,1624,1625],{},"defineScopedMcpPrompt",[1009,1627,1628],{},[606,1629,1630],{},"(args, ctx: ScopedMcpContext) => result",[727,1632,1634],{"className":786,"code":1633,"language":789,"meta":732,"style":732},"interface ScopedAccess {\n  \u002F**\n   * Required: a definition without a permission is never exposed. The caller must be allowed it on every listing and\n   * call. Whether it is session only, and who holds it, comes from its `addPermission` definition.\n   *\u002F\n  permission: string\n}\n\ninterface ScopedMcpContext {\n  event: H3Event\n  principal: AuthPrincipal\n  \u002F** The authenticated user. Use this; never take a user id as an argument. *\u002F\n  user: AuthUser\n  \u002F** Whether the caller is allowed `permission` (e.g. an opt-in `*:pii`), optionally for a record. Async. *\u002F\n  can: (permission: string, record?: unknown) => Promise\u003Cboolean>\n}\n",[606,1635,1636,1648,1653,1658,1663,1668,1678,1683,1687,1697,1708,1719,1725,1736,1742,1789],{"__ignoreMap":732},[736,1637,1638,1642,1645],{"class":738,"line":739},[736,1639,1641],{"class":1640},"spNyl","interface",[736,1643,1644],{"class":742}," ScopedAccess",[736,1646,1647],{"class":811}," {\n",[736,1649,1650],{"class":738,"line":815},[736,1651,1652],{"class":1448},"  \u002F**\n",[736,1654,1655],{"class":738,"line":850},[736,1656,1657],{"class":1448},"   * Required: a definition without a permission is never exposed. The caller must be allowed it on every listing and\n",[736,1659,1660],{"class":738,"line":876},[736,1661,1662],{"class":1448},"   * call. Whether it is session only, and who holds it, comes from its `addPermission` definition.\n",[736,1664,1665],{"class":738,"line":902},[736,1666,1667],{"class":1448},"   *\u002F\n",[736,1669,1670,1673,1675],{"class":738,"line":928},[736,1671,1672],{"class":818},"  permission",[736,1674,822],{"class":811},[736,1676,1677],{"class":742}," string\n",[736,1679,1680],{"class":738,"line":954},[736,1681,1682],{"class":811},"}\n",[736,1684,1685],{"class":738,"line":980},[736,1686,1455],{"emptyLinePlaceholder":1454},[736,1688,1690,1692,1695],{"class":738,"line":1689},9,[736,1691,1641],{"class":1640},[736,1693,1694],{"class":742}," ScopedMcpContext",[736,1696,1647],{"class":811},[736,1698,1700,1703,1705],{"class":738,"line":1699},10,[736,1701,1702],{"class":818},"  event",[736,1704,822],{"class":811},[736,1706,1707],{"class":742}," H3Event\n",[736,1709,1711,1714,1716],{"class":738,"line":1710},11,[736,1712,1713],{"class":818},"  principal",[736,1715,822],{"class":811},[736,1717,1718],{"class":742}," AuthPrincipal\n",[736,1720,1722],{"class":738,"line":1721},12,[736,1723,1724],{"class":1448},"  \u002F** The authenticated user. Use this; never take a user id as an argument. *\u002F\n",[736,1726,1728,1731,1733],{"class":738,"line":1727},13,[736,1729,1730],{"class":818},"  user",[736,1732,822],{"class":811},[736,1734,1735],{"class":742}," AuthUser\n",[736,1737,1739],{"class":738,"line":1738},14,[736,1740,1741],{"class":1448},"  \u002F** Whether the caller is allowed `permission` (e.g. an opt-in `*:pii`), optionally for a record. Async. *\u002F\n",[736,1743,1745,1748,1750,1752,1755,1757,1760,1762,1765,1768,1771,1774,1777,1780,1783,1786],{"class":738,"line":1744},15,[736,1746,1747],{"class":818},"  can",[736,1749,822],{"class":811},[736,1751,694],{"class":811},[736,1753,1235],{"class":1754},"sHdIc",[736,1756,822],{"class":811},[736,1758,1759],{"class":742}," string",[736,1761,1471],{"class":811},[736,1763,1764],{"class":1754}," record",[736,1766,1767],{"class":811},"?:",[736,1769,1770],{"class":742}," unknown",[736,1772,1773],{"class":811},")",[736,1775,1776],{"class":1640}," =>",[736,1778,1779],{"class":742}," Promise",[736,1781,1782],{"class":811},"\u003C",[736,1784,1785],{"class":742},"boolean",[736,1787,1788],{"class":811},">\n",[736,1790,1792],{"class":738,"line":1791},16,[736,1793,1682],{"class":811},[727,1795,1798],{"className":786,"code":1796,"filename":1797,"language":789,"meta":732,"style":732},"export default defineScopedMcpTool({\n  description: 'List my notes',\n  permission: 'notes:read',\n  handler: (_args, { user }) => listNotes(user.id),\n})\n","runtime\u002Fserver\u002Fmcp\u002Ftools\u002Fmy-notes.ts",[606,1799,1800,1813,1829,1844,1881],{"__ignoreMap":732},[736,1801,1802,1804,1806,1809,1811],{"class":738,"line":739},[736,1803,797],{"class":796},[736,1805,800],{"class":796},[736,1807,1808],{"class":803}," defineScopedMcpTool",[736,1810,808],{"class":807},[736,1812,812],{"class":811},[736,1814,1815,1818,1820,1822,1825,1827],{"class":738,"line":815},[736,1816,1817],{"class":818},"  description",[736,1819,822],{"class":811},[736,1821,1399],{"class":811},[736,1823,1824],{"class":746},"List my notes",[736,1826,1445],{"class":811},[736,1828,1545],{"class":811},[736,1830,1831,1833,1835,1837,1840,1842],{"class":738,"line":850},[736,1832,1672],{"class":818},[736,1834,822],{"class":811},[736,1836,1399],{"class":811},[736,1838,1839],{"class":746},"notes:read",[736,1841,1445],{"class":811},[736,1843,1545],{"class":811},[736,1845,1846,1849,1851,1853,1856,1858,1860,1863,1866,1868,1871,1874,1876,1879],{"class":738,"line":876},[736,1847,1848],{"class":803},"  handler",[736,1850,822],{"class":811},[736,1852,694],{"class":811},[736,1854,1855],{"class":1754},"_args",[736,1857,1471],{"class":811},[736,1859,825],{"class":811},[736,1861,1862],{"class":1754}," user",[736,1864,1865],{"class":811}," })",[736,1867,1776],{"class":1640},[736,1869,1870],{"class":803}," listNotes",[736,1872,1873],{"class":807},"(user",[736,1875,630],{"class":811},[736,1877,1878],{"class":807},"id)",[736,1880,1545],{"class":811},[736,1882,1883,1885],{"class":738,"line":902},[736,1884,983],{"class":811},[736,1886,986],{"class":807},[593,1888,1889,1890,1893],{},"A staff tool declares a staff permission, and withholds personal data unless the caller also holds the PII permission.\n",[606,1891,1892],{},"ctx.can"," is asynchronous, so await it:",[727,1895,1898],{"className":786,"code":1896,"filename":1897,"language":789,"meta":732,"style":732},"export default defineScopedMcpTool({\n  description: 'List every note (staff)',\n  permission: 'notes:manage',\n  handler: async (_args, ctx) => {\n    const allow = await ctx.can('notes:pii')\n    const notes = listAllNotes().map(note => redactPii(pick(note, ['id', 'text', 'ownerEmail']), { allow, fields: ['ownerEmail'] }))\n    return { notice: piiNotice(allow, 'notes:pii', 'Owner emails'), notes }\n  },\n})\n","runtime\u002Fserver\u002Fmcp\u002Ftools\u002Fadmin\u002Flist-all-notes.ts",[606,1899,1900,1912,1927,1942,1966,1998,2097,2143,2148],{"__ignoreMap":732},[736,1901,1902,1904,1906,1908,1910],{"class":738,"line":739},[736,1903,797],{"class":796},[736,1905,800],{"class":796},[736,1907,1808],{"class":803},[736,1909,808],{"class":807},[736,1911,812],{"class":811},[736,1913,1914,1916,1918,1920,1923,1925],{"class":738,"line":815},[736,1915,1817],{"class":818},[736,1917,822],{"class":811},[736,1919,1399],{"class":811},[736,1921,1922],{"class":746},"List every note (staff)",[736,1924,1445],{"class":811},[736,1926,1545],{"class":811},[736,1928,1929,1931,1933,1935,1938,1940],{"class":738,"line":850},[736,1930,1672],{"class":818},[736,1932,822],{"class":811},[736,1934,1399],{"class":811},[736,1936,1937],{"class":746},"notes:manage",[736,1939,1445],{"class":811},[736,1941,1545],{"class":811},[736,1943,1944,1946,1948,1951,1953,1955,1957,1960,1962,1964],{"class":738,"line":876},[736,1945,1848],{"class":803},[736,1947,822],{"class":811},[736,1949,1950],{"class":1640}," async",[736,1952,694],{"class":811},[736,1954,1855],{"class":1754},[736,1956,1471],{"class":811},[736,1958,1959],{"class":1754}," ctx",[736,1961,1773],{"class":811},[736,1963,1776],{"class":1640},[736,1965,1647],{"class":811},[736,1967,1968,1971,1974,1977,1980,1982,1984,1987,1989,1991,1994,1996],{"class":738,"line":902},[736,1969,1970],{"class":1640},"    const",[736,1972,1973],{"class":807}," allow",[736,1975,1976],{"class":811}," =",[736,1978,1979],{"class":796}," await",[736,1981,1959],{"class":807},[736,1983,630],{"class":811},[736,1985,1986],{"class":803},"can",[736,1988,808],{"class":818},[736,1990,1445],{"class":811},[736,1992,1993],{"class":746},"notes:pii",[736,1995,1445],{"class":811},[736,1997,986],{"class":818},[736,1999,2000,2002,2005,2007,2010,2013,2015,2018,2020,2022,2024,2027,2029,2032,2034,2036,2038,2041,2043,2046,2048,2050,2052,2055,2057,2059,2061,2064,2066,2069,2071,2073,2075,2077,2080,2082,2084,2086,2088,2090,2093,2095],{"class":738,"line":928},[736,2001,1970],{"class":1640},[736,2003,2004],{"class":807}," notes",[736,2006,1976],{"class":811},[736,2008,2009],{"class":803}," listAllNotes",[736,2011,2012],{"class":818},"()",[736,2014,630],{"class":811},[736,2016,2017],{"class":803},"map",[736,2019,808],{"class":818},[736,2021,683],{"class":1754},[736,2023,1776],{"class":1640},[736,2025,2026],{"class":803}," redactPii",[736,2028,808],{"class":818},[736,2030,2031],{"class":803},"pick",[736,2033,808],{"class":818},[736,2035,683],{"class":807},[736,2037,1471],{"class":811},[736,2039,2040],{"class":818}," [",[736,2042,1445],{"class":811},[736,2044,2045],{"class":746},"id",[736,2047,1445],{"class":811},[736,2049,1471],{"class":811},[736,2051,1399],{"class":811},[736,2053,2054],{"class":746},"text",[736,2056,1445],{"class":811},[736,2058,1471],{"class":811},[736,2060,1399],{"class":811},[736,2062,2063],{"class":746},"ownerEmail",[736,2065,1445],{"class":811},[736,2067,2068],{"class":818},"])",[736,2070,1471],{"class":811},[736,2072,825],{"class":811},[736,2074,1973],{"class":807},[736,2076,1471],{"class":811},[736,2078,2079],{"class":818}," fields",[736,2081,822],{"class":811},[736,2083,2040],{"class":818},[736,2085,1445],{"class":811},[736,2087,2063],{"class":746},[736,2089,1445],{"class":811},[736,2091,2092],{"class":818},"] ",[736,2094,983],{"class":811},[736,2096,1531],{"class":818},[736,2098,2099,2102,2104,2107,2109,2112,2114,2117,2119,2121,2123,2125,2127,2129,2132,2134,2136,2138,2140],{"class":738,"line":954},[736,2100,2101],{"class":796},"    return",[736,2103,825],{"class":811},[736,2105,2106],{"class":818}," notice",[736,2108,822],{"class":811},[736,2110,2111],{"class":803}," piiNotice",[736,2113,808],{"class":818},[736,2115,2116],{"class":807},"allow",[736,2118,1471],{"class":811},[736,2120,1399],{"class":811},[736,2122,1993],{"class":746},[736,2124,1445],{"class":811},[736,2126,1471],{"class":811},[736,2128,1399],{"class":811},[736,2130,2131],{"class":746},"Owner emails",[736,2133,1445],{"class":811},[736,2135,1773],{"class":818},[736,2137,1471],{"class":811},[736,2139,2004],{"class":807},[736,2141,2142],{"class":811}," }\n",[736,2144,2145],{"class":738,"line":980},[736,2146,2147],{"class":811},"  },\n",[736,2149,2150,2152],{"class":738,"line":1689},[736,2151,983],{"class":811},[736,2153,986],{"class":807},[593,2155,2156],{},"These helpers are auto-imported too:",[727,2158,2160],{"className":786,"code":2159,"language":789,"meta":732,"style":732},"pick(row, ['id', 'text']) \u002F\u002F an explicit allow-list, so a new column is never exposed by accident\nredactPii(row, { allow, fields }) \u002F\u002F drops `fields` unless `allow`\npiiNotice(allowed, permission, fieldsLabel) \u002F\u002F message for the agent when data was withheld; undefined when allowed\n",[606,2161,2162,2193,2218],{"__ignoreMap":732},[736,2163,2164,2166,2169,2171,2173,2175,2177,2179,2181,2183,2185,2187,2190],{"class":738,"line":739},[736,2165,2031],{"class":803},[736,2167,2168],{"class":807},"(row",[736,2170,1471],{"class":811},[736,2172,2040],{"class":807},[736,2174,1445],{"class":811},[736,2176,2045],{"class":746},[736,2178,1445],{"class":811},[736,2180,1471],{"class":811},[736,2182,1399],{"class":811},[736,2184,2054],{"class":746},[736,2186,1445],{"class":811},[736,2188,2189],{"class":807},"]) ",[736,2191,2192],{"class":1448},"\u002F\u002F an explicit allow-list, so a new column is never exposed by accident\n",[736,2194,2195,2198,2200,2202,2204,2206,2208,2211,2213,2215],{"class":738,"line":815},[736,2196,2197],{"class":803},"redactPii",[736,2199,2168],{"class":807},[736,2201,1471],{"class":811},[736,2203,825],{"class":811},[736,2205,1973],{"class":807},[736,2207,1471],{"class":811},[736,2209,2210],{"class":807}," fields ",[736,2212,983],{"class":811},[736,2214,1504],{"class":807},[736,2216,2217],{"class":1448},"\u002F\u002F drops `fields` unless `allow`\n",[736,2219,2220,2223,2226,2228,2231,2233,2236],{"class":738,"line":850},[736,2221,2222],{"class":803},"piiNotice",[736,2224,2225],{"class":807},"(allowed",[736,2227,1471],{"class":811},[736,2229,2230],{"class":807}," permission",[736,2232,1471],{"class":811},[736,2234,2235],{"class":807}," fieldsLabel) ",[736,2237,2238],{"class":1448},"\u002F\u002F message for the agent when data was withheld; undefined when allowed\n",[768,2240,2241,2242,2245],{},"Return allow-listed fields, never a raw database row. Write input schemas with plain types: zod transforms and\n",[606,2243,2244],{},"z.coerce.date()"," cannot become JSON Schema, and such a tool is dropped. Parse with your REST schema inside the handler.",[593,2247,2248,2250,2251,691,2254,1260,2257,1545,2260,1354,2263,2266],{},[606,2249,1361],{}," also exports ",[606,2252,2253],{},"permissionTags",[606,2255,2256],{},"SCOPED_META_KEY",[606,2258,2259],{},"ScopedAccess",[606,2261,2262],{},"RedactOptions",[606,2264,2265],{},"McpDefinitionKind"," types.",[632,2268,234],{"id":2269},"hooks",[593,2271,2272],{},"MCP adds one build-time hook and listens to two Nitro hooks of the toolkit.",[988,2274,2275,2288],{},[991,2276,2277],{},[994,2278,2279,2282,2285],{},[997,2280,2281],{},"Hook",[997,2283,2284],{},"When",[997,2286,2287],{},"Payload",[1004,2289,2290,2309,2325],{},[994,2291,2292,2298,2304],{},[1009,2293,2294,2297],{},[606,2295,2296],{},"mcp:definitions:paths"," (Nuxt)",[1009,2299,2300,2301,2303],{},"Build time, while definition folders are collected. ",[606,2302,1507],{}," pushes to it.",[1009,2305,2306],{},[606,2307,2308],{},"{ tools, resources, prompts, handlers: string[] }",[994,2310,2311,2317,2320],{},[1009,2312,2313,2316],{},[606,2314,2315],{},"mcp:config:resolved"," (Nitro, toolkit)",[1009,2318,2319],{},"Per request. The module drops unscoped or non-serializable definitions here.",[1009,2321,2322],{},[606,2323,2324],{},"{ config, event }",[994,2326,2327,2332,2335],{},[1009,2328,2329,2316],{},[606,2330,2331],{},"mcp:tool:called",[1009,2333,2334],{},"After every tool call. The module logs the call.",[1009,2336,2337],{},[606,2338,2339],{},"{ name, result, durationMs, event }",[632,2341,2343],{"id":2342},"next-steps","Next steps",[637,2345,2346,2351,2359,2364],{},[640,2347,2348,2350],{},[597,2349,195],{"href":196}," – the page where users create the API tokens agents connect with.",[640,2352,2353,2355,2356,2358],{},[597,2354,67],{"href":68}," – how permissions, scopes, policies and the ",[606,2357,1263],{}," hook combine.",[640,2360,2361,2363],{},[597,2362,199],{"href":200}," – roles, and which role holds the permissions your tools declare.",[640,2365,2366,2368],{},[597,2367,72],{"href":73}," – how MCP's registry fits next to menus, widgets and tabs.",[2370,2371,2372],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":732,"searchDepth":815,"depth":815,"links":2374},[2375,2376,2381,2382,2387,2388],{"id":634,"depth":815,"text":635},{"id":709,"depth":815,"text":710,"children":2377},[2378,2379,2380],{"id":717,"depth":850,"text":718},{"id":753,"depth":850,"text":754},{"id":1097,"depth":850,"text":1098},{"id":1135,"depth":815,"text":1136},{"id":1202,"depth":815,"text":1203,"children":2383},[2384,2385,2386],{"id":1209,"depth":850,"text":1210},{"id":1368,"depth":850,"text":1369},{"id":1565,"depth":850,"text":1566},{"id":2269,"depth":815,"text":234},{"id":2342,"depth":815,"text":2343},"Let AI agents use your app on a user's behalf, seeing only the tools and data that user's token allows.","md",null,{},{"title":317,"description":2389},"VOFtHImPxagA9hgXf3xfmlhMILfhnDTmBywfILHVKhw",[2396,2398],{"title":313,"path":314,"stem":315,"description":2397,"children":-1},"Ask visitors before your app sets non-essential cookies, load scripts only after they agree, and keep proof.",{"title":173,"path":327,"stem":328,"description":2399,"children":-1},"Gives every module's screens the same headings, cards, tables, forms and toasts, on top of Nuxt UI.",1794503148600]