@noodleseed/agent-kit 0.83.0 → 0.84.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 (44) hide show
  1. package/manifest.json +271 -271
  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/creating-product-agent-guides/SKILL.md +1 -1
  8. package/skills/claude-code/debugging-mcp-delivery/SKILL.md +1 -1
  9. package/skills/claude-code/deploying-mcp-services/SKILL.md +1 -1
  10. package/skills/claude-code/designing-mcp-products/SKILL.md +1 -1
  11. package/skills/claude-code/embedding-mcp-assistants/SKILL.md +1 -1
  12. package/skills/claude-code/examples/food-ordering/README.md +1 -0
  13. package/skills/claude-code/examples/food-ordering/src/server.ts +12 -0
  14. package/skills/claude-code/examples/food-ordering/test/server.test.ts +7 -0
  15. package/skills/claude-code/executing-noodle-plans/SKILL.md +1 -1
  16. package/skills/claude-code/publishing-mcp-integrations/SKILL.md +1 -1
  17. package/skills/claude-code/references/authoring-workflow.md +10 -1
  18. package/skills/claude-code/references/connect-an-api.md +31 -1
  19. package/skills/claude-code/references/sdk-surface.md +3 -2
  20. package/skills/claude-code/references/widgets-and-apps.md +1 -1
  21. package/skills/claude-code/reporting-noodle-feedback/SKILL.md +1 -1
  22. package/skills/claude-code/verifying-mcp-delivery/SKILL.md +1 -1
  23. package/skills/claude-code/wrapping-existing-applications/SKILL.md +1 -1
  24. package/skills/codex/SKILL.md +1 -1
  25. package/skills/codex/authoring-mcp-servers/SKILL.md +1 -1
  26. package/skills/codex/building-mcp-apps/SKILL.md +1 -1
  27. package/skills/codex/connecting-apis-to-mcp/SKILL.md +1 -1
  28. package/skills/codex/creating-product-agent-guides/SKILL.md +1 -1
  29. package/skills/codex/debugging-mcp-delivery/SKILL.md +1 -1
  30. package/skills/codex/deploying-mcp-services/SKILL.md +1 -1
  31. package/skills/codex/designing-mcp-products/SKILL.md +1 -1
  32. package/skills/codex/embedding-mcp-assistants/SKILL.md +1 -1
  33. package/skills/codex/examples/food-ordering/README.md +1 -0
  34. package/skills/codex/examples/food-ordering/src/server.ts +12 -0
  35. package/skills/codex/examples/food-ordering/test/server.test.ts +7 -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/authoring-workflow.md +10 -1
  39. package/skills/codex/references/connect-an-api.md +31 -1
  40. package/skills/codex/references/sdk-surface.md +3 -2
  41. package/skills/codex/references/widgets-and-apps.md +1 -1
  42. package/skills/codex/reporting-noodle-feedback/SKILL.md +1 -1
  43. package/skills/codex/verifying-mcp-delivery/SKILL.md +1 -1
  44. 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.83.0",
3
+ "version": "0.84.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.83.0 hash:13ddce01769caae4 -->
6
+ <!-- noodle-skill version:0.84.0 hash:13ddce01769caae4 -->
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.83.0 hash:11523cb33b9473c0 -->
6
+ <!-- noodle-skill version:0.84.0 hash:11523cb33b9473c0 -->
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.83.0 hash:9fd67d4d24328e15 -->
6
+ <!-- noodle-skill version:0.84.0 hash:9fd67d4d24328e15 -->
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.83.0 hash:21bbd3ec441ffd30 -->
6
+ <!-- noodle-skill version:0.84.0 hash:21bbd3ec441ffd30 -->
7
7
 
8
8
  # connecting-apis-to-mcp
9
9
 
@@ -3,7 +3,7 @@ name: creating-product-agent-guides
3
3
  description: "Use when a Noodle Seed MCP server needs a new or revised product agent guide, App Package skill, or explicit product-skill regeneration."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.83.0 hash:0fa48a82fe836cf0 -->
6
+ <!-- noodle-skill version:0.84.0 hash:0fa48a82fe836cf0 -->
7
7
 
8
8
  # creating-product-agent-guides
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.83.0 hash:aa715bae12041d7c -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:93e735b7ffb45df1 -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:78a6f181b61f92f1 -->
6
+ <!-- noodle-skill version:0.84.0 hash:78a6f181b61f92f1 -->
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.83.0 hash:cc54a67f21c0ecdb -->
6
+ <!-- noodle-skill version:0.84.0 hash:cc54a67f21c0ecdb -->
7
7
 
8
8
  # embedding-mcp-assistants
9
9
 
@@ -26,6 +26,7 @@ private customer data.
26
26
  | Handoff | `handoff.allowedDomains` allows only `https://orders.example.com` checkout URLs |
27
27
  | Progressive enhancement | Non-Apps hosts still receive stores, featured items, and a readable fallback summary |
28
28
  | Fail-closed hydration | The React view treats only the unhydrated, pre-result `{}` envelope as pending; a hydrated empty success remains distinct. It surfaces `isError`, validates required records and identifiers, and withholds ordering actions from malformed results |
29
+ | Upstream MCP composition | This synthetic example keeps its data local. For the canonical frozen-tool import, governed upstream invocation, response normalization, and Noodle-owned widget pattern, use the repository's `shopify-storefront` flagship rather than copying another composition surface here |
29
30
 
30
31
  The example is intentionally richer than the generated starter, but each inline view still follows the
31
32
  same default: one immediate purpose, one primary action, at most one subordinate action, and progressive
@@ -352,6 +352,18 @@ export default server(
352
352
  description:
353
353
  'Open a complete food-ordering widget with store discovery, menu browsing, cart review, and checkout handoff.',
354
354
  annotations: readOnly,
355
+ modelVisibility: {
356
+ latestMessageIncludesAny: [
357
+ 'order',
358
+ 'food',
359
+ 'menu',
360
+ 'restaurant',
361
+ 'cart',
362
+ 'pickup',
363
+ 'delivery',
364
+ 'checkout',
365
+ ],
366
+ },
355
367
  input: z.object({
356
368
  query: z.string().optional(),
357
369
  customer: z.string().default('Guest'),
@@ -80,6 +80,13 @@ describe('food-ordering example', () => {
80
80
  expect(JSON.stringify(tools.get('open_ordering'))).toContain('${context.ambient.serviceArea}');
81
81
  expect(JSON.stringify(tools.get('open_ordering'))).toContain('${context.location.latitude}');
82
82
  expect(JSON.stringify(tools.get('open_ordering'))).toContain('${context.location.longitude}');
83
+ expect(tools.get('open_ordering')?.annotations).toMatchObject({
84
+ 'x-noodleseed-model-latest-message-includes-any': expect.arrayContaining([
85
+ 'order',
86
+ 'menu',
87
+ 'checkout',
88
+ ]),
89
+ });
83
90
  expect(JSON.stringify(tools.get('sync_cart'))).toContain('revision');
84
91
  expect(tools.get('sync_cart')?.annotations?.confirm).toBe(false);
85
92
  expect(tools.get('prepare_checkout')?.annotations?.confirm).toBe(false);
@@ -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.83.0 hash:6a9f132ddb79352e -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:efffbf82007f935d -->
6
+ <!-- noodle-skill version:0.84.0 hash:efffbf82007f935d -->
7
7
 
8
8
  # publishing-mcp-integrations
9
9
 
@@ -23,7 +23,8 @@
23
23
 
24
24
  1. **Website scrape** — if the user gives a URL, scrape it for surface hints (products, services, hours, contact, pricing). Stop there: the URL does not reveal CRM, booking systems, custom APIs, auth model, eligibility rules, quoting logic, or approval flows. Those live in the business systems and the owner’s head — ask.
25
25
  2. **OpenAPI import** — `noodle import openapi <file>` emits a starter `server.ts` from a spec. Use it when the user provides an OpenAPI document.
26
- 3. **User interview** — Noodle does not interview; you do. Cover custom APIs/integrations, eligibility rules, quoting/approval logic, and private schemas (SQL DDL or JSON samples for custom `connector` declarations). Ask for concrete examples and sample payloads; do not guess a schema from a URL or invent endpoints.
26
+ 3. **Upstream MCP import** — `noodle import mcp <url> --name <slug> --output <dir>` discovers `tools/list` once, validates and freezes tool schemas into TypeScript, and writes a secret-free drift snapshot. Upstream annotations are untrusted, so generated tools remain destructive confirmed actions until an author verifies and narrows them. Use `--header-env <header>=<ENV_NAME>` for import-only auth and `--check` for classified, non-mutating drift detection. Runtime never performs discovery.
27
+ 4. **User interview** — Noodle does not interview; you do. Cover custom APIs/integrations, eligibility rules, quoting/approval logic, and private schemas (SQL DDL or JSON samples for custom `connector` declarations). Ask for concrete examples and sample payloads; do not guess a schema from a URL or invent endpoints.
27
28
 
28
29
  ## Fit check
29
30
 
@@ -42,10 +43,18 @@ Author in `server.ts`, then `noodle validate` → fix cited errors (see `compile
42
43
  Declare connectors as data, not imperative code:
43
44
 
44
45
  - **HTTP**: `connector("id").version("1.0.0").http({ baseUrl, allowedOrigins, auth, operations })` with per-operation `request`/`response` mapping using `${args...}` / `${response...}` expressions.
46
+ - **MCP**: `connector("id").version("1.0.0").mcp({ endpoint, allowedOrigins, auth?, operations })` where each operation freezes the separate upstream `tool` wire name plus input/output schema. Import with `noodle import mcp`; do not hand-copy a live surface or call `tools/list` at runtime.
45
47
  - **Compute**: `connector("id").version("1.0.0").compute(name, { input, output, calls?, run })` — a self-contained, sandboxed function (no imports/closure capture) that may call allowlisted operations via `callOperation`.
46
48
 
47
49
  Tools record connector calls into a flow; recording is not execution. Do not branch on runtime outputs with native `if` — use declarative `when(...)` conditions.
48
50
 
51
+ MCP connectors are curated backing operations, never transparent proxies. Publish ordinary Noodle tools
52
+ with stable intent-shaped names, descriptions, annotations, authored schemas, confirmation, visibility,
53
+ and optional React `view`. Normalize a text-only upstream result through compute before rendering when the
54
+ view needs a richer stable output. Upstream resources, prompts, `_meta`, annotations, widgets, and CSP are
55
+ not imported or forwarded. The runtime opens one guarded session for one operation, uses only a broker-minted
56
+ credential, and closes it; it does not act as an agent for upstream sampling, roots, or elicitation.
57
+
49
58
  HTTP connector auth variants: `bearer` (`{ kind: "bearer", secret: secret("API_TOKEN") }`), `apiKey` (`{ kind: "apiKey", header: "X-API-Key", secret: secret("API_KEY") }`), `clientCredentials`, `delegatedOAuth`, `delegatedSessionCookie`, and `delegatedTokenExchange` (per-user calls to your own API — see "Delegated downstream auth" below). Use managed `secret(...)` / `variable(...)` refs for all values that differ by org/app/env.
50
59
 
51
60
  When one connector needs independently selectable accounts, declare catalog `credentialProfiles` plus each operation’s accepted `credentials.profiles`, then bind each `server.use` alias with `bind(connector, { profile, connection: connection("logical_id", managedSecret(secret("NAME"), { scopes, audience })) })`. The alias is the stable account boundary; never put provider account ids, labels, or credential values in it. `gmailConnector()` is the curated Gmail catalog helper; reuse it under independent aliases and accept canonical `accounts` arrays in tools (one account for writes, or an explicitly ordered supported combination for reads). See the bundled `gmail-multi-account` flagship. Bound managed secrets are supported by hosted execution. For deployed-server access to Google APIs, use `googleWorkloadIdentity({ provider: variable("GOOGLE_WIF_PROVIDER"), access: { kind: "direct" } })`, or add `serviceAccountImpersonation` with a managed service-account email. This is keyless Google Workload Identity Federation: exact Google scopes/audience come from the catalog operation, while `noodle auth google prepare|status|doctor|revoke` owns operator lifecycle. See the bundled `google-bigquery` flagship. `externalExchange()` is runnable only when the deployment operator injects an exact HTTPS provider endpoint/origin/audience and durable shared subject-pin store through service ports; Noodle sends a short-lived platform-signed deployment workload assertion and accepts only a bounded bearer response. Provider implementations must consume assertion replay ids through durable shared atomic storage across instances and restarts. There is intentionally no hosted enrollment or provider CRUD surface yet. The provider wire contract is public, but its conformance kit is workspace/source-only and is not an installable npm package. Bound `clientCredentials(...)` remains fail-closed until its provider slice lands.
@@ -11,6 +11,7 @@ Connect a real API to a focused MCP product using managed credentials, mappings
11
11
  - Secure the key first
12
12
  - Probe the live API
13
13
  - Model the connector from the observed shape
14
+ - Import and curate an upstream MCP server
14
15
  - Return a list
15
16
  - Create, update, delete
16
17
  - Design intent tools
@@ -22,7 +23,7 @@ Connect a real API to a focused MCP product using managed credentials, mappings
22
23
 
23
24
  ## Use when
24
25
 
25
- - The user provides credentials, a reachable API, or an OpenAPI document and wants real MCP behavior backed by it.
26
+ - The user provides credentials, a reachable API, an OpenAPI document, or an upstream MCP endpoint and wants real MCP behavior backed by it.
26
27
  - Existing connector behavior compiles but still needs proof against the actual service and data shape.
27
28
 
28
29
  ## Do not use when
@@ -80,6 +81,35 @@ Encode the API as an HTTP connector, mapping only the fields you actually saw in
80
81
  The full connector shape, every `auth.kind`, and compute connectors are in
81
82
  `references/authoring-workflow.md`.
82
83
 
84
+ ### Import and curate an upstream MCP server
85
+
86
+ Use an explicit import to discover the upstream tool surface once and generate TypeScript:
87
+
88
+ ```sh
89
+ noodle import mcp https://store.example/api/mcp --name store --output store-app
90
+ # When import discovery needs a credential, read it only from the environment:
91
+ noodle import mcp https://store.example/api/mcp --name store \
92
+ --header-env Authorization=STORE_MCP_TOKEN
93
+ ```
94
+
95
+ The importer freezes upstream tool names and normalized schemas into `.mcp({ operations })`; it never
96
+ persists the import credential. Runtime calls only those declared operations and never runs `tools/list`.
97
+ MCP annotations are untrusted hints, so every generated tool starts as a destructive confirmed action.
98
+ Verify real behavior and deliberately narrow proven reads before accepting the generated source. Use
99
+ `noodle import mcp <url> --output <dir> --check` in CI to detect upstream additions, removals, or schema
100
+ changes without mutating source; its review labels drift additive, breaking, or metadata-only.
101
+
102
+ Treat the imported connector operation as a backing-system contract, not the public tool design. Publish
103
+ ordinary intent-shaped `tool(...)` capabilities with stable names and narrower schemas, normalize text or
104
+ large upstream output through compute, and attach a normal Noodle React `view` when UI helps. Upstream
105
+ `_meta`, resources, prompts, annotations, widgets, and CSP are never forwarded. A Noodle-owned widget may
106
+ therefore enrich a headless upstream tool without trusting upstream executable UI.
107
+
108
+ Managed endpoints require an exact managed origin allowlist. Configure each deployment with
109
+ `variable(...)` and `secret(...)`; inbound MCP/OAuth bearer tokens are never reusable upstream credentials.
110
+ The first release supports no auth, bearer, API key, and client credentials through the broker. Do not
111
+ invent a delegated-user OAuth shortcut for an upstream MCP server.
112
+
83
113
  ### Return a list
84
114
 
85
115
  Most real tools return a variable-length list (search results, a user’s tasks). Bind the **whole array** — a single `${response.path}` returns the referenced value verbatim, arrays included:
@@ -74,7 +74,7 @@ Platform helper connectors are explicit subpath imports from `@noodleseed/one/pl
74
74
  ## Authoring signatures
75
75
 
76
76
  - `server(name, options, definitions)` — `options` commonly includes `title`, `version`, `instructions`, `agentGuide`, `distribution`, `branding`, `auth`, `use`, `provides`, `state`, and `handoff`; `definitions` is the array of tools/resources/prompts.
77
- - `tool(name, { description, input, output, annotations?, visibility?, view?, fulfil })` — `input`/`output` are Zod schemas; `fulfil({ input, connectors, user })` returns data matching `output`. Add `view: { component, entry }` for a React widget; use `visibility: ["app"]` for an app-only helper.
77
+ - `tool(name, { description, input, output, annotations?, visibility?, modelVisibility?, view?, fulfil })` — `input`/`output` are Zod schemas; `fulfil({ input, connectors, user })` returns data matching `output`. Add `view: { component, entry }` for a React widget; use `visibility: ["app"]` for an app-only helper. Use `modelVisibility.latestMessageIncludesAny` only for normalized literal explicit-intent discovery; it does not authorize execution.
78
78
  - Keep tool input names application-owned and meaningful; `__noodleIntent` is reserved for an optional serve-time operator analytics adapter and never reaches `fulfil`.
79
79
  - `resource(name, { uri, description?, mimeType?, fulfil })` and `prompt(name, { description?, arguments?, fulfil })` expose MCP resources/prompts.
80
80
  - View metadata (`viewTitle`, `viewDescription`, `csp`, `domain`, `permissions`) belongs on the tool that renders it; `asset("./path")` packages local files.
@@ -146,7 +146,7 @@ prompt('summarize_ticket', {
146
146
 
147
147
  ### Non-trivial tool: ctx connectors, annotations, visibility, async
148
148
 
149
- `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. For stateless hosts that cannot present Noodle confirmation, set `interactions: { confirmationFallback: 'host' }` in the `server` options to explicitly trust native host write approval; omission remains fail-closed and the fallback never supplies missing `ctx.elicit` input. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. `fulfil` may be `async` (the compiler awaits it while recording).
149
+ `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. For stateless hosts that cannot present Noodle confirmation, set `interactions: { confirmationFallback: 'host' }` in the `server` options to explicitly trust native host write approval; omission remains fail-closed and the fallback never supplies missing `ctx.elicit` input. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. For a narrow explicit-intent tool, `modelVisibility: { latestMessageIncludesAny: [...] }` deterministically limits model discovery to a latest user message containing one of the normalized literal phrases; it is not authorization. `fulfil` may be `async` (the compiler awaits it while recording).
150
150
 
151
151
  ```ts
152
152
  import { annotations, connector, server, tool, z } from '@noodleseed/one';
@@ -177,6 +177,7 @@ export default server('support', { title: 'Support', version: '1.0.0', use: { cr
177
177
  output: z.object({ subject: z.string(), status: z.string() }),
178
178
  annotations: annotations.readOnly(), // read-only hint for hosts
179
179
  visibility: ['model', 'app'], // default; use ['app'] to hide the tool from the model
180
+ modelVisibility: { latestMessageIncludesAny: ['show ticket', 'open ticket'] },
180
181
  // ctx is { input, user, connectors }. A connector call records one flow step (a Ref) —
181
182
  // recording is not execution, so never branch on the result with native if (use when).
182
183
  fulfil: ({ input, connectors }) => {
@@ -12,7 +12,7 @@
12
12
 
13
13
  ## Tools and views
14
14
 
15
- Use `tool(name, { description, input, output, fulfil, view })` for a model-visible tool that renders a widget, and the same `tool(name, { ..., visibility: ["app"] })` for an app-only helper hidden from the model. A `view` is `{ component: "name", entry: "./views/name.tsx" }` — a React component the compiler bundles at validate/deploy time.
15
+ Use `tool(name, { description, input, output, fulfil, view })` for a model-visible tool that renders a widget, and the same `tool(name, { ..., visibility: ["app"] })` for an app-only helper hidden from the model. When a view is valid only for narrow explicit intent, add `modelVisibility: { latestMessageIncludesAny: ["open the form", ...] }`; Noodle normalizes and matches those literal phrases against the latest user message before model discovery and fails closed on malformed data. This is relevance filtering, never authorization. A `view` is `{ component: "name", entry: "./views/name.tsx" }` — a React component the compiler bundles at validate/deploy time.
16
16
 
17
17
  ## Noodle Design default
18
18
 
@@ -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.83.0 hash:0f404109f4845683 -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:6ef6ef551e26b78e -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:eccc3c158dcafba8 -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:13ddce01769caae4 -->
6
+ <!-- noodle-skill version:0.84.0 hash:13ddce01769caae4 -->
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.83.0 hash:11523cb33b9473c0 -->
6
+ <!-- noodle-skill version:0.84.0 hash:11523cb33b9473c0 -->
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.83.0 hash:9fd67d4d24328e15 -->
6
+ <!-- noodle-skill version:0.84.0 hash:9fd67d4d24328e15 -->
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.83.0 hash:21bbd3ec441ffd30 -->
6
+ <!-- noodle-skill version:0.84.0 hash:21bbd3ec441ffd30 -->
7
7
 
8
8
  # connecting-apis-to-mcp
9
9
 
@@ -3,7 +3,7 @@ name: creating-product-agent-guides
3
3
  description: "Use when a Noodle Seed MCP server needs a new or revised product agent guide, App Package skill, or explicit product-skill regeneration."
4
4
  ---
5
5
 
6
- <!-- noodle-skill version:0.83.0 hash:0fa48a82fe836cf0 -->
6
+ <!-- noodle-skill version:0.84.0 hash:0fa48a82fe836cf0 -->
7
7
 
8
8
  # creating-product-agent-guides
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.83.0 hash:aa715bae12041d7c -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:93e735b7ffb45df1 -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:78a6f181b61f92f1 -->
6
+ <!-- noodle-skill version:0.84.0 hash:78a6f181b61f92f1 -->
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.83.0 hash:cc54a67f21c0ecdb -->
6
+ <!-- noodle-skill version:0.84.0 hash:cc54a67f21c0ecdb -->
7
7
 
8
8
  # embedding-mcp-assistants
9
9
 
@@ -26,6 +26,7 @@ private customer data.
26
26
  | Handoff | `handoff.allowedDomains` allows only `https://orders.example.com` checkout URLs |
27
27
  | Progressive enhancement | Non-Apps hosts still receive stores, featured items, and a readable fallback summary |
28
28
  | Fail-closed hydration | The React view treats only the unhydrated, pre-result `{}` envelope as pending; a hydrated empty success remains distinct. It surfaces `isError`, validates required records and identifiers, and withholds ordering actions from malformed results |
29
+ | Upstream MCP composition | This synthetic example keeps its data local. For the canonical frozen-tool import, governed upstream invocation, response normalization, and Noodle-owned widget pattern, use the repository's `shopify-storefront` flagship rather than copying another composition surface here |
29
30
 
30
31
  The example is intentionally richer than the generated starter, but each inline view still follows the
31
32
  same default: one immediate purpose, one primary action, at most one subordinate action, and progressive
@@ -352,6 +352,18 @@ export default server(
352
352
  description:
353
353
  'Open a complete food-ordering widget with store discovery, menu browsing, cart review, and checkout handoff.',
354
354
  annotations: readOnly,
355
+ modelVisibility: {
356
+ latestMessageIncludesAny: [
357
+ 'order',
358
+ 'food',
359
+ 'menu',
360
+ 'restaurant',
361
+ 'cart',
362
+ 'pickup',
363
+ 'delivery',
364
+ 'checkout',
365
+ ],
366
+ },
355
367
  input: z.object({
356
368
  query: z.string().optional(),
357
369
  customer: z.string().default('Guest'),
@@ -80,6 +80,13 @@ describe('food-ordering example', () => {
80
80
  expect(JSON.stringify(tools.get('open_ordering'))).toContain('${context.ambient.serviceArea}');
81
81
  expect(JSON.stringify(tools.get('open_ordering'))).toContain('${context.location.latitude}');
82
82
  expect(JSON.stringify(tools.get('open_ordering'))).toContain('${context.location.longitude}');
83
+ expect(tools.get('open_ordering')?.annotations).toMatchObject({
84
+ 'x-noodleseed-model-latest-message-includes-any': expect.arrayContaining([
85
+ 'order',
86
+ 'menu',
87
+ 'checkout',
88
+ ]),
89
+ });
83
90
  expect(JSON.stringify(tools.get('sync_cart'))).toContain('revision');
84
91
  expect(tools.get('sync_cart')?.annotations?.confirm).toBe(false);
85
92
  expect(tools.get('prepare_checkout')?.annotations?.confirm).toBe(false);
@@ -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.83.0 hash:6a9f132ddb79352e -->
6
+ <!-- noodle-skill version:0.84.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.83.0 hash:efffbf82007f935d -->
6
+ <!-- noodle-skill version:0.84.0 hash:efffbf82007f935d -->
7
7
 
8
8
  # publishing-mcp-integrations
9
9
 
@@ -23,7 +23,8 @@
23
23
 
24
24
  1. **Website scrape** — if the user gives a URL, scrape it for surface hints (products, services, hours, contact, pricing). Stop there: the URL does not reveal CRM, booking systems, custom APIs, auth model, eligibility rules, quoting logic, or approval flows. Those live in the business systems and the owner’s head — ask.
25
25
  2. **OpenAPI import** — `noodle import openapi <file>` emits a starter `server.ts` from a spec. Use it when the user provides an OpenAPI document.
26
- 3. **User interview** — Noodle does not interview; you do. Cover custom APIs/integrations, eligibility rules, quoting/approval logic, and private schemas (SQL DDL or JSON samples for custom `connector` declarations). Ask for concrete examples and sample payloads; do not guess a schema from a URL or invent endpoints.
26
+ 3. **Upstream MCP import** — `noodle import mcp <url> --name <slug> --output <dir>` discovers `tools/list` once, validates and freezes tool schemas into TypeScript, and writes a secret-free drift snapshot. Upstream annotations are untrusted, so generated tools remain destructive confirmed actions until an author verifies and narrows them. Use `--header-env <header>=<ENV_NAME>` for import-only auth and `--check` for classified, non-mutating drift detection. Runtime never performs discovery.
27
+ 4. **User interview** — Noodle does not interview; you do. Cover custom APIs/integrations, eligibility rules, quoting/approval logic, and private schemas (SQL DDL or JSON samples for custom `connector` declarations). Ask for concrete examples and sample payloads; do not guess a schema from a URL or invent endpoints.
27
28
 
28
29
  ## Fit check
29
30
 
@@ -42,10 +43,18 @@ Author in `server.ts`, then `noodle validate` → fix cited errors (see `compile
42
43
  Declare connectors as data, not imperative code:
43
44
 
44
45
  - **HTTP**: `connector("id").version("1.0.0").http({ baseUrl, allowedOrigins, auth, operations })` with per-operation `request`/`response` mapping using `${args...}` / `${response...}` expressions.
46
+ - **MCP**: `connector("id").version("1.0.0").mcp({ endpoint, allowedOrigins, auth?, operations })` where each operation freezes the separate upstream `tool` wire name plus input/output schema. Import with `noodle import mcp`; do not hand-copy a live surface or call `tools/list` at runtime.
45
47
  - **Compute**: `connector("id").version("1.0.0").compute(name, { input, output, calls?, run })` — a self-contained, sandboxed function (no imports/closure capture) that may call allowlisted operations via `callOperation`.
46
48
 
47
49
  Tools record connector calls into a flow; recording is not execution. Do not branch on runtime outputs with native `if` — use declarative `when(...)` conditions.
48
50
 
51
+ MCP connectors are curated backing operations, never transparent proxies. Publish ordinary Noodle tools
52
+ with stable intent-shaped names, descriptions, annotations, authored schemas, confirmation, visibility,
53
+ and optional React `view`. Normalize a text-only upstream result through compute before rendering when the
54
+ view needs a richer stable output. Upstream resources, prompts, `_meta`, annotations, widgets, and CSP are
55
+ not imported or forwarded. The runtime opens one guarded session for one operation, uses only a broker-minted
56
+ credential, and closes it; it does not act as an agent for upstream sampling, roots, or elicitation.
57
+
49
58
  HTTP connector auth variants: `bearer` (`{ kind: "bearer", secret: secret("API_TOKEN") }`), `apiKey` (`{ kind: "apiKey", header: "X-API-Key", secret: secret("API_KEY") }`), `clientCredentials`, `delegatedOAuth`, `delegatedSessionCookie`, and `delegatedTokenExchange` (per-user calls to your own API — see "Delegated downstream auth" below). Use managed `secret(...)` / `variable(...)` refs for all values that differ by org/app/env.
50
59
 
51
60
  When one connector needs independently selectable accounts, declare catalog `credentialProfiles` plus each operation’s accepted `credentials.profiles`, then bind each `server.use` alias with `bind(connector, { profile, connection: connection("logical_id", managedSecret(secret("NAME"), { scopes, audience })) })`. The alias is the stable account boundary; never put provider account ids, labels, or credential values in it. `gmailConnector()` is the curated Gmail catalog helper; reuse it under independent aliases and accept canonical `accounts` arrays in tools (one account for writes, or an explicitly ordered supported combination for reads). See the bundled `gmail-multi-account` flagship. Bound managed secrets are supported by hosted execution. For deployed-server access to Google APIs, use `googleWorkloadIdentity({ provider: variable("GOOGLE_WIF_PROVIDER"), access: { kind: "direct" } })`, or add `serviceAccountImpersonation` with a managed service-account email. This is keyless Google Workload Identity Federation: exact Google scopes/audience come from the catalog operation, while `noodle auth google prepare|status|doctor|revoke` owns operator lifecycle. See the bundled `google-bigquery` flagship. `externalExchange()` is runnable only when the deployment operator injects an exact HTTPS provider endpoint/origin/audience and durable shared subject-pin store through service ports; Noodle sends a short-lived platform-signed deployment workload assertion and accepts only a bounded bearer response. Provider implementations must consume assertion replay ids through durable shared atomic storage across instances and restarts. There is intentionally no hosted enrollment or provider CRUD surface yet. The provider wire contract is public, but its conformance kit is workspace/source-only and is not an installable npm package. Bound `clientCredentials(...)` remains fail-closed until its provider slice lands.
@@ -11,6 +11,7 @@ Connect a real API to a focused MCP product using managed credentials, mappings
11
11
  - Secure the key first
12
12
  - Probe the live API
13
13
  - Model the connector from the observed shape
14
+ - Import and curate an upstream MCP server
14
15
  - Return a list
15
16
  - Create, update, delete
16
17
  - Design intent tools
@@ -22,7 +23,7 @@ Connect a real API to a focused MCP product using managed credentials, mappings
22
23
 
23
24
  ## Use when
24
25
 
25
- - The user provides credentials, a reachable API, or an OpenAPI document and wants real MCP behavior backed by it.
26
+ - The user provides credentials, a reachable API, an OpenAPI document, or an upstream MCP endpoint and wants real MCP behavior backed by it.
26
27
  - Existing connector behavior compiles but still needs proof against the actual service and data shape.
27
28
 
28
29
  ## Do not use when
@@ -80,6 +81,35 @@ Encode the API as an HTTP connector, mapping only the fields you actually saw in
80
81
  The full connector shape, every `auth.kind`, and compute connectors are in
81
82
  `references/authoring-workflow.md`.
82
83
 
84
+ ### Import and curate an upstream MCP server
85
+
86
+ Use an explicit import to discover the upstream tool surface once and generate TypeScript:
87
+
88
+ ```sh
89
+ noodle import mcp https://store.example/api/mcp --name store --output store-app
90
+ # When import discovery needs a credential, read it only from the environment:
91
+ noodle import mcp https://store.example/api/mcp --name store \
92
+ --header-env Authorization=STORE_MCP_TOKEN
93
+ ```
94
+
95
+ The importer freezes upstream tool names and normalized schemas into `.mcp({ operations })`; it never
96
+ persists the import credential. Runtime calls only those declared operations and never runs `tools/list`.
97
+ MCP annotations are untrusted hints, so every generated tool starts as a destructive confirmed action.
98
+ Verify real behavior and deliberately narrow proven reads before accepting the generated source. Use
99
+ `noodle import mcp <url> --output <dir> --check` in CI to detect upstream additions, removals, or schema
100
+ changes without mutating source; its review labels drift additive, breaking, or metadata-only.
101
+
102
+ Treat the imported connector operation as a backing-system contract, not the public tool design. Publish
103
+ ordinary intent-shaped `tool(...)` capabilities with stable names and narrower schemas, normalize text or
104
+ large upstream output through compute, and attach a normal Noodle React `view` when UI helps. Upstream
105
+ `_meta`, resources, prompts, annotations, widgets, and CSP are never forwarded. A Noodle-owned widget may
106
+ therefore enrich a headless upstream tool without trusting upstream executable UI.
107
+
108
+ Managed endpoints require an exact managed origin allowlist. Configure each deployment with
109
+ `variable(...)` and `secret(...)`; inbound MCP/OAuth bearer tokens are never reusable upstream credentials.
110
+ The first release supports no auth, bearer, API key, and client credentials through the broker. Do not
111
+ invent a delegated-user OAuth shortcut for an upstream MCP server.
112
+
83
113
  ### Return a list
84
114
 
85
115
  Most real tools return a variable-length list (search results, a user’s tasks). Bind the **whole array** — a single `${response.path}` returns the referenced value verbatim, arrays included:
@@ -74,7 +74,7 @@ Platform helper connectors are explicit subpath imports from `@noodleseed/one/pl
74
74
  ## Authoring signatures
75
75
 
76
76
  - `server(name, options, definitions)` — `options` commonly includes `title`, `version`, `instructions`, `agentGuide`, `distribution`, `branding`, `auth`, `use`, `provides`, `state`, and `handoff`; `definitions` is the array of tools/resources/prompts.
77
- - `tool(name, { description, input, output, annotations?, visibility?, view?, fulfil })` — `input`/`output` are Zod schemas; `fulfil({ input, connectors, user })` returns data matching `output`. Add `view: { component, entry }` for a React widget; use `visibility: ["app"]` for an app-only helper.
77
+ - `tool(name, { description, input, output, annotations?, visibility?, modelVisibility?, view?, fulfil })` — `input`/`output` are Zod schemas; `fulfil({ input, connectors, user })` returns data matching `output`. Add `view: { component, entry }` for a React widget; use `visibility: ["app"]` for an app-only helper. Use `modelVisibility.latestMessageIncludesAny` only for normalized literal explicit-intent discovery; it does not authorize execution.
78
78
  - Keep tool input names application-owned and meaningful; `__noodleIntent` is reserved for an optional serve-time operator analytics adapter and never reaches `fulfil`.
79
79
  - `resource(name, { uri, description?, mimeType?, fulfil })` and `prompt(name, { description?, arguments?, fulfil })` expose MCP resources/prompts.
80
80
  - View metadata (`viewTitle`, `viewDescription`, `csp`, `domain`, `permissions`) belongs on the tool that renders it; `asset("./path")` packages local files.
@@ -146,7 +146,7 @@ prompt('summarize_ticket', {
146
146
 
147
147
  ### Non-trivial tool: ctx connectors, annotations, visibility, async
148
148
 
149
- `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. For stateless hosts that cannot present Noodle confirmation, set `interactions: { confirmationFallback: 'host' }` in the `server` options to explicitly trust native host write approval; omission remains fail-closed and the fallback never supplies missing `ctx.elicit` input. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. `fulfil` may be `async` (the compiler awaits it while recording).
149
+ `ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` declares a closed-world safe read. TypeScript action helpers enforce confirmation only with `{ confirm: true }`; omitted or `false` executes directly, and action/destructive/open-world hints alone never enable the gate. For stateless hosts that cannot present Noodle confirmation, set `interactions: { confirmationFallback: 'host' }` in the `server` options to explicitly trust native host write approval; omission remains fail-closed and the fallback never supplies missing `ctx.elicit` input. `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. For a narrow explicit-intent tool, `modelVisibility: { latestMessageIncludesAny: [...] }` deterministically limits model discovery to a latest user message containing one of the normalized literal phrases; it is not authorization. `fulfil` may be `async` (the compiler awaits it while recording).
150
150
 
151
151
  ```ts
152
152
  import { annotations, connector, server, tool, z } from '@noodleseed/one';
@@ -177,6 +177,7 @@ export default server('support', { title: 'Support', version: '1.0.0', use: { cr
177
177
  output: z.object({ subject: z.string(), status: z.string() }),
178
178
  annotations: annotations.readOnly(), // read-only hint for hosts
179
179
  visibility: ['model', 'app'], // default; use ['app'] to hide the tool from the model
180
+ modelVisibility: { latestMessageIncludesAny: ['show ticket', 'open ticket'] },
180
181
  // ctx is { input, user, connectors }. A connector call records one flow step (a Ref) —
181
182
  // recording is not execution, so never branch on the result with native if (use when).
182
183
  fulfil: ({ input, connectors }) => {