@noodleseed/agent-kit 0.44.1 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/manifest.json +241 -241
  2. package/package.json +1 -1
  3. package/skills/claude-code/SKILL.md +1 -1
  4. package/skills/claude-code/authoring-mcp-servers/SKILL.md +1 -1
  5. package/skills/claude-code/building-mcp-apps/SKILL.md +1 -1
  6. package/skills/claude-code/connecting-apis-to-mcp/SKILL.md +1 -1
  7. package/skills/claude-code/debugging-mcp-delivery/SKILL.md +1 -1
  8. package/skills/claude-code/deploying-mcp-services/SKILL.md +1 -1
  9. package/skills/claude-code/designing-mcp-products/SKILL.md +1 -1
  10. package/skills/claude-code/embedding-mcp-assistants/SKILL.md +1 -1
  11. package/skills/claude-code/examples/customer-auth/README.md +31 -10
  12. package/skills/claude-code/executing-noodle-plans/SKILL.md +1 -1
  13. package/skills/claude-code/publishing-mcp-integrations/SKILL.md +1 -1
  14. package/skills/claude-code/references/embedded-assistant.md +16 -8
  15. package/skills/claude-code/reporting-noodle-feedback/SKILL.md +1 -1
  16. package/skills/claude-code/verifying-mcp-delivery/SKILL.md +1 -1
  17. package/skills/codex/SKILL.md +1 -1
  18. package/skills/codex/authoring-mcp-servers/SKILL.md +1 -1
  19. package/skills/codex/building-mcp-apps/SKILL.md +1 -1
  20. package/skills/codex/connecting-apis-to-mcp/SKILL.md +1 -1
  21. package/skills/codex/debugging-mcp-delivery/SKILL.md +1 -1
  22. package/skills/codex/deploying-mcp-services/SKILL.md +1 -1
  23. package/skills/codex/designing-mcp-products/SKILL.md +1 -1
  24. package/skills/codex/embedding-mcp-assistants/SKILL.md +1 -1
  25. package/skills/codex/examples/customer-auth/README.md +31 -10
  26. package/skills/codex/executing-noodle-plans/SKILL.md +1 -1
  27. package/skills/codex/publishing-mcp-integrations/SKILL.md +1 -1
  28. package/skills/codex/references/embedded-assistant.md +16 -8
  29. package/skills/codex/reporting-noodle-feedback/SKILL.md +1 -1
  30. package/skills/codex/verifying-mcp-delivery/SKILL.md +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/agent-kit",
3
- "version": "0.44.1",
3
+ "version": "0.46.0",
4
4
  "private": false,
5
5
  "description": "Self-checking, self-updating agent skills for the Noodle Seed CLI. Authored in this repo by @noodle-borg/agent-kit; this is the published, independently-versioned canonical skills artifact the CLI fetches and verifies.",
6
6
  "license": "Apache-2.0",
@@ -3,7 +3,7 @@ name: noodle-seed
3
3
  description: "Use when building, validating, testing, deploying, or operating a local or hosted Noodle Seed MCP server or app authored in TypeScript with the noodle CLI."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:cd6ca0d915e6acb9 -->
6
+ <!-- noodle-skill version:0.46.0 hash:cd6ca0d915e6acb9 -->
7
7
 
8
8
  # Noodle Seed
9
9
 
@@ -3,7 +3,7 @@ name: authoring-mcp-servers
3
3
  description: "Use when creating or extending a headless Noodle Seed MCP server, tool, resource, prompt, or typed model-facing capability."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:0b2fd8c7e43fc69f -->
6
+ <!-- noodle-skill version:0.46.0 hash:0b2fd8c7e43fc69f -->
7
7
 
8
8
  # authoring-mcp-servers
9
9
 
@@ -3,7 +3,7 @@ name: building-mcp-apps
3
3
  description: "Use when a Noodle Seed MCP App, widget, interactive card, visual interaction, or host-visible UI is the primary requested outcome."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:f7fa54992c8d7692 -->
6
+ <!-- noodle-skill version:0.46.0 hash:f7fa54992c8d7692 -->
7
7
 
8
8
  # building-mcp-apps
9
9
 
@@ -3,7 +3,7 @@ name: connecting-apis-to-mcp
3
3
  description: "Use when credentials, an API URL, an OpenAPI document, or an observed response must become real Noodle Seed MCP behavior."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:1e86b8704f407bd3 -->
6
+ <!-- noodle-skill version:0.46.0 hash:1e86b8704f407bd3 -->
7
7
 
8
8
  # connecting-apis-to-mcp
9
9
 
@@ -3,7 +3,7 @@ name: debugging-mcp-delivery
3
3
  description: "Use when an existing Noodle Seed MCP project has a concrete validation, runtime, connector, App, host, deployment, or production failure."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:aa715bae12041d7c -->
6
+ <!-- noodle-skill version:0.46.0 hash:aa715bae12041d7c -->
7
7
 
8
8
  # debugging-mcp-delivery
9
9
 
@@ -3,7 +3,7 @@ name: deploying-mcp-services
3
3
  description: "Use when the user explicitly requests a Noodle Seed hosted link, configuration write, deployment, access change, rollback, or connection write."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:93e735b7ffb45df1 -->
6
+ <!-- noodle-skill version:0.46.0 hash:93e735b7ffb45df1 -->
7
7
 
8
8
  # deploying-mcp-services
9
9
 
@@ -3,7 +3,7 @@ name: designing-mcp-products
3
3
  description: "Use when a Noodle Seed MCP product idea needs conversational fit, user benefit, scope, interaction, or evidence design before implementation."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:76cce86729cffbee -->
6
+ <!-- noodle-skill version:0.46.0 hash:76cce86729cffbee -->
7
7
 
8
8
  # designing-mcp-products
9
9
 
@@ -3,7 +3,7 @@ name: embedding-mcp-assistants
3
3
  description: "Use when embedding a Noodle assistant into an existing SaaS or web application with browser, identity, session, and credential boundaries."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:5d8f40f904d6ab4b -->
6
+ <!-- noodle-skill version:0.46.0 hash:5d8f40f904d6ab4b -->
7
7
 
8
8
  # embedding-mcp-assistants
9
9
 
@@ -193,11 +193,14 @@ import { NoodleAssistant } from '@noodleseed/assistant/react';
193
193
 
194
194
  <NoodleAssistant
195
195
  sessionEndpoint="/api/noodle-assistant/session"
196
- theme="auto"
196
+ theme={resolvedTheme}
197
197
  onSessionExpired={() => console.info('Assistant session renewed')}
198
198
  />;
199
199
  ```
200
200
 
201
+ `resolvedTheme` is the application's current `'light' | 'dark'` value. Use `theme="auto"` only when the
202
+ browser operating-system preference is intentionally authoritative.
203
+
201
204
  For an entirely application-owned React renderer, use the renderer-free hook. It creates no custom element
202
205
  and returns the AI SDK transcript plus the canonical client commands:
203
206
 
@@ -205,9 +208,16 @@ and returns the AI SDK transcript plus the canonical client commands:
205
208
  'use client';
206
209
 
207
210
  import { useState } from 'react';
211
+ import { NoodleAppView } from '@noodleseed/assistant/react';
208
212
  import { useNoodleAssistant } from '@noodleseed/assistant/react/client';
209
213
 
210
- export function CustomerAssistant({ principalKey }: { principalKey: string }) {
214
+ export function CustomerAssistant({
215
+ principalKey,
216
+ resolvedTheme,
217
+ }: {
218
+ principalKey: string;
219
+ resolvedTheme: 'light' | 'dark';
220
+ }) {
211
221
  const [draft, setDraft] = useState('');
212
222
  const { client, messages, status, error } = useNoodleAssistant({
213
223
  sessionEndpoint: '/api/noodle-assistant/session',
@@ -274,9 +284,12 @@ export function CustomerAssistant({ principalKey }: { principalKey: string }) {
274
284
  }
275
285
  if (part.type === 'data-view') {
276
286
  return (
277
- <p key={part.data.id}>
278
- Trusted app view available: {part.data.title ?? part.data.resourceUri}
279
- </p>
287
+ <NoodleAppView
288
+ key={`${part.data.id}:${part.data.resourceUri}`}
289
+ client={client}
290
+ view={part.data}
291
+ theme={resolvedTheme}
292
+ />
280
293
  );
281
294
  }
282
295
  return <p key={index}>Unsupported assistant content.</p>;
@@ -315,8 +328,12 @@ export function CustomerAssistant({ principalKey }: { principalKey: string }) {
315
328
  then aborts and clears the prior session and transcript. The sample fails closed on input requests until its
316
329
  fallback is replaced with a form generated from `requestedSchema`. A production renderer must show the
317
330
  complete confirmation review and both decisions. For `data-view`, map `resourceUri` or `tool` and the
318
- bounded/redacted result to a component already trusted by this application. Never inject `part.data.html`,
319
- assign it to `srcdoc`, or fetch a `ui://` URI.
331
+ bounded/redacted result to a component already trusted by this application only when intentionally replacing
332
+ the linked App with a native UI. Otherwise use `NoodleAppView`; JSON result data is not the App UI. Its
333
+ semantic lifecycle identity is the client plus `view.id` plus `view.resourceUri`, so parent payload/callback
334
+ rerenders keep the iframe and only a different view or unmount tears down the bridge.
335
+ Never inject `part.data.html`, assign it to `srcdoc`, fetch a `ui://` URI, or reproduce the bridge directly. Pages with a
336
+ Content-Security-Policy must include the Noodle service origin in both `connect-src` and `frame-src`.
320
337
 
321
338
  Outside React, subscribe to the DOM-free client directly. It exposes the same conversation as headless AI
322
339
  SDK `UIMessage` state, including typed confirmation, input, tool-result, and linked-view parts:
@@ -340,9 +357,13 @@ assistant.subscribeChat((state) => {
340
357
  });
