@noodleseed/agent-kit 0.60.0 → 0.62.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 (42) hide show
  1. package/manifest.json +257 -257
  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/food-ordering/src/helpers.ts +1 -0
  12. package/skills/claude-code/examples/food-ordering/src/views/ordering-flow.tsx +9 -1
  13. package/skills/claude-code/examples/weather/README.md +4 -1
  14. package/skills/claude-code/examples/weather/src/server.ts +2 -0
  15. package/skills/claude-code/examples/weather/test/server.test.ts +11 -0
  16. package/skills/claude-code/executing-noodle-plans/SKILL.md +1 -1
  17. package/skills/claude-code/publishing-mcp-integrations/SKILL.md +1 -1
  18. package/skills/claude-code/references/connect-an-api.md +18 -0
  19. package/skills/claude-code/references/widgets-and-apps.md +6 -4
  20. package/skills/claude-code/reporting-noodle-feedback/SKILL.md +1 -1
  21. package/skills/claude-code/verifying-mcp-delivery/SKILL.md +1 -1
  22. package/skills/claude-code/wrapping-existing-applications/SKILL.md +1 -1
  23. package/skills/codex/SKILL.md +1 -1
  24. package/skills/codex/authoring-mcp-servers/SKILL.md +1 -1
  25. package/skills/codex/building-mcp-apps/SKILL.md +1 -1
  26. package/skills/codex/connecting-apis-to-mcp/SKILL.md +1 -1
  27. package/skills/codex/debugging-mcp-delivery/SKILL.md +1 -1
  28. package/skills/codex/deploying-mcp-services/SKILL.md +1 -1
  29. package/skills/codex/designing-mcp-products/SKILL.md +1 -1
  30. package/skills/codex/embedding-mcp-assistants/SKILL.md +1 -1
  31. package/skills/codex/examples/food-ordering/src/helpers.ts +1 -0
  32. package/skills/codex/examples/food-ordering/src/views/ordering-flow.tsx +9 -1
  33. package/skills/codex/examples/weather/README.md +4 -1
  34. package/skills/codex/examples/weather/src/server.ts +2 -0
  35. package/skills/codex/examples/weather/test/server.test.ts +11 -0
  36. package/skills/codex/executing-noodle-plans/SKILL.md +1 -1
  37. package/skills/codex/publishing-mcp-integrations/SKILL.md +1 -1
  38. package/skills/codex/references/connect-an-api.md +18 -0
  39. package/skills/codex/references/widgets-and-apps.md +6 -4
  40. package/skills/codex/reporting-noodle-feedback/SKILL.md +1 -1
  41. package/skills/codex/verifying-mcp-delivery/SKILL.md +1 -1
  42. package/skills/codex/wrapping-existing-applications/SKILL.md +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/agent-kit",
3
- "version": "0.60.0",
3
+ "version": "0.62.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.60.0 hash:d83543258e5ca5ff -->
6
+ <!-- noodle-skill version:0.62.0 hash:d83543258e5ca5ff -->
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.60.0 hash:0b2fd8c7e43fc69f -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:f7fa54992c8d7692 -->
6
+ <!-- noodle-skill version:0.62.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 all four API-evidence inputs exist—and only then: API base URL, authentication scheme, representative safe read, and observed response."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.60.0 hash:21bbd3ec441ffd30 -->
6
+ <!-- noodle-skill version:0.62.0 hash:21bbd3ec441ffd30 -->
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.60.0 hash:aa715bae12041d7c -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:93e735b7ffb45df1 -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:76cce86729cffbee -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:cc54a67f21c0ecdb -->
6
+ <!-- noodle-skill version:0.62.0 hash:cc54a67f21c0ecdb -->
7
7
 
8
8
  # embedding-mcp-assistants
9
9
 
@@ -34,4 +34,5 @@ export const {
34
34
  useUpdateModelContext,
35
35
  useViewState,
36
36
  useWidgetLifecycle,
37
+ useWidgetReady,
37
38
  } = generateHelpers<AppType>();
