@noodleseed/agent-kit 0.101.0 → 0.103.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.
- package/manifest.json +367 -367
- package/package.json +1 -1
- package/skills/claude-code/SKILL.md +1 -1
- package/skills/claude-code/authoring-mcp-servers/SKILL.md +1 -1
- package/skills/claude-code/authoring-mcp-servers/references/authoring-workflow.md +9 -3
- package/skills/claude-code/building-mcp-apps/SKILL.md +1 -1
- package/skills/claude-code/connecting-apis-to-mcp/SKILL.md +1 -1
- package/skills/claude-code/connecting-apis-to-mcp/references/authoring-workflow.md +9 -3
- package/skills/claude-code/creating-product-agent-guides/SKILL.md +1 -1
- package/skills/claude-code/debugging-mcp-delivery/SKILL.md +1 -1
- package/skills/claude-code/deploying-mcp-services/SKILL.md +1 -1
- package/skills/claude-code/designing-mcp-products/SKILL.md +1 -1
- package/skills/claude-code/designing-mcp-products/references/authoring-workflow.md +9 -3
- package/skills/claude-code/embedding-mcp-assistants/SKILL.md +1 -1
- package/skills/claude-code/embedding-mcp-assistants/references/authoring-workflow.md +9 -3
- package/skills/claude-code/examples/acme-bistro/README.md +1 -1
- package/skills/claude-code/examples/acme-bistro/src/server.ts +7 -7
- package/skills/claude-code/examples/customer-auth/README.md +29 -41
- package/skills/claude-code/examples/customer-auth/src/server.ts +15 -4
- package/skills/claude-code/examples/customer-auth/test/server.test.ts +6 -1
- package/skills/claude-code/examples/weather/src/server.ts +3 -3
- package/skills/claude-code/executing-noodle-plans/SKILL.md +1 -1
- package/skills/claude-code/publishing-mcp-integrations/SKILL.md +1 -1
- package/skills/claude-code/references/authoring-workflow.md +9 -3
- package/skills/claude-code/references/compile-errors.md +2 -0
- package/skills/claude-code/reporting-noodle-feedback/SKILL.md +1 -1
- package/skills/claude-code/verifying-mcp-delivery/SKILL.md +1 -1
- package/skills/claude-code/wrapping-existing-applications/SKILL.md +1 -1
- package/skills/claude-code/wrapping-existing-applications/references/authoring-workflow.md +9 -3
- package/skills/codex/SKILL.md +1 -1
- package/skills/codex/authoring-mcp-servers/SKILL.md +1 -1
- package/skills/codex/authoring-mcp-servers/references/authoring-workflow.md +9 -3
- package/skills/codex/building-mcp-apps/SKILL.md +1 -1
- package/skills/codex/connecting-apis-to-mcp/SKILL.md +1 -1
- package/skills/codex/connecting-apis-to-mcp/references/authoring-workflow.md +9 -3
- package/skills/codex/creating-product-agent-guides/SKILL.md +1 -1
- package/skills/codex/debugging-mcp-delivery/SKILL.md +1 -1
- package/skills/codex/deploying-mcp-services/SKILL.md +1 -1
- package/skills/codex/designing-mcp-products/SKILL.md +1 -1
- package/skills/codex/designing-mcp-products/references/authoring-workflow.md +9 -3
- package/skills/codex/embedding-mcp-assistants/SKILL.md +1 -1
- package/skills/codex/embedding-mcp-assistants/references/authoring-workflow.md +9 -3
- package/skills/codex/examples/acme-bistro/README.md +1 -1
- package/skills/codex/examples/acme-bistro/src/server.ts +7 -7
- package/skills/codex/examples/customer-auth/README.md +29 -41
- package/skills/codex/examples/customer-auth/src/server.ts +15 -4
- package/skills/codex/examples/customer-auth/test/server.test.ts +6 -1
- package/skills/codex/examples/weather/src/server.ts +3 -3
- package/skills/codex/executing-noodle-plans/SKILL.md +1 -1
- package/skills/codex/publishing-mcp-integrations/SKILL.md +1 -1
- package/skills/codex/references/authoring-workflow.md +9 -3
- package/skills/codex/references/compile-errors.md +2 -0
- package/skills/codex/reporting-noodle-feedback/SKILL.md +1 -1
- package/skills/codex/verifying-mcp-delivery/SKILL.md +1 -1
- package/skills/codex/wrapping-existing-applications/SKILL.md +1 -1
- package/skills/codex/wrapping-existing-applications/references/authoring-workflow.md +9 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/agent-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.103.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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:d3ceb1902ef4bb72 -->
|
|
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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:dd57a15df15d10b2 -->
|
|
7
7
|
|
|
8
8
|
# authoring-mcp-servers
|
|
9
9
|
|
|
@@ -47,6 +47,9 @@ Declare typed connectors:
|
|
|
47
47
|
- **HTTP**: `connector("id").version("1.0.0").http({ baseUrl, allowedOrigins, auth, operations })`; map request/response with `${args...}` / `${response...}`. Use `${execution.id}` for provider idempotency, never model input. Optional `evidence: { outcome: "${response.execution_outcome}", reference: "${response.id}" }` classifies completed/rejected/accepted/unknown; reference is a bounded opaque ID, never a bearer URL or payload. No automatic action retry.
|
|
48
48
|
- **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.
|
|
49
49
|
- **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`.
|
|
50
|
+
- **Explicit helpers**: `run: (input, host) => ...` can use `host.time.parse(iso)`, `host.time.format(epochMs)`, `host.time.parts(epochMs, timeZone)` and `host.digest(text, "hex")` (or `"base32hex"`). They convert bounded explicit data; there is no ambient clock. Pass trusted `context.temporal.instant` through fulfilment when current time is needed. `examples/weather` demonstrates a stable digest fallback for provider records without IDs.
|
|
51
|
+
- **Expected HTTP errors**: declare `responses: { "409": { response: { status: "conflict" }, evidence: { outcome: "rejected" } } }` alongside the ordinary success `response`. Explicit 4xx overrides exclude 401/403/429; validate against the same output schema. Undeclared errors still fail. Overrides never inherit successful completion evidence or introduce action retries.
|
|
52
|
+
- **Coordinated external actions**: a compute action may declare `coordination: { connectionId, namespace, key: "${args.resource}", reference: "${execution.id}" }` with a bounded execution deadline. It requires an installed application with a live bound connection and durable service coordination. Read `host.coordination.acquired` before writing; a blocked invocation may inspect `previous` through a declared read and call `host.resolveCoordination()` only after exact source proof, then require a fresh invocation/confirmation. The runtime permits at most one nested action when acquired and zero when blocked, even after recovery. Report explicit completed/rejected/unknown evidence with `host.reportOutcome(...)`; a successful return alone never unlocks uncertainty. Do not create an external-record collection for this.
|
|
50
53
|
|
|
51
54
|
Tools record connector calls into a flow; recording is not execution. Do not branch on runtime outputs with native `if` — use declarative `when(...)` conditions.
|
|
52
55
|
|
|
@@ -219,7 +222,7 @@ Every federated issuer must repeat every endpoint key used by the app, although
|
|
|
219
222
|
|
|
220
223
|
Resolved customer URLs are private routing authority: they never enter the manifest/artifact, `${user}`, logs, model output, widgets, public confirmation review, cache keys, or delegated-token-exchange assertions. Routed reads may be used by tools, including declared nested calls. A routed action—including one reached through a connector wrapper—requires exact `annotations.confirm: true`; omitted or `false` fails with `customer_endpoint_action_unsupported`. Routed resources, prompts, and ambient context fail with `customer_endpoint_surface_unsupported`.
|
|
221
224
|
|
|
222
|
-
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list`
|
|
225
|
+
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list` follows the scope/role discovery rule and its explicit public-descriptor opt-in, so route availability neither reveals tenant topology nor changes execution authorization.
|
|
223
226
|
|
|
224
227
|
## Per-tool authorization
|
|
225
228
|
|
|
@@ -241,7 +244,10 @@ tool('list_org_apps', {
|
|
|
241
244
|
})
|
|
242
245
|
```
|
|
243
246
|
|
|
244
|
-
|
|
247
|
+
Use `authorization.discovery: 'public'` on a nonempty scope/role rule to expose its MCP descriptor before sign-in. Omission and explicit 'authorized' preserve filtered discovery and compile identically. Visibility grants no execution or product-skill eligibility; scopes remain ALL and roles ANY. Noodle derives securitySchemes; never author them.
|
|
248
|
+
For mixed customer preview, keep server customerAuth and adopt on the same org/app/env, endpoint, issuer and audience; keep the separate public Help endpoint during the pilot, and never create overlapping active issuer/audience ownership. Before any mixed deploy or access change, leave only Help unrestricted, add authorization to every customer tool, and validate plus preview with `noodle dev --access mixed`. For an existing customer-only app, first run `noodle deployments list --org <org> --app <app> --env <env> --json` and inspect an inactive `customers` record for the exact server version. If none exists, record the active ID, redeploy the unchanged secured source to the same version with `--access customers`, then list and inspect again to prove that ID is now inactive; recording it alone preserves nothing. Next deploy the policy-prepared source with `--access customers`, verify the original rollback record remains inactive, and only then run `noodle access set mixed ... --version <version>`. On pilot failure use `noodle rollback <deployment-id> --org <org> --app <app> --env <env> --reason <text>`. This app-history rollback differs from the compatible hosted service-release floor. Invalid supplied credentials fail, with no platform-human fallback. Broker exchange remains required. Local Devtools retries after successful sign-in and leaves Help available after cancellation without executing the protected tool. After deployment, test anonymous discovery, sign-in, cancellation, authenticated retry and expiry in the actual host before customer cutover; local/SDK checks do not prove ChatGPT or another host.
|
|
249
|
+
|
|
250
|
+
Role values are trusted only from the explicitly configured claim path (or the platform-private bridge role claim). Direct OIDC scopes default to standard `scope`, `scp`, or `scopes` claims unless `claims.scopes` is configured. Embedded-assistant backends pass verified `user.roles` and `user.scopes` separately during `createAssistantSession(...)`; page context never grants either. Claim values must be a string or string array; malformed or oversized values fail closed. Tools retain authored order in `tools/list`; protected descriptors are omitted unless explicitly public, and an unauthorized direct call is still denied before argument validation or connector execution. Scope denials use MCP OAuth step-up metadata without disclosing role names.
|
|
245
251
|
|
|
246
252
|
## Delegated downstream auth (call your API as the signed-in user)
|
|
247
253
|
|
|
@@ -409,7 +415,7 @@ Adapt the representative arguments and assertions when business contracts change
|
|
|
409
415
|
|
|
410
416
|
Author managed config as `secret("NAME")` / `variable("NAME")` and operate it with `noodle secrets set` / `noodle variables set` (scoped org/app/env). Never inline secret values in `server.ts`, tests, or generated files.
|
|
411
417
|
|
|
412
|
-
For business-editable configuration, declare `const
|
|
418
|
+
For business-editable configuration, declare `const guestExperience = variable("GUEST_EXPERIENCE", { schema: z.object({ notice: z.string().max(500) }), default: { notice: "Welcome" }, portal: { label: "Guest experience" }, requiredFor: ["show_menu"] })` and register it in `server(..., { variables: [guestExperience], ... }, tools)`. Use the whole ref or `guestExperience.field("notice")` in ordinary fulfilment/connector arguments. `.field()` selects a schema-declared object property, can chain for nested objects, and retains the parent variable and full configuration snapshot; it never reads operator data at author time. Keep confirmed action arguments shallow enough for complete review; do not label ordinary settings sensitive to bypass the review. The default is reusable safe intent; each business supplies its own values without editing source. Only explicit `portal` metadata exposes a setting. Name-only references and declared variables without `portal` remain technical configuration; secrets remain credential slots. See the bundled `acme-bistro` source.
|
|
413
419
|
|
|
414
420
|
Business schemas must be bounded: booleans, finite bounded numbers, bounded text, string enums, bounded arrays, and closed objects. Put defaults in the declaration, not inside Zod schema defaults; custom transforms/refinements and arbitrary schema code cannot run in the shared runtime. `requiredFor` names existing tools whose invocation needs the value; unresolved settings must leave only dependent capabilities unavailable. Publisher compilation does not require a future buyer’s values. Application code enforces business rules server-side; exposing a control or placing the rule in a prompt is insufficient.
|
|
415
421
|
|
|
@@ -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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:98c7b07c82a7d7ce -->
|
|
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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:8020811f1769c538 -->
|
|
7
7
|
|
|
8
8
|
# connecting-apis-to-mcp
|
|
9
9
|
|
|
@@ -47,6 +47,9 @@ Declare typed connectors:
|
|
|
47
47
|
- **HTTP**: `connector("id").version("1.0.0").http({ baseUrl, allowedOrigins, auth, operations })`; map request/response with `${args...}` / `${response...}`. Use `${execution.id}` for provider idempotency, never model input. Optional `evidence: { outcome: "${response.execution_outcome}", reference: "${response.id}" }` classifies completed/rejected/accepted/unknown; reference is a bounded opaque ID, never a bearer URL or payload. No automatic action retry.
|
|
48
48
|
- **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.
|
|
49
49
|
- **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`.
|
|
50
|
+
- **Explicit helpers**: `run: (input, host) => ...` can use `host.time.parse(iso)`, `host.time.format(epochMs)`, `host.time.parts(epochMs, timeZone)` and `host.digest(text, "hex")` (or `"base32hex"`). They convert bounded explicit data; there is no ambient clock. Pass trusted `context.temporal.instant` through fulfilment when current time is needed. `examples/weather` demonstrates a stable digest fallback for provider records without IDs.
|
|
51
|
+
- **Expected HTTP errors**: declare `responses: { "409": { response: { status: "conflict" }, evidence: { outcome: "rejected" } } }` alongside the ordinary success `response`. Explicit 4xx overrides exclude 401/403/429; validate against the same output schema. Undeclared errors still fail. Overrides never inherit successful completion evidence or introduce action retries.
|
|
52
|
+
- **Coordinated external actions**: a compute action may declare `coordination: { connectionId, namespace, key: "${args.resource}", reference: "${execution.id}" }` with a bounded execution deadline. It requires an installed application with a live bound connection and durable service coordination. Read `host.coordination.acquired` before writing; a blocked invocation may inspect `previous` through a declared read and call `host.resolveCoordination()` only after exact source proof, then require a fresh invocation/confirmation. The runtime permits at most one nested action when acquired and zero when blocked, even after recovery. Report explicit completed/rejected/unknown evidence with `host.reportOutcome(...)`; a successful return alone never unlocks uncertainty. Do not create an external-record collection for this.
|
|
50
53
|
|
|
51
54
|
Tools record connector calls into a flow; recording is not execution. Do not branch on runtime outputs with native `if` — use declarative `when(...)` conditions.
|
|
52
55
|
|
|
@@ -219,7 +222,7 @@ Every federated issuer must repeat every endpoint key used by the app, although
|
|
|
219
222
|
|
|
220
223
|
Resolved customer URLs are private routing authority: they never enter the manifest/artifact, `${user}`, logs, model output, widgets, public confirmation review, cache keys, or delegated-token-exchange assertions. Routed reads may be used by tools, including declared nested calls. A routed action—including one reached through a connector wrapper—requires exact `annotations.confirm: true`; omitted or `false` fails with `customer_endpoint_action_unsupported`. Routed resources, prompts, and ambient context fail with `customer_endpoint_surface_unsupported`.
|
|
221
224
|
|
|
222
|
-
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list`
|
|
225
|
+
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list` follows the scope/role discovery rule and its explicit public-descriptor opt-in, so route availability neither reveals tenant topology nor changes execution authorization.
|
|
223
226
|
|
|
224
227
|
## Per-tool authorization
|
|
225
228
|
|
|
@@ -241,7 +244,10 @@ tool('list_org_apps', {
|
|
|
241
244
|
})
|
|
242
245
|
```
|
|
243
246
|
|
|
244
|
-
|
|
247
|
+
Use `authorization.discovery: 'public'` on a nonempty scope/role rule to expose its MCP descriptor before sign-in. Omission and explicit 'authorized' preserve filtered discovery and compile identically. Visibility grants no execution or product-skill eligibility; scopes remain ALL and roles ANY. Noodle derives securitySchemes; never author them.
|
|
248
|
+
For mixed customer preview, keep server customerAuth and adopt on the same org/app/env, endpoint, issuer and audience; keep the separate public Help endpoint during the pilot, and never create overlapping active issuer/audience ownership. Before any mixed deploy or access change, leave only Help unrestricted, add authorization to every customer tool, and validate plus preview with `noodle dev --access mixed`. For an existing customer-only app, first run `noodle deployments list --org <org> --app <app> --env <env> --json` and inspect an inactive `customers` record for the exact server version. If none exists, record the active ID, redeploy the unchanged secured source to the same version with `--access customers`, then list and inspect again to prove that ID is now inactive; recording it alone preserves nothing. Next deploy the policy-prepared source with `--access customers`, verify the original rollback record remains inactive, and only then run `noodle access set mixed ... --version <version>`. On pilot failure use `noodle rollback <deployment-id> --org <org> --app <app> --env <env> --reason <text>`. This app-history rollback differs from the compatible hosted service-release floor. Invalid supplied credentials fail, with no platform-human fallback. Broker exchange remains required. Local Devtools retries after successful sign-in and leaves Help available after cancellation without executing the protected tool. After deployment, test anonymous discovery, sign-in, cancellation, authenticated retry and expiry in the actual host before customer cutover; local/SDK checks do not prove ChatGPT or another host.
|
|
249
|
+
|
|
250
|
+
Role values are trusted only from the explicitly configured claim path (or the platform-private bridge role claim). Direct OIDC scopes default to standard `scope`, `scp`, or `scopes` claims unless `claims.scopes` is configured. Embedded-assistant backends pass verified `user.roles` and `user.scopes` separately during `createAssistantSession(...)`; page context never grants either. Claim values must be a string or string array; malformed or oversized values fail closed. Tools retain authored order in `tools/list`; protected descriptors are omitted unless explicitly public, and an unauthorized direct call is still denied before argument validation or connector execution. Scope denials use MCP OAuth step-up metadata without disclosing role names.
|
|
245
251
|
|
|
246
252
|
## Delegated downstream auth (call your API as the signed-in user)
|
|
247
253
|
|
|
@@ -409,7 +415,7 @@ Adapt the representative arguments and assertions when business contracts change
|
|
|
409
415
|
|
|
410
416
|
Author managed config as `secret("NAME")` / `variable("NAME")` and operate it with `noodle secrets set` / `noodle variables set` (scoped org/app/env). Never inline secret values in `server.ts`, tests, or generated files.
|
|
411
417
|
|
|
412
|
-
For business-editable configuration, declare `const
|
|
418
|
+
For business-editable configuration, declare `const guestExperience = variable("GUEST_EXPERIENCE", { schema: z.object({ notice: z.string().max(500) }), default: { notice: "Welcome" }, portal: { label: "Guest experience" }, requiredFor: ["show_menu"] })` and register it in `server(..., { variables: [guestExperience], ... }, tools)`. Use the whole ref or `guestExperience.field("notice")` in ordinary fulfilment/connector arguments. `.field()` selects a schema-declared object property, can chain for nested objects, and retains the parent variable and full configuration snapshot; it never reads operator data at author time. Keep confirmed action arguments shallow enough for complete review; do not label ordinary settings sensitive to bypass the review. The default is reusable safe intent; each business supplies its own values without editing source. Only explicit `portal` metadata exposes a setting. Name-only references and declared variables without `portal` remain technical configuration; secrets remain credential slots. See the bundled `acme-bistro` source.
|
|
413
419
|
|
|
414
420
|
Business schemas must be bounded: booleans, finite bounded numbers, bounded text, string enums, bounded arrays, and closed objects. Put defaults in the declaration, not inside Zod schema defaults; custom transforms/refinements and arbitrary schema code cannot run in the shared runtime. `requiredFor` names existing tools whose invocation needs the value; unresolved settings must leave only dependent capabilities unavailable. Publisher compilation does not require a future buyer’s values. Application code enforces business rules server-side; exposing a control or placing the rule in a prompt is insufficient.
|
|
415
421
|
|
|
@@ -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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:0e06e11254563b6a -->
|
|
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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:8d75ad13f4b3120a -->
|
|
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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:3a1e14ff9b98ddbd -->
|
|
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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:a21b2ed9997f9454 -->
|
|
7
7
|
|
|
8
8
|
# designing-mcp-products
|
|
9
9
|
|
|
@@ -47,6 +47,9 @@ Declare typed connectors:
|
|
|
47
47
|
- **HTTP**: `connector("id").version("1.0.0").http({ baseUrl, allowedOrigins, auth, operations })`; map request/response with `${args...}` / `${response...}`. Use `${execution.id}` for provider idempotency, never model input. Optional `evidence: { outcome: "${response.execution_outcome}", reference: "${response.id}" }` classifies completed/rejected/accepted/unknown; reference is a bounded opaque ID, never a bearer URL or payload. No automatic action retry.
|
|
48
48
|
- **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.
|
|
49
49
|
- **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`.
|
|
50
|
+
- **Explicit helpers**: `run: (input, host) => ...` can use `host.time.parse(iso)`, `host.time.format(epochMs)`, `host.time.parts(epochMs, timeZone)` and `host.digest(text, "hex")` (or `"base32hex"`). They convert bounded explicit data; there is no ambient clock. Pass trusted `context.temporal.instant` through fulfilment when current time is needed. `examples/weather` demonstrates a stable digest fallback for provider records without IDs.
|
|
51
|
+
- **Expected HTTP errors**: declare `responses: { "409": { response: { status: "conflict" }, evidence: { outcome: "rejected" } } }` alongside the ordinary success `response`. Explicit 4xx overrides exclude 401/403/429; validate against the same output schema. Undeclared errors still fail. Overrides never inherit successful completion evidence or introduce action retries.
|
|
52
|
+
- **Coordinated external actions**: a compute action may declare `coordination: { connectionId, namespace, key: "${args.resource}", reference: "${execution.id}" }` with a bounded execution deadline. It requires an installed application with a live bound connection and durable service coordination. Read `host.coordination.acquired` before writing; a blocked invocation may inspect `previous` through a declared read and call `host.resolveCoordination()` only after exact source proof, then require a fresh invocation/confirmation. The runtime permits at most one nested action when acquired and zero when blocked, even after recovery. Report explicit completed/rejected/unknown evidence with `host.reportOutcome(...)`; a successful return alone never unlocks uncertainty. Do not create an external-record collection for this.
|
|
50
53
|
|
|
51
54
|
Tools record connector calls into a flow; recording is not execution. Do not branch on runtime outputs with native `if` — use declarative `when(...)` conditions.
|
|
52
55
|
|
|
@@ -219,7 +222,7 @@ Every federated issuer must repeat every endpoint key used by the app, although
|
|
|
219
222
|
|
|
220
223
|
Resolved customer URLs are private routing authority: they never enter the manifest/artifact, `${user}`, logs, model output, widgets, public confirmation review, cache keys, or delegated-token-exchange assertions. Routed reads may be used by tools, including declared nested calls. A routed action—including one reached through a connector wrapper—requires exact `annotations.confirm: true`; omitted or `false` fails with `customer_endpoint_action_unsupported`. Routed resources, prompts, and ambient context fail with `customer_endpoint_surface_unsupported`.
|
|
221
224
|
|
|
222
|
-
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list`
|
|
225
|
+
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list` follows the scope/role discovery rule and its explicit public-descriptor opt-in, so route availability neither reveals tenant topology nor changes execution authorization.
|
|
223
226
|
|
|
224
227
|
## Per-tool authorization
|
|
225
228
|
|
|
@@ -241,7 +244,10 @@ tool('list_org_apps', {
|
|
|
241
244
|
})
|
|
242
245
|
```
|
|
243
246
|
|
|
244
|
-
|
|
247
|
+
Use `authorization.discovery: 'public'` on a nonempty scope/role rule to expose its MCP descriptor before sign-in. Omission and explicit 'authorized' preserve filtered discovery and compile identically. Visibility grants no execution or product-skill eligibility; scopes remain ALL and roles ANY. Noodle derives securitySchemes; never author them.
|
|
248
|
+
For mixed customer preview, keep server customerAuth and adopt on the same org/app/env, endpoint, issuer and audience; keep the separate public Help endpoint during the pilot, and never create overlapping active issuer/audience ownership. Before any mixed deploy or access change, leave only Help unrestricted, add authorization to every customer tool, and validate plus preview with `noodle dev --access mixed`. For an existing customer-only app, first run `noodle deployments list --org <org> --app <app> --env <env> --json` and inspect an inactive `customers` record for the exact server version. If none exists, record the active ID, redeploy the unchanged secured source to the same version with `--access customers`, then list and inspect again to prove that ID is now inactive; recording it alone preserves nothing. Next deploy the policy-prepared source with `--access customers`, verify the original rollback record remains inactive, and only then run `noodle access set mixed ... --version <version>`. On pilot failure use `noodle rollback <deployment-id> --org <org> --app <app> --env <env> --reason <text>`. This app-history rollback differs from the compatible hosted service-release floor. Invalid supplied credentials fail, with no platform-human fallback. Broker exchange remains required. Local Devtools retries after successful sign-in and leaves Help available after cancellation without executing the protected tool. After deployment, test anonymous discovery, sign-in, cancellation, authenticated retry and expiry in the actual host before customer cutover; local/SDK checks do not prove ChatGPT or another host.
|
|
249
|
+
|
|
250
|
+
Role values are trusted only from the explicitly configured claim path (or the platform-private bridge role claim). Direct OIDC scopes default to standard `scope`, `scp`, or `scopes` claims unless `claims.scopes` is configured. Embedded-assistant backends pass verified `user.roles` and `user.scopes` separately during `createAssistantSession(...)`; page context never grants either. Claim values must be a string or string array; malformed or oversized values fail closed. Tools retain authored order in `tools/list`; protected descriptors are omitted unless explicitly public, and an unauthorized direct call is still denied before argument validation or connector execution. Scope denials use MCP OAuth step-up metadata without disclosing role names.
|
|
245
251
|
|
|
246
252
|
## Delegated downstream auth (call your API as the signed-in user)
|
|
247
253
|
|
|
@@ -409,7 +415,7 @@ Adapt the representative arguments and assertions when business contracts change
|
|
|
409
415
|
|
|
410
416
|
Author managed config as `secret("NAME")` / `variable("NAME")` and operate it with `noodle secrets set` / `noodle variables set` (scoped org/app/env). Never inline secret values in `server.ts`, tests, or generated files.
|
|
411
417
|
|
|
412
|
-
For business-editable configuration, declare `const
|
|
418
|
+
For business-editable configuration, declare `const guestExperience = variable("GUEST_EXPERIENCE", { schema: z.object({ notice: z.string().max(500) }), default: { notice: "Welcome" }, portal: { label: "Guest experience" }, requiredFor: ["show_menu"] })` and register it in `server(..., { variables: [guestExperience], ... }, tools)`. Use the whole ref or `guestExperience.field("notice")` in ordinary fulfilment/connector arguments. `.field()` selects a schema-declared object property, can chain for nested objects, and retains the parent variable and full configuration snapshot; it never reads operator data at author time. Keep confirmed action arguments shallow enough for complete review; do not label ordinary settings sensitive to bypass the review. The default is reusable safe intent; each business supplies its own values without editing source. Only explicit `portal` metadata exposes a setting. Name-only references and declared variables without `portal` remain technical configuration; secrets remain credential slots. See the bundled `acme-bistro` source.
|
|
413
419
|
|
|
414
420
|
Business schemas must be bounded: booleans, finite bounded numbers, bounded text, string enums, bounded arrays, and closed objects. Put defaults in the declaration, not inside Zod schema defaults; custom transforms/refinements and arbitrary schema code cannot run in the shared runtime. `requiredFor` names existing tools whose invocation needs the value; unresolved settings must leave only dependent capabilities unavailable. Publisher compilation does not require a future buyer’s values. Application code enforces business rules server-side; exposing a control or placing the rule in a prompt is insufficient.
|
|
415
421
|
|
|
@@ -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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:d554d661ed7ac7be -->
|
|
7
7
|
|
|
8
8
|
# embedding-mcp-assistants
|
|
9
9
|
|
|
@@ -47,6 +47,9 @@ Declare typed connectors:
|
|
|
47
47
|
- **HTTP**: `connector("id").version("1.0.0").http({ baseUrl, allowedOrigins, auth, operations })`; map request/response with `${args...}` / `${response...}`. Use `${execution.id}` for provider idempotency, never model input. Optional `evidence: { outcome: "${response.execution_outcome}", reference: "${response.id}" }` classifies completed/rejected/accepted/unknown; reference is a bounded opaque ID, never a bearer URL or payload. No automatic action retry.
|
|
48
48
|
- **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.
|
|
49
49
|
- **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`.
|
|
50
|
+
- **Explicit helpers**: `run: (input, host) => ...` can use `host.time.parse(iso)`, `host.time.format(epochMs)`, `host.time.parts(epochMs, timeZone)` and `host.digest(text, "hex")` (or `"base32hex"`). They convert bounded explicit data; there is no ambient clock. Pass trusted `context.temporal.instant` through fulfilment when current time is needed. `examples/weather` demonstrates a stable digest fallback for provider records without IDs.
|
|
51
|
+
- **Expected HTTP errors**: declare `responses: { "409": { response: { status: "conflict" }, evidence: { outcome: "rejected" } } }` alongside the ordinary success `response`. Explicit 4xx overrides exclude 401/403/429; validate against the same output schema. Undeclared errors still fail. Overrides never inherit successful completion evidence or introduce action retries.
|
|
52
|
+
- **Coordinated external actions**: a compute action may declare `coordination: { connectionId, namespace, key: "${args.resource}", reference: "${execution.id}" }` with a bounded execution deadline. It requires an installed application with a live bound connection and durable service coordination. Read `host.coordination.acquired` before writing; a blocked invocation may inspect `previous` through a declared read and call `host.resolveCoordination()` only after exact source proof, then require a fresh invocation/confirmation. The runtime permits at most one nested action when acquired and zero when blocked, even after recovery. Report explicit completed/rejected/unknown evidence with `host.reportOutcome(...)`; a successful return alone never unlocks uncertainty. Do not create an external-record collection for this.
|
|
50
53
|
|
|
51
54
|
Tools record connector calls into a flow; recording is not execution. Do not branch on runtime outputs with native `if` — use declarative `when(...)` conditions.
|
|
52
55
|
|
|
@@ -219,7 +222,7 @@ Every federated issuer must repeat every endpoint key used by the app, although
|
|
|
219
222
|
|
|
220
223
|
Resolved customer URLs are private routing authority: they never enter the manifest/artifact, `${user}`, logs, model output, widgets, public confirmation review, cache keys, or delegated-token-exchange assertions. Routed reads may be used by tools, including declared nested calls. A routed action—including one reached through a connector wrapper—requires exact `annotations.confirm: true`; omitted or `false` fails with `customer_endpoint_action_unsupported`. Routed resources, prompts, and ambient context fail with `customer_endpoint_surface_unsupported`.
|
|
221
224
|
|
|
222
|
-
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list`
|
|
225
|
+
At runtime, an initially missing, malformed, or disallowed claim returns the same safe `connector_route_unavailable` tool error before credential lookup or connector egress. Preparation stores only sorted route `{ key, fingerprint }` bindings in the private server-held continuation. Acceptance re-resolves the current request routes; a missing or changed binding returns `invalid_continuation` before policy, credentials, or egress, then the matching frozen snapshot is reused for the action and nested/later calls. `tools/list` follows the scope/role discovery rule and its explicit public-descriptor opt-in, so route availability neither reveals tenant topology nor changes execution authorization.
|
|
223
226
|
|
|
224
227
|
## Per-tool authorization
|
|
225
228
|
|
|
@@ -241,7 +244,10 @@ tool('list_org_apps', {
|
|
|
241
244
|
})
|
|
242
245
|
```
|
|
243
246
|
|
|
244
|
-
|
|
247
|
+
Use `authorization.discovery: 'public'` on a nonempty scope/role rule to expose its MCP descriptor before sign-in. Omission and explicit 'authorized' preserve filtered discovery and compile identically. Visibility grants no execution or product-skill eligibility; scopes remain ALL and roles ANY. Noodle derives securitySchemes; never author them.
|
|
248
|
+
For mixed customer preview, keep server customerAuth and adopt on the same org/app/env, endpoint, issuer and audience; keep the separate public Help endpoint during the pilot, and never create overlapping active issuer/audience ownership. Before any mixed deploy or access change, leave only Help unrestricted, add authorization to every customer tool, and validate plus preview with `noodle dev --access mixed`. For an existing customer-only app, first run `noodle deployments list --org <org> --app <app> --env <env> --json` and inspect an inactive `customers` record for the exact server version. If none exists, record the active ID, redeploy the unchanged secured source to the same version with `--access customers`, then list and inspect again to prove that ID is now inactive; recording it alone preserves nothing. Next deploy the policy-prepared source with `--access customers`, verify the original rollback record remains inactive, and only then run `noodle access set mixed ... --version <version>`. On pilot failure use `noodle rollback <deployment-id> --org <org> --app <app> --env <env> --reason <text>`. This app-history rollback differs from the compatible hosted service-release floor. Invalid supplied credentials fail, with no platform-human fallback. Broker exchange remains required. Local Devtools retries after successful sign-in and leaves Help available after cancellation without executing the protected tool. After deployment, test anonymous discovery, sign-in, cancellation, authenticated retry and expiry in the actual host before customer cutover; local/SDK checks do not prove ChatGPT or another host.
|
|
249
|
+
|
|
250
|
+
Role values are trusted only from the explicitly configured claim path (or the platform-private bridge role claim). Direct OIDC scopes default to standard `scope`, `scp`, or `scopes` claims unless `claims.scopes` is configured. Embedded-assistant backends pass verified `user.roles` and `user.scopes` separately during `createAssistantSession(...)`; page context never grants either. Claim values must be a string or string array; malformed or oversized values fail closed. Tools retain authored order in `tools/list`; protected descriptors are omitted unless explicitly public, and an unauthorized direct call is still denied before argument validation or connector execution. Scope denials use MCP OAuth step-up metadata without disclosing role names.
|
|
245
251
|
|
|
246
252
|
## Delegated downstream auth (call your API as the signed-in user)
|
|
247
253
|
|
|
@@ -409,7 +415,7 @@ Adapt the representative arguments and assertions when business contracts change
|
|
|
409
415
|
|
|
410
416
|
Author managed config as `secret("NAME")` / `variable("NAME")` and operate it with `noodle secrets set` / `noodle variables set` (scoped org/app/env). Never inline secret values in `server.ts`, tests, or generated files.
|
|
411
417
|
|
|
412
|
-
For business-editable configuration, declare `const
|
|
418
|
+
For business-editable configuration, declare `const guestExperience = variable("GUEST_EXPERIENCE", { schema: z.object({ notice: z.string().max(500) }), default: { notice: "Welcome" }, portal: { label: "Guest experience" }, requiredFor: ["show_menu"] })` and register it in `server(..., { variables: [guestExperience], ... }, tools)`. Use the whole ref or `guestExperience.field("notice")` in ordinary fulfilment/connector arguments. `.field()` selects a schema-declared object property, can chain for nested objects, and retains the parent variable and full configuration snapshot; it never reads operator data at author time. Keep confirmed action arguments shallow enough for complete review; do not label ordinary settings sensitive to bypass the review. The default is reusable safe intent; each business supplies its own values without editing source. Only explicit `portal` metadata exposes a setting. Name-only references and declared variables without `portal` remain technical configuration; secrets remain credential slots. See the bundled `acme-bistro` source.
|
|
413
419
|
|
|
414
420
|
Business schemas must be bounded: booleans, finite bounded numbers, bounded text, string enums, bounded arrays, and closed objects. Put defaults in the declaration, not inside Zod schema defaults; custom transforms/refinements and arbitrary schema code cannot run in the shared runtime. `requiredFor` names existing tools whose invocation needs the value; unresolved settings must leave only dependent capabilities unavailable. Publisher compilation does not require a future buyer’s values. Application code enforces business rules server-side; exposing a control or placing the rule in a prompt is insufficient.
|
|
415
421
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Fictional [`menu/cart`](src/server.ts) with off-app payment: card data stays outside the app.
|
|
4
4
|
|
|
5
|
-
`
|
|
5
|
+
`GUEST_EXPERIENCE` settings use `guestExperience.field('notice')` to select a typed business value; native `guest_requests` demonstrate status, field exposure and notes. `submit_guest_request` requires an authorized installation and returns a receipt
|
|
6
6
|
for staff review. The installed skill's `references/authoring-workflow.md` owns setup and source contracts.
|
|
7
7
|
External collections declare a bounded connector scan; provider changes remain ordinary tools.
|
|
8
8
|
|
|
@@ -20,11 +20,11 @@ const menu = [
|
|
|
20
20
|
|
|
21
21
|
const itemId = z.enum(['stone_pizza', 'roast_bowl', 'house_salad', 'lemon_tart', 'sparkling']);
|
|
22
22
|
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
schema: z.string().max(500),
|
|
26
|
-
default: 'Ask us about dietary requirements before placing your order.',
|
|
27
|
-
portal: { label: '
|
|
23
|
+
// Operators configure the notice without redeploying.
|
|
24
|
+
const guestExperience = variable('GUEST_EXPERIENCE', {
|
|
25
|
+
schema: z.object({ notice: z.string().max(500) }),
|
|
26
|
+
default: { notice: 'Ask us about dietary requirements before placing your order.' },
|
|
27
|
+
portal: { label: 'Guest experience', group: 'Guest experience' },
|
|
28
28
|
requiredFor: ['show_menu'],
|
|
29
29
|
});
|
|
30
30
|
|
|
@@ -86,7 +86,7 @@ export default server(
|
|
|
86
86
|
// Reusable business-record intent. Storage, lifecycle, access, and public intake bind separately.
|
|
87
87
|
collections: [guestRequests],
|
|
88
88
|
use: { records: noodlePlatform.records.v1 },
|
|
89
|
-
variables: [
|
|
89
|
+
variables: [guestExperience],
|
|
90
90
|
},
|
|
91
91
|
[
|
|
92
92
|
tool('submit_guest_request', {
|
|
@@ -123,7 +123,7 @@ export default server(
|
|
|
123
123
|
fulfil: ({ input }) => ({
|
|
124
124
|
status: `Acme Bistro menu is ready for ${input.customer}. Build the order here; pay at checkout.`,
|
|
125
125
|
customer: input.customer,
|
|
126
|
-
serviceNotice,
|
|
126
|
+
serviceNotice: guestExperience.field('notice'),
|
|
127
127
|
items: menu,
|
|
128
128
|
}),
|
|
129
129
|
viewTitle: 'Order at Acme Bistro',
|
|
@@ -7,20 +7,16 @@ This curated example owns the customer/end-user authentication capability slot.
|
|
|
7
7
|
can protect an MCP endpoint with direct OIDC, retain role/scope-based tool authorization, and route ordinary
|
|
8
8
|
reads and confirmed actions to the API origin selected by the verified customer's identity provider.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
route from the verified OIDC claim; embedded sessions obtain it from the authenticated customer backend's
|
|
12
|
-
session exchange. Both paths keep the URL outside tool/model/browser-visible state. The built-in card hides
|
|
13
|
-
its optional technical Additional details disclosure while retaining the business review and confirmation
|
|
14
|
-
controls; this presentation setting does not weaken the exact runtime confirmation boundary.
|
|
10
|
+
Direct MCP calls obtain the private route from verified OIDC claims; embedded sessions obtain it from the authenticated backend. Both keep routes out of model and browser state.
|
|
15
11
|
|
|
16
12
|
The public developer entrypoint is [`src/server.ts`](src/server.ts). It exposes a deliberately small MCP
|
|
17
13
|
surface for organization discovery and app lifecycle operations:
|
|
18
14
|
|
|
19
|
-
- `
|
|
20
|
-
|
|
21
|
-
- `list_org_apps`
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
- `help` explains the product without customer identity.
|
|
16
|
+
- `list_my_organizations` publicly advertises its descriptor but requires `organizations:read` to list the signed-in customer’s organizations.
|
|
17
|
+
- `list_org_apps` uses `authorization.discovery: 'public'` to expose its descriptor on an anonymously
|
|
18
|
+
accessible endpoint. Execution still requires `org_apps:read` and `org_admin` or `org_member`. Visibility
|
|
19
|
+
grants no permissions, records, role disclosure, or product-guide eligibility. ChatGPT sign-in is unproven.
|
|
24
20
|
- `archive_org_app` archives one app only after exact runtime confirmation. It requires the
|
|
25
21
|
`org_apps:write` scope and `org_admin` role.
|
|
26
22
|
|
|
@@ -28,22 +24,7 @@ The tools chain: `list_my_organizations` surfaces the `org_id`s the customer can
|
|
|
28
24
|
`list_org_apps` takes one of those ids, and `archive_org_app` accepts the selected app id. Tool code remains
|
|
29
25
|
independent of the selected origin.
|
|
30
26
|
|
|
31
|
-
The
|
|
32
|
-
uses it automatically: each turn keeps only complete workflows supported by the verified session's roles,
|
|
33
|
-
scopes, and model-visible tools. An organization member can receive organization/app review guidance, while
|
|
34
|
-
only an administrator with `org_apps:write` receives the complete archive workflow and its confirmation
|
|
35
|
-
boundary. The guide stays server-side, so the Web Component, React renderer, headless hook, and public client
|
|
36
|
-
need no new option and receive no raw skill content. See
|
|
37
|
-
[using a product guide at runtime](https://docs.noodleseed.dev/docs/guides/product-agent-guides#use-the-guide-at-runtime)
|
|
38
|
-
for the public behavior guide.
|
|
39
|
-
|
|
40
|
-
A skill-aware external agent connected directly to the same tenant MCP URL receives the same
|
|
41
|
-
complete-workflow filtering through the modern draft MCP Skills extension. Members and administrators may
|
|
42
|
-
therefore receive different `SKILL.md` and MCP-surface bytes, each with matching caller-specific digests.
|
|
43
|
-
This reuses the configured customer OAuth boundary; it does not require a second skill installation or auth
|
|
44
|
-
system, and it is not a claim that every external host currently implements the draft extension. The
|
|
45
|
-
same [runtime guide](https://docs.noodleseed.dev/docs/guides/product-agent-guides#use-the-guide-at-runtime)
|
|
46
|
-
explains this preview boundary.
|
|
27
|
+
The typed `agentGuide` retains only complete workflows the verified caller can execute. Public descriptor discovery does not grant workflow access. See the [runtime guide](https://docs.noodleseed.dev/docs/guides/product-agent-guides#use-the-guide-at-runtime) for embedded behavior and the draft MCP Skills preview.
|
|
47
28
|
|
|
48
29
|
## Declare the customer endpoint
|
|
49
30
|
|
|
@@ -212,6 +193,7 @@ rule beside the rest of its public contract:
|
|
|
212
193
|
```ts
|
|
213
194
|
tool('list_org_apps', {
|
|
214
195
|
authorization: {
|
|
196
|
+
discovery: 'public',
|
|
215
197
|
requiredScopes: ['org_apps:read'],
|
|
216
198
|
allowedRoles: ['org_admin', 'org_member'],
|
|
217
199
|
},
|
|
@@ -220,9 +202,9 @@ tool('list_org_apps', {
|
|
|
220
202
|
```
|
|
221
203
|
|
|
222
204
|
Every required scope must be present and at least one allowed role must match. When both lists are declared,
|
|
223
|
-
both conditions apply.
|
|
224
|
-
|
|
225
|
-
closed.
|
|
205
|
+
both conditions apply. In mixed customer mode, `discovery: 'public'` exposes this descriptor before sign-in;
|
|
206
|
+
execution still requires those scopes and roles. Other restricted tools remain filtered by authorization.
|
|
207
|
+
Route availability never changes discovery, and unauthorized direct calls fail closed.
|
|
226
208
|
|
|
227
209
|
Tool code calls the connector normally:
|
|
228
210
|
|
|
@@ -811,11 +793,7 @@ subject assertion and mints a short-lived token scoped to the signed-in user and
|
|
|
811
793
|
|
|
812
794
|
## Launch and qualified-usage proof
|
|
813
795
|
|
|
814
|
-
|
|
815
|
-
pre-launch, browser-proof, qualified-usage, recovery, measurement, and operator procedure; do not copy those
|
|
816
|
-
commands into this example. Keep deployed capability, production-browser proof, qualified usage, and measured
|
|
817
|
-
outcome separate; raw turn volume is utilization rather than outcome. Platform-owned completion events still
|
|
818
|
-
require a separate human-approved analytics and customer-data contract.
|
|
796
|
+
For launch, browser verification, and qualified usage, follow the [embedded assistant guide](https://docs.noodleseed.dev/docs/guides/embedded-assistant).
|
|
819
797
|
|
|
820
798
|
## Deploy customer-protected to Noodle Seed Cloud
|
|
821
799
|
|
|
@@ -833,13 +811,23 @@ Endpoint:
|
|
|
833
811
|
https://cloud.noodleseed.dev/o/noodleseed/customer-auth/mcp
|
|
834
812
|
```
|
|
835
813
|
|
|
836
|
-
##
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
814
|
+
## Preview anonymous Help with customer sign-in
|
|
815
|
+
|
|
816
|
+
Use `noodle dev examples/customer-auth/src/server.ts --access mixed`. Help remains available before sign-in;
|
|
817
|
+
protected reads advertise descriptors and require their verified scopes/roles to execute. Customer mode
|
|
818
|
+
remains the default. Local Devtools retries a protected call after successful sign-in; cancellation executes
|
|
819
|
+
nothing and leaves Help available. With a hosted service, a new target may use
|
|
820
|
+
`--access mixed` only after every customer tool has an authorization rule. For an existing customer-only
|
|
821
|
+
target, preserve its org/app/env, endpoint, issuer, and audience. Follow the public guide: verify an inactive
|
|
822
|
+
`customers` record for the exact version, creating it by unchanged secured redeploy if absent; add and
|
|
823
|
+
validate every tool rule; deploy the prepared source as `customers`; recheck the rollback; then adopt mixed
|
|
824
|
+
access. On pilot failure, use
|
|
825
|
+
`noodle rollback <deployment-id>` with the same org/app/env. This app-history rollback is separate from the
|
|
826
|
+
compatible hosted service-release floor. Keep the public Help endpoint through the post-deployment ChatGPT
|
|
827
|
+
and customer API pilot. Local behavior and wire checks do not prove that host
|
|
828
|
+
journey. See the
|
|
829
|
+
[customer auth rollback and adoption procedure](https://docs.noodleseed.dev/docs/guides/customer-auth#preserve-an-app-rollback-target-and-adopt)
|
|
830
|
+
for the exact commands and checks.
|
|
843
831
|
|
|
844
832
|
## Auth boundary
|
|
845
833
|
|
|
@@ -202,10 +202,23 @@ export default server(
|
|
|
202
202
|
}),
|
|
203
203
|
},
|
|
204
204
|
[
|
|
205
|
+
tool('help', {
|
|
206
|
+
title: 'Help with organizations and apps',
|
|
207
|
+
description: 'Explain what customers can do before they sign in.',
|
|
208
|
+
input: z.object({}),
|
|
209
|
+
output: z.object({ help: z.string() }),
|
|
210
|
+
annotations: annotations.readOnly(),
|
|
211
|
+
fulfil() {
|
|
212
|
+
return {
|
|
213
|
+
help: 'Sign in to browse your organizations and apps. Archiving an app requires an administrator and confirmation.',
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
}),
|
|
205
217
|
tool('list_org_apps', {
|
|
206
218
|
title: 'List organization apps',
|
|
207
219
|
description: 'List NoodleSeed.com apps for an organization from its customer API.',
|
|
208
220
|
authorization: {
|
|
221
|
+
discovery: 'public',
|
|
209
222
|
requiredScopes: ['org_apps:read'],
|
|
210
223
|
allowedRoles: ['org_admin', 'org_member'],
|
|
211
224
|
},
|
|
@@ -232,12 +245,10 @@ export default server(
|
|
|
232
245
|
tool('list_my_organizations', {
|
|
233
246
|
title: 'List my organizations',
|
|
234
247
|
description: 'List the NoodleSeed.com organizations the signed-in customer belongs to.',
|
|
248
|
+
authorization: { discovery: 'public', requiredScopes: ['organizations:read'] },
|
|
235
249
|
contextProvider: true,
|
|
236
250
|
input: z.object({}),
|
|
237
|
-
// The
|
|
238
|
-
// page parameter to pass through, so the bound is declared on the shape. A customer belongs to a
|
|
239
|
-
// handful of organizations; `noodle check` reports an unbounded list as
|
|
240
|
-
// `tool_design_output_bounds`.
|
|
251
|
+
// The API returns all of the caller's organizations without pagination; bound the output shape.
|
|
241
252
|
output: z.object({
|
|
242
253
|
organizations: z.array(z.unknown()).max(100),
|
|
243
254
|
}),
|
|
@@ -85,12 +85,17 @@ describe('customer-auth example', () => {
|
|
|
85
85
|
expect(catalog?.connectors[0]?.http).not.toHaveProperty('allowedOrigins');
|
|
86
86
|
expect(JSON.stringify({ manifest, catalog })).not.toContain('tenant-a.api.noodleseed.dev');
|
|
87
87
|
expect(manifest.tools.find((tool) => tool.name === 'list_org_apps')?.authorization).toEqual({
|
|
88
|
+
discovery: 'public',
|
|
88
89
|
requiredScopes: ['org_apps:read'],
|
|
89
90
|
allowedRoles: ['org_admin', 'org_member'],
|
|
90
91
|
});
|
|
91
92
|
expect(
|
|
92
93
|
manifest.tools.find((tool) => tool.name === 'list_my_organizations')?.authorization,
|
|
93
|
-
).
|
|
94
|
+
).toEqual({ discovery: 'public', requiredScopes: ['organizations:read'] });
|
|
95
|
+
const help = manifest.tools.find((tool) => tool.name === 'help');
|
|
96
|
+
expect(help).toBeDefined();
|
|
97
|
+
expect(help?.authorization).toBeUndefined();
|
|
98
|
+
expect(help?.annotations?.readOnlyHint).toBe(true);
|
|
94
99
|
expect(manifest.tools.find((tool) => tool.name === 'archive_org_app')).toMatchObject({
|
|
95
100
|
authorization: {
|
|
96
101
|
requiredScopes: ['org_apps:write'],
|
|
@@ -158,8 +158,8 @@ const placeNarrow = connector('geo_places')
|
|
|
158
158
|
type: 'read',
|
|
159
159
|
input: z.object({ results: z.unknown().optional() }),
|
|
160
160
|
output: z.object({ places: z.array(z.unknown()) }),
|
|
161
|
-
//
|
|
162
|
-
run: (input) => {
|
|
161
|
+
// Synchronous and self-contained.
|
|
162
|
+
run: (input, host) => {
|
|
163
163
|
const raw = input.results;
|
|
164
164
|
const list = Array.isArray(raw) ? raw : [];
|
|
165
165
|
const places = list.map((entry) => {
|
|
@@ -169,7 +169,7 @@ const placeNarrow = connector('geo_places')
|
|
|
169
169
|
const id =
|
|
170
170
|
entry.id !== undefined && entry.id !== null
|
|
171
171
|
? String(entry.id)
|
|
172
|
-
: `${entry.latitude},${entry.longitude}
|
|
172
|
+
: host.digest(`${entry.latitude},${entry.longitude}`);
|
|
173
173
|
return { id, label: parts.join(', ') };
|
|
174
174
|
});
|
|
175
175
|
return { places };
|
|
@@ -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.
|
|
6
|
+
<!-- noodle-skill version:0.103.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.
|
|
6
|
+
<!-- noodle-skill version:0.103.0 hash:0ccafb222038f553 -->
|
|
7
7
|
|
|
8
8
|
# publishing-mcp-integrations
|
|
9
9
|
|