341
358
  ```
342
359
 
343
- `theme="auto"` follows the SaaS application. The server-level `branding` block is inherited by both MCP App
344
- widgets and the assistant; documented `--ns-assistant-*` semantic CSS variables remain the final integration
345
- escape hatch. There is no second assistant branding declaration.
360
+ `theme="auto"` follows the browser operating-system preference, not a SaaS-owned theme toggle. Pass the
361
+ application's resolved `light`/`dark` theme to both `NoodleAssistant` and `NoodleAppView`; later updates
362
+ reach mounted MCP Apps without remounting them. CSS custom properties inherit through the assistant host, so
363
+ typed appearance roles may reuse existing application tokens with `var(--app-token)`. The server-level
364
+ `branding` block is inherited by both MCP App widgets and the assistant; documented `--ns-assistant-*`
365
+ semantic CSS variables remain the final integration escape hatch. There is no second assistant branding
366
+ declaration.
346
367
  The end-user UI contains only customer branding.
347
368
  Text streams progressively. Expired turns re-exchange through the authenticated backend and retry once;
348
369
  consent-bound tool confirmations never replay automatically.
@@ -3,7 +3,7 @@ name: executing-noodle-plans
3
3
  description: "Use when the user asks to execute an approved, decision-complete implementation plan for a Noodle Seed project task by task with test-first changes, review, recovery, and final verification."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:6a9f132ddb79352e -->
6
+ <!-- noodle-skill version:0.46.0 hash:6a9f132ddb79352e -->
7
7
 
8
8
  # Execute a Noodle Seed implementation plan
9
9
 
@@ -3,7 +3,7 @@ name: publishing-mcp-integrations
3
3
  description: "Use when preparing, reviewing, or submitting a Noodle Seed MCP integration to a host or app directory."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:efffbf82007f935d -->
6
+ <!-- noodle-skill version:0.46.0 hash:efffbf82007f935d -->
7
7
 
8
8
  # publishing-mcp-integrations
9
9
 
@@ -82,7 +82,7 @@ assistant: embeddedAssistant({
82
82
 
83
83
  The Atlas-style product treatment above is the maximum deployment-configurable presentation. The bounded surface covers panel treatment, launcher icon/size/session pulse, header mark/status badge, composer controls, and message treatment; it does not accept custom header actions, structured empty-state layouts, footers, spectacle variants/effects, or tenant code.
84
84
 
85
- Omitted fields retain the quiet premium baseline. For exact application-owned color roles, pass the typed React `appearance={{ light: { panel: { surface, text, border }, composer: {...}, confirmation: {...}, primaryButton: {...} }, dark: {...} }}` prop or assign the same object to `element.appearance`. It covers canvas, panel, header, messages, composer, suggestions, confirmation, buttons, launcher, code, and the MCP App frame. Exact colors are preserved and low contrast emits `assistant-appearance-warning`. Precedence is host appearance object, host slots/public `--ns-assistant-*` variables, deployed semantic presentation, then defaults. Prefer `server.ts` configuration first so every embedding app receives the same assistant after redeploy.
85
+ Omitted fields retain the quiet premium baseline. For exact application-owned color roles, pass the typed React `appearance={{ light: { panel: { surface, text, border }, composer: {...}, confirmation: {...}, primaryButton: {...} }, dark: {...} }}` prop or assign the same object to `element.appearance`. CSS custom properties inherit through the assistant host, so those values may reuse existing application tokens such as `surface: "var(--app-surface)"` without copying literals. The appearance surface covers canvas, panel, header, messages, composer, suggestions, confirmation, buttons, launcher, code, and the MCP App frame; the package README publishes the complete role-to-`--ns-assistant-*` map. Exact parseable literal colors are preserved and low contrast emits `assistant-appearance-warning`; contrast for unresolved CSS references remains host-owned. Precedence is host appearance object, host slots/public variables, deployed semantic presentation, then defaults. Prefer `server.ts` configuration first so every embedding app receives the same assistant after redeploy.
86
86
 
87
87
  Give every business action a portable `tool(..., { title: "Complete task", description: "This will mark the task complete for everyone.", input: z.object({ task: z.string().meta({ title: "Task" }) }) })` title. The standard confirmation uses the tool title/description plus schema field `title`, `description`, and `format`; it shows Confirm and Don't proceed and keeps technical action details secondary. Do not put JSON or implementation names in business-facing copy.
88
88
 
@@ -241,11 +241,13 @@ Use the React wrapper in React applications:
241
241
  ```tsx
242
242
  import { NoodleAssistant } from "@noodleseed/assistant/react";
243
243
 