@@ -23,6 +23,7 @@ import {
23
23
  useUpdateModelContext,
24
24
  useViewState,
25
25
  useWidgetLifecycle,
26
+ useWidgetReady,
26
27
  View,
27
28
  ViewStack,
28
29
  } from '../helpers.js';
@@ -74,9 +75,10 @@ function modifierLabel(value: string): string {
74
75
  }
75
76
 
76
77
  export default function OrderingFlow() {
78
+ const ready = useWidgetReady();
77
79
  const { displayMode, supports, theme } = useLayout();
78
80
  const toolInfo = useToolInfo('open_ordering');
79
- const isPending = Object.keys(toolInfo).length === 0;
81
+ const isPending = !ready || Object.keys(toolInfo).length === 0;
80
82
  const entry = isOrderingEntryResult(toolInfo.structuredContent)
81
83
  ? toolInfo.structuredContent
82
84
  : undefined;
@@ -357,6 +359,7 @@ export default function OrderingFlow() {
357
359
  </div>
358
360
  <ActionBar className="nw-actions">
359
361
  <SubmitButton
362
+ type="button"
360
363
  className="nw-button nw-button-primary"
361
364
  pending={searchStores.isPending}
362
365
  pendingLabel="Searching..."
@@ -366,6 +369,7 @@ export default function OrderingFlow() {
366
369
  Search stores
367
370
  </SubmitButton>
368
371
  <SubmitButton
372
+ type="button"
369
373
  className="nw-button"
370
374
  pending={readCart.isPending}
371
375
  pendingLabel="Loading..."
@@ -427,6 +431,7 @@ export default function OrderingFlow() {
427
431
  />
428
432
  <ActionBar className="nw-actions">
429
433
  <SubmitButton
434
+ type="button"
430
435
  className="nw-button nw-button-primary"
431
436
  pending={syncCart.isPending}
432
437
  pendingLabel="Adding..."
@@ -459,6 +464,7 @@ export default function OrderingFlow() {
459
464
  </Field>
460
465
  <ActionBar className="nw-actions">
461
466
  <SubmitButton
467
+ type="button"
462
468
  className="nw-button"
463
469
  pending={syncCart.isPending}
464
470
  pendingLabel="Saving..."
@@ -468,6 +474,7 @@ export default function OrderingFlow() {
468
474
  Save cart
469
475
  </SubmitButton>
470
476
  <SubmitButton
477
+ type="button"
471
478
  className="nw-button nw-button-primary"
472
479
  disabled={cart.lines.length === 0}
473
480
  pending={prepareCheckout.isPending}
@@ -491,6 +498,7 @@ export default function OrderingFlow() {
491
498
  Edit cart
492
499
  </button>
493
500
  <SubmitButton
501
+ type="button"
494
502
  className="nw-button nw-button-primary"
495
503
  disabled={cart.lines.length === 0}
496
504
  pending={prepareCheckout.isPending}
@@ -5,7 +5,7 @@ keys**. The `weather_briefing` tool takes a city name and runs a **three-step fl
5
5
 
6
6
  Capability slots: HTTP connector authoring, ordered fulfilment flows, query/response mapping,
7
7
  **list-returning connector output** (a connector that returns a live, variable-length array), and
8
- sandboxed compute.
8
+ sandboxed compute, including an explicit least-privilege per-operation response-size bound.
9
9
 
10
10
  1. **`geo.search`** → geocode the city to coordinates (Open-Meteo Geocoding API)
11
11
  2. **`forecast.current`** → fetch current weather for those coordinates (Open-Meteo Forecast API)
@@ -30,6 +30,9 @@ It exercises, in one TypeScript-authored app:
30
30
  - **A list-returning connector + compute narrowing** — `geo.search_list` binds the whole `results`
31
31
  array; `places.narrow` reduces each element to `{ id, label }` and normalizes the no-results case
32
32
  to `[]`.
33
+ - **A per-operation transport bound** — `search_list` sets
34
+ `limits: { maxResponseBytes: 256 * 1024 }`, tightening this known-small endpoint below the 1 MiB default.
35
+ Raise a limit only when representative evidence proves the required raw response is larger.
33
36
  - **Sandboxed compute** (no network/fs/env/clock) turning raw numbers into conditions + advice.
34
37
  - **Typed input/output schemas** emitted as JSON Schema 2020-12.
35
38
 
@@ -44,6 +44,8 @@ const geocoding = connector('open_meteo_geocoding')
44
44
  method: 'GET',
45
45
  path: '/v1/search',
46
46
  query: ['name', 'count'],
47
+ // This endpoint is intentionally small; tighten its allowance below the 1 MiB default.
48
+ limits: { maxResponseBytes: 256 * 1024 },
47
49
  input: z.object({ name: z.string(), count: z.number().optional() }),
48
50
  output: z.object({ results: z.array(z.unknown()).optional() }),
49
51
  response: {
@@ -26,4 +26,15 @@ describe('weather example', () => {
26
26
  expect(wire).toContain('search_list');
27
27
  expect(wire).toContain('narrow');
28
28
  });
29
+
30
+ it('demonstrates an explicit least-privilege response-size bound', () => {
31
+ const catalog = app.toConnectorCatalog();
32
+ const geocoding = catalog?.connectors.find(
33
+ (candidate) => candidate.id === 'open_meteo_geocoding',
34
+ );
35
+
36
+ expect(geocoding?.operations.search_list?.limits).toEqual({
37
+ maxResponseBytes: 256 * 1024,
38
+ });
39
+ });
29
40
  });
@@ -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.60.0 hash:6a9f132ddb79352e -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:efffbf82007f935d -->
6
+ <!-- noodle-skill version:0.62.0 hash:efffbf82007f935d -->
7
7
 
8
8
  # publishing-mcp-integrations
9
9
 
@@ -111,6 +111,24 @@ pagination: {
111
111
  response: { tasks: '${response.items}' },
112
112
  ```
113
113
 
114
+ ### Bound exceptional response sizes
115
+
116
+ HTTP operations default to a 1 MiB decoded-response limit. Narrow the upstream query, paginate, or
117
+ reduce the requested dataset before raising it; a `response` mapping runs only after the raw body is
118
+ buffered. When representative evidence proves one operation legitimately needs more, grant only that
119
+ operation the required bytes, up to the 3 MiB authoring maximum:
120
+
121
+ ```ts
122
+ search: {
123
+ type: 'read', method: 'GET', path: '/search',
124
+ limits: { maxResponseBytes: 3 * 1024 * 1024 },
125
+ // input / output / response omitted
126
+ },
127
+ ```
128
+
129
+ The inclusive limit counts decoded streamed bytes. `response_too_large` is a safe structured reason;
130
+ never copy a response body, header, URL, credential, or upstream error prose into user-visible output.
131
+
114
132
  ### Create, update, delete
115
133
 
116
134
  Pair the read/list with the mutations your intent tools need:
@@ -34,6 +34,7 @@ Author views as React components. `generateHelpers<ServerDefinition>()` (from `@
34
34
 
35
35
  | Hook | Use for |
36
36
  | :-- | :-- |
37
+ | `useWidgetReady` | Report when the standard MCP Apps bridge has connected; keep tool-backed controls disabled (or render loading) until this returns `true`. |
37
38
  | `useToolInfo` | Read the complete invoking tool result: treat `{}` as pending, handle `isError`, validate every required `structuredContent` field and identifier, reject malformed success data, and render dependent actions only after validation succeeds. |
38
39
  | `useCallTool` | Call a tool from the widget — returns `{ status, callTool, callToolAsync, data, structuredContent, error, reset }`; target a model-visible tool or a hidden `tool` helper. |
39
40
  | `useViewState` | Persist per-widget UI state across re-renders and restores: `const [value, setValue] = useViewState("key", initial)`. |
@@ -47,7 +48,7 @@ Author views as React components. `generateHelpers<ServerDefinition>()` (from `@
47
48
  | `useAppFlow` | Manage named widget views with persisted params and back-stack state: `const flow = useAppFlow({ initialView, views })`. |
48
49
  | `useHandoff` | Open server-created HTTP(S) handoff URLs through the host with status/error state; domain policy still comes from `handoff.allowedDomains`. |
49
50
 
50
- Bind interactive elements to tools (`useCallTool("place_order")`), drive named views with `useAppFlow(...)`, open server-created handoffs with `useHandoff()`, and publish one compact, safe, cohesive snapshot with `useUpdateModelContext()` when `useLayout().supports?.modelContext` is true. Every model-context or lifecycle publication replaces the prior snapshot rather than merging fields, so include everything the model should still know. Calling `useWidgetLifecycle("name")` automatically publishes `mounted`, listens for host `cancelled` and `dismissed`, and returns a publisher for author-owned `submitted` or app-specific milestones; `mounted` is not proof that the host presented pixels. Both hooks use the standard MCP Apps model-context channel, not a host-specific API. These updates affect future model context but do not start a model turn. When an explicit user submit/cancel should receive an immediate reply, also call `useSendFollowUpMessage()` from that user action. `data-llm` may remain a DOM inspection hint, but it is not the bidirectional model-state contract. Use `createViewStore("key", initial)` for multi-component widget state such as carts, filters, or drafts. Use the domain-neutral React components from `@noodleseed/one/react` (`AppShell`, `ShellNav`, `ViewStack`, `AsyncBoundary`, `ActionBar`, `Field`, `QuantityStepper`, `ChoiceGroup`, `HandoffButton`, and related state components) for rich apps before inventing local shell/control scaffolding. Adapt to the host with `useLayout()` — style for both `theme` values, and keep the inline `displayMode` compact (content fits the space; no internal scrolling). Trigger `useOpenExternal()`, `useHandoff()`, and `useSendFollowUpMessage()` only from explicit user actions. A raw `html` escape hatch exists for self-contained widgets (declarative `data-bind`/`data-action`; no inline `<script>`).
51
+ Bind interactive elements to tools (`useCallTool("place_order")`), keep bridge-backed controls disabled until `useWidgetReady()` is true, drive named views with `useAppFlow(...)`, open server-created handoffs with `useHandoff()`, and publish one compact, safe, cohesive snapshot with `useUpdateModelContext()` when `useLayout().supports?.modelContext` is true. Generated form workflows use the portable `<Form onSubmit={...}>` component with a submit button; never add browser-navigation `action`, `method`, or `target` attributes. Existing intrinsic React forms are valid when their `onSubmit` handler calls `preventDefault()` before the explicit tool call and omits those navigation attributes. Standalone actions use an explicit `type="button"` and call the tool from their click handler. In every case the widget calls the standard MCP Apps tool bridge itself — never rely on a host to translate native form submission into a tool call, and never branch on a host name. Every model-context or lifecycle publication replaces the prior snapshot rather than merging fields, so include everything the model should still know. Calling `useWidgetLifecycle("name")` automatically publishes `mounted`, listens for host `cancelled` and `dismissed`, and returns a publisher for author-owned `submitted` or app-specific milestones; `mounted` is not proof that the host presented pixels. Both hooks use the standard MCP Apps model-context channel, not a host-specific API. These updates affect future model context but do not start a model turn. When an explicit user submit/cancel should receive an immediate reply, also call `useSendFollowUpMessage()` from that user action. `data-llm` may remain a DOM inspection hint, but it is not the bidirectional model-state contract. Use `createViewStore("key", initial)` for multi-component widget state such as carts, filters, or drafts. Use the domain-neutral React components from `@noodleseed/one/react` (`AppShell`, `ShellNav`, `ViewStack`, `AsyncBoundary`, `ActionBar`, `Form`, `Field`, `QuantityStepper`, `ChoiceGroup`, `HandoffButton`, and related state components) for rich apps before inventing local shell/control scaffolding. Adapt to the host with `useLayout()` — style for both `theme` values, and keep the inline `displayMode` compact (content fits the space; no internal scrolling). Trigger `useOpenExternal()`, `useHandoff()`, and `useSendFollowUpMessage()` only from explicit user actions. A raw `html` escape hatch exists for self-contained widgets (declarative `data-bind`/`data-action`; no inline `<script>`); raw markup must cancel native form navigation explicitly.
51
52
 
52
53
  ## Worked widget recipe
53
54
 
@@ -63,7 +64,7 @@ import type { ServerDefinition } from '@noodleseed/one';
63
64
  import { Action, ActionBar, AsyncBoundary, Feedback, Field, Flow, Frame, Region, Select, generateHelpers } from '@noodleseed/one/react';
64
65
 
65
66
  // One call wires the typed host bridge; destructure only the hooks this view uses.
66
- const { useToolInfo, useCallTool, useViewState, useLayout, useOpenExternal, useSendFollowUpMessage, useUpdateModelContext, useWidgetLifecycle } =
67
+ const { useToolInfo, useCallTool, useViewState, useLayout, useOpenExternal, useSendFollowUpMessage, useUpdateModelContext, useWidgetLifecycle, useWidgetReady } =
67
68
  generateHelpers<ServerDefinition>();
68
69
 
69
70
  type OrderResult = {
@@ -85,8 +86,9 @@ function isOrderResult(value: unknown): value is OrderResult {
85
86
  }
86
87
 
87
88
  export default function OrderStatus() {
89
+ const ready = useWidgetReady();
88
90
  const toolInfo = useToolInfo('show_order');
89
- const isPending = Object.keys(toolInfo).length === 0;
91
+ const isPending = !ready || Object.keys(toolInfo).length === 0;
90
92
  const shown = isOrderResult(toolInfo.structuredContent) ? toolInfo.structuredContent : undefined;
91
93
  const placeOrder = useCallTool('place_order'); // calls the widget-only helper tool
92
94
  const { supports } = useLayout();
@@ -138,7 +140,7 @@ export default function OrderStatus() {
138
140
  </Region>
139
141
  {confirmed?.status ? <Feedback status="success">{confirmed.status}</Feedback> : null}
140
142
  <ActionBar>
141
- <Action variant="primary" pending={placeOrder.isPending} pendingLabel="Placing…"
143
+ <Action type="button" variant="primary" disabled={!ready} pending={placeOrder.isPending} pendingLabel="Placing…"
142
144
  onClick={submitOrder}
143
145
  >
144
146
  Place order
@@ -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.60.0 hash:0f404109f4845683 -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:6ef6ef551e26b78e -->
6
+ <!-- noodle-skill version:0.62.0 hash:6ef6ef551e26b78e -->
7
7
 
8
8
  # verifying-mcp-delivery
9
9
 
@@ -3,7 +3,7 @@ name: wrapping-existing-applications
3
3
  description: "Use when an existing application has no stable usable API and needs a read-only, identity-first Noodle Seed integration plan before implementation."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.60.0 hash:eccc3c158dcafba8 -->
6
+ <!-- noodle-skill version:0.62.0 hash:eccc3c158dcafba8 -->
7
7
 
8
8
  # wrapping-existing-applications
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.60.0 hash:d83543258e5ca5ff -->
6
+ <!-- noodle-skill version:0.62.0 hash:d83543258e5ca5ff -->
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.60.0 hash:0b2fd8c7e43fc69f -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:f7fa54992c8d7692 -->
6
+ <!-- noodle-skill version:0.62.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 all four API-evidence inputs exist—and only then: API base URL, authentication scheme, representative safe read, and observed response."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.60.0 hash:21bbd3ec441ffd30 -->
6
+ <!-- noodle-skill version:0.62.0 hash:21bbd3ec441ffd30 -->
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.60.0 hash:aa715bae12041d7c -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:93e735b7ffb45df1 -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:76cce86729cffbee -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:cc54a67f21c0ecdb -->
6
+ <!-- noodle-skill version:0.62.0 hash:cc54a67f21c0ecdb -->
7
7
 
8
8
  # embedding-mcp-assistants
9
9
 
@@ -34,4 +34,5 @@ export const {
34
34
  useUpdateModelContext,
35
35
  useViewState,
36
36
  useWidgetLifecycle,
37
+ useWidgetReady,
37
38
  } = generateHelpers<AppType>();
@@ -23,6 +23,7 @@ import {
23
23
  useUpdateModelContext,
24
24
  useViewState,
25
25
  useWidgetLifecycle,
26
+ useWidgetReady,
26
27
  View,
27
28
  ViewStack,
28
29
  } from '../helpers.js';
@@ -74,9 +75,10 @@ function modifierLabel(value: string): string {
74
75
  }
75
76
 
76
77
  export default function OrderingFlow() {
78
+ const ready = useWidgetReady();
77
79
  const { displayMode, supports, theme } = useLayout();
78
80
  const toolInfo = useToolInfo('open_ordering');
79
- const isPending = Object.keys(toolInfo).length === 0;
81
+ const isPending = !ready || Object.keys(toolInfo).length === 0;
80
82
  const entry = isOrderingEntryResult(toolInfo.structuredContent)
81
83
  ? toolInfo.structuredContent
82
84
  : undefined;
@@ -357,6 +359,7 @@ export default function OrderingFlow() {
357
359
  </div>
358
360
  <ActionBar className="nw-actions">
359
361
  <SubmitButton
362
+ type="button"
360
363
  className="nw-button nw-button-primary"
361
364
  pending={searchStores.isPending}
362
365
  pendingLabel="Searching..."
@@ -366,6 +369,7 @@ export default function OrderingFlow() {
366
369
  Search stores
367
370
  </SubmitButton>
368
371
  <SubmitButton
372
+ type="button"
369
373
  className="nw-button"
370
374
  pending={readCart.isPending}
371
375
  pendingLabel="Loading..."
@@ -427,6 +431,7 @@ export default function OrderingFlow() {
427
431
  />
428
432
  <ActionBar className="nw-actions">
429
433
  <SubmitButton
434
+ type="button"
430
435
  className="nw-button nw-button-primary"
431
436
  pending={syncCart.isPending}
432
437
  pendingLabel="Adding..."
@@ -459,6 +464,7 @@ export default function OrderingFlow() {
459
464
  </Field>
460
465
  <ActionBar className="nw-actions">
461
466
  <SubmitButton
467
+ type="button"
462
468
  className="nw-button"
463
469
  pending={syncCart.isPending}
464
470
  pendingLabel="Saving..."
@@ -468,6 +474,7 @@ export default function OrderingFlow() {
468
474
  Save cart
469
475
  </SubmitButton>
470
476
  <SubmitButton
477
+ type="button"
471
478
  className="nw-button nw-button-primary"
472
479
  disabled={cart.lines.length === 0}
473
480
  pending={prepareCheckout.isPending}
@@ -491,6 +498,7 @@ export default function OrderingFlow() {
491
498
  Edit cart
492
499
  </button>
493
500
  <SubmitButton
501
+ type="button"
494
502
  className="nw-button nw-button-primary"
495
503
  disabled={cart.lines.length === 0}
496
504
  pending={prepareCheckout.isPending}
@@ -5,7 +5,7 @@ keys**. The `weather_briefing` tool takes a city name and runs a **three-step fl
5
5
 
6
6
  Capability slots: HTTP connector authoring, ordered fulfilment flows, query/response mapping,
7
7
  **list-returning connector output** (a connector that returns a live, variable-length array), and
8
- sandboxed compute.
8
+ sandboxed compute, including an explicit least-privilege per-operation response-size bound.
9
9
 
10
10
  1. **`geo.search`** → geocode the city to coordinates (Open-Meteo Geocoding API)
11
11
  2. **`forecast.current`** → fetch current weather for those coordinates (Open-Meteo Forecast API)
@@ -30,6 +30,9 @@ It exercises, in one TypeScript-authored app:
30
30
  - **A list-returning connector + compute narrowing** — `geo.search_list` binds the whole `results`
31
31
  array; `places.narrow` reduces each element to `{ id, label }` and normalizes the no-results case
32
32
  to `[]`.
33
+ - **A per-operation transport bound** — `search_list` sets
34
+ `limits: { maxResponseBytes: 256 * 1024 }`, tightening this known-small endpoint below the 1 MiB default.
35
+ Raise a limit only when representative evidence proves the required raw response is larger.
33
36
  - **Sandboxed compute** (no network/fs/env/clock) turning raw numbers into conditions + advice.
34
37
  - **Typed input/output schemas** emitted as JSON Schema 2020-12.
35
38
 
@@ -44,6 +44,8 @@ const geocoding = connector('open_meteo_geocoding')
44
44
  method: 'GET',
45
45
  path: '/v1/search',
46
46
  query: ['name', 'count'],
47
+ // This endpoint is intentionally small; tighten its allowance below the 1 MiB default.
48
+ limits: { maxResponseBytes: 256 * 1024 },
47
49
  input: z.object({ name: z.string(), count: z.number().optional() }),
48
50
  output: z.object({ results: z.array(z.unknown()).optional() }),
49
51
  response: {
@@ -26,4 +26,15 @@ describe('weather example', () => {
26
26
  expect(wire).toContain('search_list');
27
27
  expect(wire).toContain('narrow');
28
28
  });
29
+
30
+ it('demonstrates an explicit least-privilege response-size bound', () => {
31
+ const catalog = app.toConnectorCatalog();
32
+ const geocoding = catalog?.connectors.find(
33
+ (candidate) => candidate.id === 'open_meteo_geocoding',
34
+ );
35
+
36
+ expect(geocoding?.operations.search_list?.limits).toEqual({
37
+ maxResponseBytes: 256 * 1024,
38
+ });
39
+ });
29
40
  });
@@ -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.60.0 hash:6a9f132ddb79352e -->
6
+ <!-- noodle-skill version:0.62.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.60.0 hash:efffbf82007f935d -->
6
+ <!-- noodle-skill version:0.62.0 hash:efffbf82007f935d -->
7
7
 
8
8
  # publishing-mcp-integrations
9
9
 
@@ -111,6 +111,24 @@ pagination: {
111
111
  response: { tasks: '${response.items}' },
112
112
  ```
113
113
 
114
+ ### Bound exceptional response sizes
115
+
116
+ HTTP operations default to a 1 MiB decoded-response limit. Narrow the upstream query, paginate, or
117
+ reduce the requested dataset before raising it; a `response` mapping runs only after the raw body is
118
+ buffered. When representative evidence proves one operation legitimately needs more, grant only that
119
+ operation the required bytes, up to the 3 MiB authoring maximum:
120
+
121
+ ```ts
122
+ search: {
123
+ type: 'read', method: 'GET', path: '/search',
124
+ limits: { maxResponseBytes: 3 * 1024 * 1024 },
125
+ // input / output / response omitted
126
+ },
127
+ ```
128
+
129
+ The inclusive limit counts decoded streamed bytes. `response_too_large` is a safe structured reason;
130
+ never copy a response body, header, URL, credential, or upstream error prose into user-visible output.
131
+
114
132
  ### Create, update, delete
115
133
 
116
134
  Pair the read/list with the mutations your intent tools need: