[{"data":1,"prerenderedAt":392},["ShallowReactive",2],{"$fkJkQ4GwMNjVi1S5ZrF1LPWXMZZB1tN1k96ugkA-fM1E":3},{"newThing":4,"project":5,"cycle":8,"sections":20,"threads":386,"otherDocs":387,"documents":388,"images":389,"archiveItems":390,"links":391},null,{"id":6,"label":7,"liveBase":4},"app","app.qpoint.io",{"id":9,"num":10,"dir":11,"name":12,"title":13,"focus":14,"status":15,"statusNote":4,"created":16,"completed":4,"mode":4,"report":4,"recordless":17,"thumbnail":4,"imageCount":18,"artifactCount":18,"lastActivity":19,"hasPickup":17,"hasInitialPrompt":17},"c2",2,"c2.mcp-apps","mcp-apps","MCP Apps","Add AI assistant UI to app.qpoint.io with shared Vue components usable as MCP Apps","active","2026-03-05",false,0,"2026-03-12",[21,35,45,102],{"key":22,"title":23,"empty":17,"ast":24},"why","Why",{"type":25,"children":26},"root",[27],{"type":28,"tag":29,"props":30,"children":31},"element","p",{},[32],{"type":33,"value":34},"text","Qpoint has an MCP server. We want to add an in-app AI assistant and also expose interactive UI widgets to external AI clients (Claude, ChatGPT, VS Code Copilot, Goose) via the MCP Apps extension. Building shared Vue components lets us do both from one codebase.",{"key":36,"title":37,"empty":17,"ast":38},"objective","Objective",{"type":25,"children":39},[40],{"type":28,"tag":29,"props":41,"children":42},{},[43],{"type":33,"value":44},"Design and implement a shared component architecture where Vue components serve both as in-app chat UI widgets and as MCP App bundles. Ship an initial AI assistant chat interface in app.qpoint.io.",{"key":46,"title":47,"empty":17,"ast":48},"scope","Scope",{"type":25,"children":49},[50],{"type":28,"tag":51,"props":52,"children":53},"ul",{},[54,67,78,89],{"type":28,"tag":55,"props":56,"children":57},"li",{},[58,65],{"type":28,"tag":59,"props":60,"children":62},"code",{"className":61},[],[63],{"type":33,"value":64},"app\u002Fcomponents\u002F",{"type":33,"value":66}," — shared presentational components",{"type":28,"tag":55,"props":68,"children":69},{},[70,76],{"type":28,"tag":59,"props":71,"children":73},{"className":72},[],[74],{"type":33,"value":75},"app\u002Fserver\u002Fapi\u002Fchat.ts",{"type":33,"value":77}," — AI SDK chat endpoint (future)",{"type":28,"tag":55,"props":79,"children":80},{},[81,87],{"type":28,"tag":59,"props":82,"children":84},{"className":83},[],[85],{"type":33,"value":86},"mcp-apps\u002F",{"type":33,"value":88}," — MCP App entry points and build config (future)",{"type":28,"tag":55,"props":90,"children":91},{},[92,94,100],{"type":33,"value":93},"MCP server tool definitions with ",{"type":28,"tag":59,"props":95,"children":97},{"className":96},[],[98],{"type":33,"value":99},"_meta.ui",{"type":33,"value":101}," references (future)",{"key":103,"title":104,"empty":17,"ast":105},"extra","Research Findings",{"type":25,"children":106},[107,114,222,228,296,302,314,357,363],{"type":28,"tag":108,"props":109,"children":111},"h3",{"id":110},"approaches-evaluated",[112],{"type":33,"value":113},"Approaches Evaluated",{"type":28,"tag":115,"props":116,"children":117},"ol",{},[118,203,213],{"type":28,"tag":55,"props":119,"children":120},{},[121,127,129],{"type":28,"tag":122,"props":123,"children":124},"strong",{},[125],{"type":33,"value":126},"Vercel AI SDK + Custom Vue UI",{"type":33,"value":128}," (recommended for in-app chat)",{"type":28,"tag":51,"props":130,"children":131},{},[132,153,179,190],{"type":28,"tag":55,"props":133,"children":134},{},[135,137,143,145,151],{"type":33,"value":136},"AI SDK has first-class Nuxt support (",{"type":28,"tag":59,"props":138,"children":140},{"className":139},[],[141],{"type":33,"value":142},"@ai-sdk\u002Fvue",{"type":33,"value":144},", ",{"type":28,"tag":59,"props":146,"children":148},{"className":147},[],[149],{"type":33,"value":150},"useChat",{"type":33,"value":152},")",{"type":28,"tag":55,"props":154,"children":155},{},[156,158,164,165,171,172,178],{"type":33,"value":157},"Nuxt UI has pre-built chat components (",{"type":28,"tag":59,"props":159,"children":161},{"className":160},[],[162],{"type":33,"value":163},"ChatMessage",{"type":33,"value":144},{"type":28,"tag":59,"props":166,"children":168},{"className":167},[],[169],{"type":33,"value":170},"ChatMessages",{"type":33,"value":144},{"type":28,"tag":59,"props":173,"children":175},{"className":174},[],[176],{"type":33,"value":177},"ChatPrompt",{"type":33,"value":152},{"type":28,"tag":55,"props":180,"children":181},{},[182,188],{"type":28,"tag":59,"props":183,"children":185},{"className":184},[],[186],{"type":33,"value":187},"@ai-sdk\u002Fmcp",{"type":33,"value":189}," bridges MCP tools to the AI SDK",{"type":28,"tag":55,"props":191,"children":192},{},[193,195,201],{"type":33,"value":194},"Needs a ",{"type":28,"tag":59,"props":196,"children":198},{"className":197},[],[199],{"type":33,"value":200},"\u002Fserver\u002Fapi\u002Fchat.ts",{"type":33,"value":202}," route to proxy LLM calls",{"type":28,"tag":55,"props":204,"children":205},{},[206,211],{"type":28,"tag":122,"props":207,"children":208},{},[209],{"type":33,"value":210},"CopilotKit",{"type":33,"value":212}," — open-source copilot framework, Vue SDK newer, heavier dependency",{"type":28,"tag":55,"props":214,"children":215},{},[216,220],{"type":28,"tag":122,"props":217,"children":218},{},[219],{"type":33,"value":13},{"type":33,"value":221}," (for external AI clients) — official MCP extension, self-contained HTML in sandboxed iframes",{"type":28,"tag":108,"props":223,"children":225},{"id":224},"mcp-apps-architecture",[226],{"type":33,"value":227},"MCP Apps Architecture",{"type":28,"tag":51,"props":229,"children":230},{},[231,252,257,262,267,286,291],{"type":28,"tag":55,"props":232,"children":233},{},[234,236,242,244,250],{"type":33,"value":235},"Tools declare UI via ",{"type":28,"tag":59,"props":237,"children":239},{"className":238},[],[240],{"type":33,"value":241},"_meta.ui.resourceUri",{"type":33,"value":243}," pointing to a ",{"type":28,"tag":59,"props":245,"children":247},{"className":246},[],[248],{"type":33,"value":249},"ui:\u002F\u002F",{"type":33,"value":251}," resource",{"type":28,"tag":55,"props":253,"children":254},{},[255],{"type":33,"value":256},"UI resources are self-contained HTML files (bundled JS\u002FCSS)",{"type":28,"tag":55,"props":258,"children":259},{},[260],{"type":33,"value":261},"Rendered in double-iframe sandbox by the host client",{"type":28,"tag":55,"props":263,"children":264},{},[265],{"type":33,"value":266},"Communication via JSON-RPC over postMessage",{"type":28,"tag":55,"props":268,"children":269},{},[270,276,278,284],{"type":28,"tag":59,"props":271,"children":273},{"className":272},[],[274],{"type":33,"value":275},"@modelcontextprotocol\u002Fext-apps",{"type":33,"value":277}," provides the ",{"type":28,"tag":59,"props":279,"children":281},{"className":280},[],[282],{"type":33,"value":283},"App",{"type":33,"value":285}," SDK class",{"type":28,"tag":55,"props":287,"children":288},{},[289],{"type":33,"value":290},"Framework-agnostic: official Vue starter template exists",{"type":28,"tag":55,"props":292,"children":293},{},[294],{"type":33,"value":295},"Backward compatible: tools still return text for non-supporting clients",{"type":28,"tag":108,"props":297,"children":299},{"id":298},"shared-component-strategy",[300],{"type":33,"value":301},"Shared Component Strategy",{"type":28,"tag":303,"props":304,"children":308},"pre",{"className":305,"code":307,"language":33},[306],"language-text","Vue Component (pure, prop-driven)\n    |                    |\n    v                    v\nIn-app wrapper       MCP App wrapper\n(composables,        (App SDK,\n Pinia, Pulse API)    ontoolresult,\n                      callServerTool)\n",[309],{"type":28,"tag":59,"props":310,"children":312},{"__ignoreMap":311},"",[313],{"type":33,"value":307},{"type":28,"tag":51,"props":315,"children":316},{},[317,329,334,347,352],{"type":28,"tag":55,"props":318,"children":319},{},[320,322,327],{"type":33,"value":321},"Build Vue components as ",{"type":28,"tag":122,"props":323,"children":324},{},[325],{"type":33,"value":326},"pure presentation",{"type":33,"value":328}," — props in, events out",{"type":28,"tag":55,"props":330,"children":331},{},[332],{"type":33,"value":333},"In Nuxt app: wrap with composables\u002Fstores as normal",{"type":28,"tag":55,"props":335,"children":336},{},[337,339,345],{"type":33,"value":338},"For MCP Apps: thin Vite build using ",{"type":28,"tag":59,"props":340,"children":342},{"className":341},[],[343],{"type":33,"value":344},"vite-plugin-singlefile",{"type":33,"value":346}," to produce self-contained HTML",{"type":28,"tag":55,"props":348,"children":349},{},[350],{"type":33,"value":351},"MCP App wrapper is ~20 lines of glue per component",{"type":28,"tag":55,"props":353,"children":354},{},[355],{"type":33,"value":356},"Shared Tailwind config across both builds",{"type":28,"tag":108,"props":358,"children":360},{"id":359},"key-constraints",[361],{"type":33,"value":362},"Key Constraints",{"type":28,"tag":51,"props":364,"children":365},{},[366,371,376,381],{"type":28,"tag":55,"props":367,"children":368},{},[369],{"type":33,"value":370},"MCP Apps must be self-contained HTML (no SSR, no Nuxt runtime)",{"type":28,"tag":55,"props":372,"children":373},{},[374],{"type":33,"value":375},"Shared components must avoid Nuxt-specific auto-imports (use explicit imports)",{"type":28,"tag":55,"props":377,"children":378},{},[379],{"type":33,"value":380},"Need separate Vite build config for MCP App bundles",{"type":28,"tag":55,"props":382,"children":383},{},[384],{"type":33,"value":385},"Double-iframe sandbox: no access to parent DOM, cookies, or storage",[],[],[],[],[],[],1794599363318]