244
- <NoodleAssistant sessionEndpoint="/api/assistant/session" theme="auto" />;
244
+ <NoodleAssistant sessionEndpoint="/api/assistant/session" theme={resolvedTheme} />;
245
245
  ```
246
246
 
247
247
  Or import the package root once and mount `<noodle-assistant session-endpoint="/api/assistant/session" theme="auto"></noodle-assistant>`. Mount only inside the authenticated application surface.
248
248
 
249
+ `theme="auto"` follows the browser operating-system preference. If the SaaS application owns a theme toggle, obtain its resolved application theme (`"light"` or `"dark"`), pass `theme={resolvedTheme}` to `NoodleAssistant`, and update the custom element's `theme` attribute when that value changes.
250
+
249
251
  The component renders a custom element and must mount client-side. In a Next.js App Router tree, put the mount in a `"use client"` component; from a server component or the Pages Router, load it with `next/dynamic` and `ssr: false`.
250
252
 
251
253
  For a customer-owned React renderer, use the renderer-free hook. It owns client lifetime and React subscription while `client` remains the one command surface:
@@ -254,9 +256,10 @@ For a customer-owned React renderer, use the renderer-free hook. It owns client
254
256
  "use client";
255
257
 
256
258
  import { useState } from "react";
259
+ import { NoodleAppView } from "@noodleseed/assistant/react";
257
260
  import { useNoodleAssistant } from "@noodleseed/assistant/react/client";
258
261
 
259
- export function CustomAssistant({ principalKey }: { principalKey: string }) {
262
+ export function CustomAssistant({ principalKey, resolvedTheme }: { principalKey: string; resolvedTheme: "light" | "dark" }) {
260
263
  const [draft, setDraft] = useState("");
261
264
  const { client, messages, status, error } = useNoodleAssistant({
262
265
  sessionEndpoint: "/api/assistant/session",
@@ -327,9 +330,12 @@ export function CustomAssistant({ principalKey }: { principalKey: string }) {
327
330
  }
328
331
  if (part.type === "data-view") {
329
332
  return (
330
- <p key={part.data.id}>
331
- Trusted app view available: {part.data.title ?? part.data.resourceUri}
332
- </p>
333
+ <NoodleAppView
334
+ key={`${part.data.id}:${part.data.resourceUri}`}
335
+ client={client}
336
+ view={part.data}
337
+ theme={resolvedTheme}
338
+ />
333
339
  );
334
340
  }
335
341
  return <p key={index}>Unsupported assistant content.</p>;
@@ -364,7 +370,9 @@ export function CustomAssistant({ principalKey }: { principalKey: string }) {
364
370
 
365
371
  `principalKey` is a browser-local identity for the authenticated user/tenant and is never sent to Noodle. Change it whenever that principal changes; the hook then aborts and clears the previous session and transcript. The hook does not register `<noodle-assistant>` or render Noodle markup.
366
372
 
367
- The sample fails closed on input requests until you replace that branch with a form generated from `requestedSchema`. A custom renderer must show the complete confirmation review and both decisions, handle every part it supports, and surface an explicit unsupported state for the rest. For `data-view`, map `resourceUri` or `tool` plus the bounded/redacted `result` to a component already trusted by the application. Never inject `part.data.html`, assign it to `srcdoc`, or fetch a `ui://` URI; the managed element alone supplies Noodle’s sandbox host. Do not wrap this client in another chat transport or invent user messages for interaction continuations.
373
+ The sample fails closed on input requests until you replace that branch with a form generated from `requestedSchema`. A custom renderer must show the complete confirmation review and both decisions, handle every part it supports, and surface an explicit unsupported state for the rest. For `data-view`, use `NoodleAppView` to render the linked App or deliberately map `resourceUri`/tool plus the bounded redacted `result` to an application-trusted native component. JSON result data is not the linked App UI. Never inject `part.data.html`, assign it to `srcdoc`, fetch a `ui://` URI, or reproduce the bridge with a direct Ext Apps dependency. Do not wrap this client in another chat transport or invent user messages for interaction continuations.
374
+
375
+ `NoodleAppView` owns one bridge for the semantic view identity: client + `view.id` + `view.resourceUri`. It retains the iframe across fresh payload/callback/theme rerenders, reads current payloads through refs, publishes later resolved-theme changes through MCP Apps host context, and sends standard App teardown only when that semantic identity changes or the component unmounts. Pass the same resolved application theme used by the conversation shell. Do not key an ancestor by a view object or callback. If the embedding page sets Content-Security-Policy, include the Noodle service origin in both `connect-src` and `frame-src`.
368
376
 
369
377
  Outside React, use the same DOM-free client directly. It keeps the session token in memory, exposes a React-free `UIMessage` transcript with typed parts, and never registers a custom element:
370
378
 
@@ -416,7 +424,7 @@ if (pending) {
416
424
 
417
425
  `subscribeChat` immediately emits a detached `{ messages, status, error? }` snapshot and then emits as `UIMessage.parts` change. Text uses `text`; Noodle confirmations, input requests, tool results, and linked views use `data-confirmation`, `data-input-request`, `data-tool-result`, and `data-view`. Interaction data moves through pending/submitting/accepted/declined/cancelled. Use raw `subscribe(...)` only for transport/session lifecycle events that are not transcript content.
418
426
 
419
- `data-view` means a completed tool has a linked MCP App view. It carries the call/interaction id, tool, `ui://` identity, optional title, bounded/redacted public result, and—on current services—the self-contained bridged document. The standard element is an MCP Apps host and mounts that document behind a double iframe; a customer renderer ignores it and maps the identity/result to an application-trusted component. The standard element supports lifecycle, app tool/resource calls, ui/message, ui/update-model-context, links, resize, and inline/fullscreen; sampling, tasks, downloads, and remote DOM are not advertised. It also dispatches `assistant-view-available` for a customer-owned renderer.
427
+ `data-view` means a completed tool has a linked MCP App view. In a customer-owned React renderer, pass that typed part and the existing client to `NoodleAppView`; it retains one bridge for client + `view.id` + `view.resourceUri` and requests standard App teardown on semantic replacement or unmount. Deliberately map the bounded result to an application-trusted native component only when replacing the linked App UI.
420
428
 
421
429
  `clientContext` and typed `pageContext` are recomputed for each turn. `updateContext(...)` remains the legacy session-exchange context; `updatePageContext(...)` replaces the fresh per-turn application hint. `updateModelContext({ content, structuredContent })` publishes one cohesive renderer snapshot for later message turns without starting a turn; every call replaces the prior snapshot rather than merging fields. These are untrusted data, not conversation history or authorization input, and the boundaries reject credential-shaped or unbounded updates. A message may re-exchange once after a pre-execution `401`; the client never auto-retries interaction decisions. `tool_proposed.arguments` is a complete schema-aware review projection and, for connector-backed tools, names the sole exact connector version/operation/resolved arguments. Sensitive/write-only fields are redacted; truncating or omitting any non-sensitive action field fails closed. Accept is bound to the server-held action and claims at most one execution attempt—clients cannot replace it. Normal terminal outcomes scrub private arguments and continuations immediately; only an accepted action still executing retains them for the one-hour unknown-outcome recovery window, after which it records `interaction_outcome_unknown` and scrubs. Without downstream idempotency this is not an exactly-once business-effect guarantee. To reconcile a lost response, explicitly repeat the same id and decision: the service returns its durable stored outcome without re-execution.
422
430
 
@@ -3,7 +3,7 @@ name: reporting-noodle-feedback
3
3
  description: "Use when a Noodle Seed bug, misleading instruction, missing capability, or concrete product improvement should be proposed to the user."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:0f404109f4845683 -->
6
+ <!-- noodle-skill version:0.46.0 hash:0f404109f4845683 -->
7
7
 
8
8
  # reporting-noodle-feedback
9
9
 
@@ -3,7 +3,7 @@ name: verifying-mcp-delivery
3
3
  description: "Use when proving a Noodle Seed MCP project works at a named compile, local, connector, App, host, deployment, or production evidence level."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:6ef6ef551e26b78e -->
6
+ <!-- noodle-skill version:0.46.0 hash:6ef6ef551e26b78e -->
7
7
 
8
8
  # verifying-mcp-delivery
9
9
 
@@ -3,7 +3,7 @@ name: noodle-seed
3
3
  description: "Use when building, validating, testing, deploying, or operating a local or hosted Noodle Seed MCP server or app authored in TypeScript with the noodle CLI."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:cd6ca0d915e6acb9 -->
6
+ <!-- noodle-skill version:0.46.0 hash:cd6ca0d915e6acb9 -->
7
7
 
8
8
  # Noodle Seed
9
9
 
@@ -3,7 +3,7 @@ name: authoring-mcp-servers
3
3
  description: "Use when creating or extending a headless Noodle Seed MCP server, tool, resource, prompt, or typed model-facing capability."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:0b2fd8c7e43fc69f -->
6
+ <!-- noodle-skill version:0.46.0 hash:0b2fd8c7e43fc69f -->
7
7
 
8
8
  # authoring-mcp-servers
9
9
 
@@ -3,7 +3,7 @@ name: building-mcp-apps
3
3
  description: "Use when a Noodle Seed MCP App, widget, interactive card, visual interaction, or host-visible UI is the primary requested outcome."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:f7fa54992c8d7692 -->
6
+ <!-- noodle-skill version:0.46.0 hash:f7fa54992c8d7692 -->
7
7
 
8
8
  # building-mcp-apps
9
9
 
@@ -3,7 +3,7 @@ name: connecting-apis-to-mcp
3
3
  description: "Use when credentials, an API URL, an OpenAPI document, or an observed response must become real Noodle Seed MCP behavior."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:1e86b8704f407bd3 -->
6
+ <!-- noodle-skill version:0.46.0 hash:1e86b8704f407bd3 -->
7
7
 
8
8
  # connecting-apis-to-mcp
9
9
 
@@ -3,7 +3,7 @@ name: debugging-mcp-delivery
3
3
  description: "Use when an existing Noodle Seed MCP project has a concrete validation, runtime, connector, App, host, deployment, or production failure."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:aa715bae12041d7c -->
6
+ <!-- noodle-skill version:0.46.0 hash:aa715bae12041d7c -->
7
7
 
8
8
  # debugging-mcp-delivery
9
9
 
@@ -3,7 +3,7 @@ name: deploying-mcp-services
3
3
  description: "Use when the user explicitly requests a Noodle Seed hosted link, configuration write, deployment, access change, rollback, or connection write."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:93e735b7ffb45df1 -->
6
+ <!-- noodle-skill version:0.46.0 hash:93e735b7ffb45df1 -->
7
7
 
8
8
  # deploying-mcp-services
9
9
 
@@ -3,7 +3,7 @@ name: designing-mcp-products
3
3
  description: "Use when a Noodle Seed MCP product idea needs conversational fit, user benefit, scope, interaction, or evidence design before implementation."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:76cce86729cffbee -->
6
+ <!-- noodle-skill version:0.46.0 hash:76cce86729cffbee -->
7
7
 
8
8
  # designing-mcp-products
9
9
 
@@ -3,7 +3,7 @@ name: embedding-mcp-assistants
3
3
  description: "Use when embedding a Noodle assistant into an existing SaaS or web application with browser, identity, session, and credential boundaries."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:5d8f40f904d6ab4b -->
6
+ <!-- noodle-skill version:0.46.0 hash:5d8f40f904d6ab4b -->
7
7
 
8
8
  # embedding-mcp-assistants
9
9
 
@@ -193,11 +193,14 @@ import { NoodleAssistant } from '@noodleseed/assistant/react';
193
193
 
194
194
  <NoodleAssistant
195
195
  sessionEndpoint="/api/noodle-assistant/session"
196
- theme="auto"
196
+ theme={resolvedTheme}
197
197
  onSessionExpired={() => console.info('Assistant session renewed')}
198
198
  />;
199
199
  ```
200
200
 
201
+ `resolvedTheme` is the application's current `'light' | 'dark'` value. Use `theme="auto"` only when the
202
+ browser operating-system preference is intentionally authoritative.
203
+
201
204
  For an entirely application-owned React renderer, use the renderer-free hook. It creates no custom element
202
205
  and returns the AI SDK transcript plus the canonical client commands:
203
206
 
@@ -205,9 +208,16 @@ and returns the AI SDK transcript plus the canonical client commands:
205
208
  'use client';
206
209
 
207
210
  import { useState } from 'react';
211
+ import { NoodleAppView } from '@noodleseed/assistant/react';
208
212
  import { useNoodleAssistant } from '@noodleseed/assistant/react/client';
209
213
 
210
- export function CustomerAssistant({ principalKey }: { principalKey: string }) {
214
+ export function CustomerAssistant({
215
+ principalKey,
216
+ resolvedTheme,
217
+ }: {
218
+ principalKey: string;
219
+ resolvedTheme: 'light' | 'dark';
220
+ }) {
211
221
  const [draft, setDraft] = useState('');
212
222
  const { client, messages, status, error } = useNoodleAssistant({
213
223
  sessionEndpoint: '/api/noodle-assistant/session',
@@ -274,9 +284,12 @@ export function CustomerAssistant({ principalKey }: { principalKey: string }) {
274
284
  }
275
285
  if (part.type === 'data-view') {
276
286
  return (
277
- <p key={part.data.id}>
278
- Trusted app view available: {part.data.title ?? part.data.resourceUri}
279
- </p>
287
+ <NoodleAppView
288
+ key={`${part.data.id}:${part.data.resourceUri}`}
289
+ client={client}
290
+ view={part.data}
291
+ theme={resolvedTheme}
292
+ />
280
293
  );
281
294
  }
282
295
  return <p key={index}>Unsupported assistant content.</p>;
@@ -315,8 +328,12 @@ export function CustomerAssistant({ principalKey }: { principalKey: string }) {
315
328
  then aborts and clears the prior session and transcript. The sample fails closed on input requests until its
316
329
  fallback is replaced with a form generated from `requestedSchema`. A production renderer must show the
317
330
  complete confirmation review and both decisions. For `data-view`, map `resourceUri` or `tool` and the
318
- bounded/redacted result to a component already trusted by this application. Never inject `part.data.html`,
319
- assign it to `srcdoc`, or fetch a `ui://` URI.
331
+ bounded/redacted result to a component already trusted by this application only when intentionally replacing
332
+ the linked App with a native UI. Otherwise use `NoodleAppView`; JSON result data is not the App UI. Its
333
+ semantic lifecycle identity is the client plus `view.id` plus `view.resourceUri`, so parent payload/callback
334
+ rerenders keep the iframe and only a different view or unmount tears down the bridge.
335
+ Never inject `part.data.html`, assign it to `srcdoc`, fetch a `ui://` URI, or reproduce the bridge directly. Pages with a
336
+ Content-Security-Policy must include the Noodle service origin in both `connect-src` and `frame-src`.
320
337
 
321
338
  Outside React, subscribe to the DOM-free client directly. It exposes the same conversation as headless AI
322
339
  SDK `UIMessage` state, including typed confirmation, input, tool-result, and linked-view parts:
@@ -340,9 +357,13 @@ assistant.subscribeChat((state) => {
340
357
  });
341
358
  ```
342
359
 
343
- `theme="auto"` follows the SaaS application. The server-level `branding` block is inherited by both MCP App
344
- widgets and the assistant; documented `--ns-assistant-*` semantic CSS variables remain the final integration
345
- escape hatch. There is no second assistant branding declaration.
360
+ `theme="auto"` follows the browser operating-system preference, not a SaaS-owned theme toggle. Pass the
361
+ application's resolved `light`/`dark` theme to both `NoodleAssistant` and `NoodleAppView`; later updates
362
+ reach mounted MCP Apps without remounting them. CSS custom properties inherit through the assistant host, so
363
+ typed appearance roles may reuse existing application tokens with `var(--app-token)`. The server-level
364
+ `branding` block is inherited by both MCP App widgets and the assistant; documented `--ns-assistant-*`
365
+ semantic CSS variables remain the final integration escape hatch. There is no second assistant branding
366
+ declaration.
346
367
  The end-user UI contains only customer branding.
347
368
  Text streams progressively. Expired turns re-exchange through the authenticated backend and retry once;
348
369
  consent-bound tool confirmations never replay automatically.
@@ -3,7 +3,7 @@ name: executing-noodle-plans
3
3
  description: "Use when the user asks to execute an approved, decision-complete implementation plan for a Noodle Seed project task by task with test-first changes, review, recovery, and final verification."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:6a9f132ddb79352e -->
6
+ <!-- noodle-skill version:0.46.0 hash:6a9f132ddb79352e -->
7
7
 
8
8
  # Execute a Noodle Seed implementation plan
9
9
 
@@ -3,7 +3,7 @@ name: publishing-mcp-integrations
3
3
  description: "Use when preparing, reviewing, or submitting a Noodle Seed MCP integration to a host or app directory."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:efffbf82007f935d -->
6
+ <!-- noodle-skill version:0.46.0 hash:efffbf82007f935d -->
7
7
 
8
8
  # publishing-mcp-integrations
9
9
 
@@ -82,7 +82,7 @@ assistant: embeddedAssistant({
82
82
 
83
83
  The Atlas-style product treatment above is the maximum deployment-configurable presentation. The bounded surface covers panel treatment, launcher icon/size/session pulse, header mark/status badge, composer controls, and message treatment; it does not accept custom header actions, structured empty-state layouts, footers, spectacle variants/effects, or tenant code.
84
84
 
85
- Omitted fields retain the quiet premium baseline. For exact application-owned color roles, pass the typed React `appearance={{ light: { panel: { surface, text, border }, composer: {...}, confirmation: {...}, primaryButton: {...} }, dark: {...} }}` prop or assign the same object to `element.appearance`. It covers canvas, panel, header, messages, composer, suggestions, confirmation, buttons, launcher, code, and the MCP App frame. Exact colors are preserved and low contrast emits `assistant-appearance-warning`. Precedence is host appearance object, host slots/public `--ns-assistant-*` variables, deployed semantic presentation, then defaults. Prefer `server.ts` configuration first so every embedding app receives the same assistant after redeploy.
85
+ Omitted fields retain the quiet premium baseline. For exact application-owned color roles, pass the typed React `appearance={{ light: { panel: { surface, text, border }, composer: {...}, confirmation: {...}, primaryButton: {...} }, dark: {...} }}` prop or assign the same object to `element.appearance`. CSS custom properties inherit through the assistant host, so those values may reuse existing application tokens such as `surface: "var(--app-surface)"` without copying literals. The appearance surface covers canvas, panel, header, messages, composer, suggestions, confirmation, buttons, launcher, code, and the MCP App frame; the package README publishes the complete role-to-`--ns-assistant-*` map. Exact parseable literal colors are preserved and low contrast emits `assistant-appearance-warning`; contrast for unresolved CSS references remains host-owned. Precedence is host appearance object, host slots/public variables, deployed semantic presentation, then defaults. Prefer `server.ts` configuration first so every embedding app receives the same assistant after redeploy.
86
86
 
87
87
  Give every business action a portable `tool(..., { title: "Complete task", description: "This will mark the task complete for everyone.", input: z.object({ task: z.string().meta({ title: "Task" }) }) })` title. The standard confirmation uses the tool title/description plus schema field `title`, `description`, and `format`; it shows Confirm and Don't proceed and keeps technical action details secondary. Do not put JSON or implementation names in business-facing copy.
88
88
 
@@ -241,11 +241,13 @@ Use the React wrapper in React applications:
241
241
  ```tsx
242
242
  import { NoodleAssistant } from "@noodleseed/assistant/react";
243
243
 
244
- <NoodleAssistant sessionEndpoint="/api/assistant/session" theme="auto" />;
244
+ <NoodleAssistant sessionEndpoint="/api/assistant/session" theme={resolvedTheme} />;
245
245
  ```
246
246
 
247
247
  Or import the package root once and mount `<noodle-assistant session-endpoint="/api/assistant/session" theme="auto"></noodle-assistant>`. Mount only inside the authenticated application surface.
248
248
 
249
+ `theme="auto"` follows the browser operating-system preference. If the SaaS application owns a theme toggle, obtain its resolved application theme (`"light"` or `"dark"`), pass `theme={resolvedTheme}` to `NoodleAssistant`, and update the custom element's `theme` attribute when that value changes.
250
+
249
251
  The component renders a custom element and must mount client-side. In a Next.js App Router tree, put the mount in a `"use client"` component; from a server component or the Pages Router, load it with `next/dynamic` and `ssr: false`.
250
252
 
251
253
  For a customer-owned React renderer, use the renderer-free hook. It owns client lifetime and React subscription while `client` remains the one command surface:
@@ -254,9 +256,10 @@ For a customer-owned React renderer, use the renderer-free hook. It owns client
254
256
  "use client";
255
257
 
256
258
  import { useState } from "react";
259
+ import { NoodleAppView } from "@noodleseed/assistant/react";
257
260
  import { useNoodleAssistant } from "@noodleseed/assistant/react/client";
258
261
 
259
- export function CustomAssistant({ principalKey }: { principalKey: string }) {
262
+ export function CustomAssistant({ principalKey, resolvedTheme }: { principalKey: string; resolvedTheme: "light" | "dark" }) {
260
263
  const [draft, setDraft] = useState("");
261
264
  const { client, messages, status, error } = useNoodleAssistant({
262
265
  sessionEndpoint: "/api/assistant/session",
@@ -327,9 +330,12 @@ export function CustomAssistant({ principalKey }: { principalKey: string }) {
327
330
  }
328
331
  if (part.type === "data-view") {
329
332
  return (
330
- <p key={part.data.id}>
331
- Trusted app view available: {part.data.title ?? part.data.resourceUri}
332
- </p>
333
+ <NoodleAppView
334
+ key={`${part.data.id}:${part.data.resourceUri}`}
335
+ client={client}
336
+ view={part.data}
337
+ theme={resolvedTheme}
338
+ />
333
339
  );
334
340
  }
335
341
  return <p key={index}>Unsupported assistant content.</p>;
@@ -364,7 +370,9 @@ export function CustomAssistant({ principalKey }: { principalKey: string }) {
364
370
 
365
371
  `principalKey` is a browser-local identity for the authenticated user/tenant and is never sent to Noodle. Change it whenever that principal changes; the hook then aborts and clears the previous session and transcript. The hook does not register `<noodle-assistant>` or render Noodle markup.
366
372
 
367
- The sample fails closed on input requests until you replace that branch with a form generated from `requestedSchema`. A custom renderer must show the complete confirmation review and both decisions, handle every part it supports, and surface an explicit unsupported state for the rest. For `data-view`, map `resourceUri` or `tool` plus the bounded/redacted `result` to a component already trusted by the application. Never inject `part.data.html`, assign it to `srcdoc`, or fetch a `ui://` URI; the managed element alone supplies Noodle’s sandbox host. Do not wrap this client in another chat transport or invent user messages for interaction continuations.
373
+ The sample fails closed on input requests until you replace that branch with a form generated from `requestedSchema`. A custom renderer must show the complete confirmation review and both decisions, handle every part it supports, and surface an explicit unsupported state for the rest. For `data-view`, use `NoodleAppView` to render the linked App or deliberately map `resourceUri`/tool plus the bounded redacted `result` to an application-trusted native component. JSON result data is not the linked App UI. Never inject `part.data.html`, assign it to `srcdoc`, fetch a `ui://` URI, or reproduce the bridge with a direct Ext Apps dependency. Do not wrap this client in another chat transport or invent user messages for interaction continuations.
374
+
375
+ `NoodleAppView` owns one bridge for the semantic view identity: client + `view.id` + `view.resourceUri`. It retains the iframe across fresh payload/callback/theme rerenders, reads current payloads through refs, publishes later resolved-theme changes through MCP Apps host context, and sends standard App teardown only when that semantic identity changes or the component unmounts. Pass the same resolved application theme used by the conversation shell. Do not key an ancestor by a view object or callback. If the embedding page sets Content-Security-Policy, include the Noodle service origin in both `connect-src` and `frame-src`.
368
376
 
369
377
  Outside React, use the same DOM-free client directly. It keeps the session token in memory, exposes a React-free `UIMessage` transcript with typed parts, and never registers a custom element:
370
378
 
@@ -416,7 +424,7 @@ if (pending) {
416
424
 
417
425
  `subscribeChat` immediately emits a detached `{ messages, status, error? }` snapshot and then emits as `UIMessage.parts` change. Text uses `text`; Noodle confirmations, input requests, tool results, and linked views use `data-confirmation`, `data-input-request`, `data-tool-result`, and `data-view`. Interaction data moves through pending/submitting/accepted/declined/cancelled. Use raw `subscribe(...)` only for transport/session lifecycle events that are not transcript content.
418
426
 
419
- `data-view` means a completed tool has a linked MCP App view. It carries the call/interaction id, tool, `ui://` identity, optional title, bounded/redacted public result, and—on current services—the self-contained bridged document. The standard element is an MCP Apps host and mounts that document behind a double iframe; a customer renderer ignores it and maps the identity/result to an application-trusted component. The standard element supports lifecycle, app tool/resource calls, ui/message, ui/update-model-context, links, resize, and inline/fullscreen; sampling, tasks, downloads, and remote DOM are not advertised. It also dispatches `assistant-view-available` for a customer-owned renderer.
427
+ `data-view` means a completed tool has a linked MCP App view. In a customer-owned React renderer, pass that typed part and the existing client to `NoodleAppView`; it retains one bridge for client + `view.id` + `view.resourceUri` and requests standard App teardown on semantic replacement or unmount. Deliberately map the bounded result to an application-trusted native component only when replacing the linked App UI.
420
428
 
421
429
  `clientContext` and typed `pageContext` are recomputed for each turn. `updateContext(...)` remains the legacy session-exchange context; `updatePageContext(...)` replaces the fresh per-turn application hint. `updateModelContext({ content, structuredContent })` publishes one cohesive renderer snapshot for later message turns without starting a turn; every call replaces the prior snapshot rather than merging fields. These are untrusted data, not conversation history or authorization input, and the boundaries reject credential-shaped or unbounded updates. A message may re-exchange once after a pre-execution `401`; the client never auto-retries interaction decisions. `tool_proposed.arguments` is a complete schema-aware review projection and, for connector-backed tools, names the sole exact connector version/operation/resolved arguments. Sensitive/write-only fields are redacted; truncating or omitting any non-sensitive action field fails closed. Accept is bound to the server-held action and claims at most one execution attempt—clients cannot replace it. Normal terminal outcomes scrub private arguments and continuations immediately; only an accepted action still executing retains them for the one-hour unknown-outcome recovery window, after which it records `interaction_outcome_unknown` and scrubs. Without downstream idempotency this is not an exactly-once business-effect guarantee. To reconcile a lost response, explicitly repeat the same id and decision: the service returns its durable stored outcome without re-execution.
422
430
 
@@ -3,7 +3,7 @@ name: reporting-noodle-feedback
3
3
  description: "Use when a Noodle Seed bug, misleading instruction, missing capability, or concrete product improvement should be proposed to the user."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:0f404109f4845683 -->
6
+ <!-- noodle-skill version:0.46.0 hash:0f404109f4845683 -->
7
7
 
8
8
  # reporting-noodle-feedback
9
9
 
@@ -3,7 +3,7 @@ name: verifying-mcp-delivery
3
3
  description: "Use when proving a Noodle Seed MCP project works at a named compile, local, connector, App, host, deployment, or production evidence level."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.44.1 hash:6ef6ef551e26b78e -->
6
+ <!-- noodle-skill version:0.46.0 hash:6ef6ef551e26b78e -->
7
7
 
8
8
  # verifying-mcp-delivery
9
9