@noodleseed/agent-kit 0.55.0 → 0.56.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 +249 -249
- 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/building-mcp-apps/SKILL.md +1 -1
- package/skills/claude-code/connecting-apis-to-mcp/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/embedding-mcp-assistants/SKILL.md +1 -1
- package/skills/claude-code/examples/customer-auth/README.md +52 -13
- package/skills/claude-code/examples/customer-auth/src/server.ts +41 -2
- package/skills/claude-code/examples/customer-auth/test/server.test.ts +18 -5
- 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 +23 -3
- package/skills/claude-code/references/compile-errors.md +2 -1
- package/skills/claude-code/references/examples.md +1 -1
- package/skills/claude-code/reporting-noodle-feedback/SKILL.md +1 -1
- package/skills/claude-code/verifying-mcp-delivery/SKILL.md +1 -1
- package/skills/codex/SKILL.md +1 -1
- package/skills/codex/authoring-mcp-servers/SKILL.md +1 -1
- package/skills/codex/building-mcp-apps/SKILL.md +1 -1
- package/skills/codex/connecting-apis-to-mcp/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/embedding-mcp-assistants/SKILL.md +1 -1
- package/skills/codex/examples/customer-auth/README.md +52 -13
- package/skills/codex/examples/customer-auth/src/server.ts +41 -2
- package/skills/codex/examples/customer-auth/test/server.test.ts +18 -5
- 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 +23 -3
- package/skills/codex/references/compile-errors.md +2 -1
- package/skills/codex/references/examples.md +1 -1
- package/skills/codex/reporting-noodle-feedback/SKILL.md +1 -1
- package/skills/codex/verifying-mcp-delivery/SKILL.md +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/agent-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.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.56.0 hash:ec5bfcd0d8165205 -->
|
|
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.56.0 hash:0b2fd8c7e43fc69f -->
|
|
7
7
|
|
|
8
8
|
# authoring-mcp-servers
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: building-mcp-apps
|
|
|
3
3
|
description: "Use when a Noodle Seed MCP App, widget, interactive card, visual interaction, or host-visible UI is the primary requested outcome."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:f7fa54992c8d7692 -->
|
|
7
7
|
|
|
8
8
|
# building-mcp-apps
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: connecting-apis-to-mcp
|
|
|
3
3
|
description: "Use when credentials, an API URL, an OpenAPI document, or an observed response must become real Noodle Seed MCP behavior."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:1e86b8704f407bd3 -->
|
|
7
7
|
|
|
8
8
|
# connecting-apis-to-mcp
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: debugging-mcp-delivery
|
|
|
3
3
|
description: "Use when an existing Noodle Seed MCP project has a concrete validation, runtime, connector, App, host, deployment, or production failure."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.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.
|
|
6
|
+
<!-- noodle-skill version:0.56.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.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:76cce86729cffbee -->
|
|
7
7
|
|
|
8
8
|
# designing-mcp-products
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: embedding-mcp-assistants
|
|
|
3
3
|
description: "Use when embedding a Noodle assistant into an existing SaaS or web application with browser, identity, session, and credential boundaries."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:cc54a67f21c0ecdb -->
|
|
7
7
|
|
|
8
8
|
# embedding-mcp-assistants
|
|
9
9
|
|
|
@@ -2,23 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
This curated example owns the customer/end-user authentication capability slot. It proves that a SaaS app
|
|
4
4
|
can protect an MCP endpoint with direct OIDC, retain role/scope-based tool authorization, and route ordinary
|
|
5
|
-
|
|
5
|
+
reads and confirmed actions to the API origin selected by the verified customer's identity provider.
|
|
6
6
|
|
|
7
7
|
It also owns the customer-branded embedded-assistant presentation showcase. Embedded sessions lack
|
|
8
8
|
direct/federated MCP OIDC endpoint claims, so these routed tools fail with `connector_route_unavailable`;
|
|
9
9
|
static connectors still support embedded delegated exchange. Exercise routed tools through the MCP endpoint.
|
|
10
10
|
|
|
11
11
|
The public developer entrypoint is [`src/server.ts`](src/server.ts). It exposes a deliberately small MCP
|
|
12
|
-
surface for organization discovery:
|
|
12
|
+
surface for organization discovery and app lifecycle operations:
|
|
13
13
|
|
|
14
14
|
- `list_my_organizations` lists the NoodleSeed.com organizations the signed-in customer belongs to (no
|
|
15
15
|
arguments — the org set comes from the verified customer session).
|
|
16
16
|
- `list_org_apps` lists apps for one of those organizations through that tenant's API. It is visible and
|
|
17
17
|
callable only when the verified customer has the `org_apps:read` scope and either the `org_admin` or
|
|
18
18
|
`org_member` role.
|
|
19
|
+
- `archive_org_app` archives one app only after exact runtime confirmation. It requires the
|
|
20
|
+
`org_apps:write` scope and `org_admin` role.
|
|
19
21
|
|
|
20
|
-
The
|
|
21
|
-
`list_org_apps` takes one of those `
|
|
22
|
+
The tools chain: `list_my_organizations` surfaces the `org_id`s the customer can act on,
|
|
23
|
+
`list_org_apps` takes one of those ids, and `archive_org_app` accepts the selected app id. Tool code remains
|
|
24
|
+
independent of the selected origin.
|
|
22
25
|
|
|
23
26
|
## Declare the customer endpoint
|
|
24
27
|
|
|
@@ -48,11 +51,11 @@ const api = connector('noodleseed_app_api')
|
|
|
48
51
|
tokenUrl: 'https://id.noodleseed.dev/oauth/token',
|
|
49
52
|
clientId: variable('CUSTOMER_API_CLIENT_ID'),
|
|
50
53
|
clientSecret: secret('CUSTOMER_API_CLIENT_SECRET'),
|
|
51
|
-
scopes: ['organizations:read', 'org_apps:read'],
|
|
54
|
+
scopes: ['organizations:read', 'org_apps:read', 'org_apps:write'],
|
|
52
55
|
audience: 'noodleseed-customer-api',
|
|
53
56
|
},
|
|
54
57
|
operations: {
|
|
55
|
-
// read operations...
|
|
58
|
+
// read and action operations...
|
|
56
59
|
},
|
|
57
60
|
});
|
|
58
61
|
```
|
|
@@ -113,12 +116,45 @@ auth: customerAuth.federatedOidc({
|
|
|
113
116
|
At runtime, Noodle Seed validates both the configured audience and exact MCP resource, projects the route
|
|
114
117
|
into private request state, applies its policy, and freezes it for the call. Missing, malformed, or
|
|
115
118
|
disallowed claims return `connector_route_unavailable` before credential lookup or connector egress.
|
|
116
|
-
Resolved URLs never enter artifacts, `${user}`, logs, model output, widgets, confirmation review,
|
|
117
|
-
keys, or delegated exchange assertions.
|
|
119
|
+
Resolved URLs never enter artifacts, `${user}`, logs, model output, widgets, public confirmation review,
|
|
120
|
+
broker cache keys, or delegated exchange assertions.
|
|
118
121
|
|
|
119
|
-
|
|
120
|
-
`
|
|
121
|
-
`customer_endpoint_surface_unsupported`.
|
|
122
|
+
Routed reads work in tools, including declared nested calls. Routed actions require exact
|
|
123
|
+
`annotations.confirm: true`; otherwise they fail with `customer_endpoint_action_unsupported`. Routed
|
|
124
|
+
resources, prompts, and ambient context fail with `customer_endpoint_surface_unsupported`.
|
|
125
|
+
|
|
126
|
+
The flagship's routed action uses the normal TypeScript action helper:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
tool('archive_org_app', {
|
|
130
|
+
authorization: {
|
|
131
|
+
requiredScopes: ['org_apps:write'],
|
|
132
|
+
allowedRoles: ['org_admin'],
|
|
133
|
+
},
|
|
134
|
+
annotations: annotations.openAction({ destructive: false, confirm: true }),
|
|
135
|
+
// input, output, and the normal connectors.app_api.archiveOrgApp(...) call...
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The flagship also opts into the current stateless hosted MCP path:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
interactions: {
|
|
143
|
+
confirmationFallback: 'host',
|
|
144
|
+
},
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
A bidirectional client that negotiated form elicitation can complete the standard confirmation exchange
|
|
148
|
+
instead. The explicit host fallback trusts the MCP host to have collected native write approval before the
|
|
149
|
+
tool call reaches Noodle Seed; it is never inferred from client identity and does not replace auth, policy,
|
|
150
|
+
or accurate action/destructive annotations. Omit the fallback when connected hosts are not trusted to
|
|
151
|
+
provide that approval. If neither standard confirmation nor the fallback is available, the action fails
|
|
152
|
+
closed with `interaction_unavailable`.
|
|
153
|
+
|
|
154
|
+
Preparation stores only sorted route `{ key, fingerprint }` bindings in its private server-held
|
|
155
|
+
continuation; the public review exposes none of them. Acceptance re-resolves the current request route and
|
|
156
|
+
returns `invalid_continuation` if it is missing or changed, before policy, credentials, or egress. A match
|
|
157
|
+
reuses the current frozen snapshot for the action and all nested or later reads.
|
|
122
158
|
|
|
123
159
|
The application developer owns the direct/federated authorization server. It must publish its path-inserted
|
|
124
160
|
RFC 8414 document as direct HTTP 200 JSON with exact issuer and HTTPS authorization/token/registration/JWKS
|
|
@@ -180,7 +216,7 @@ noodle validate examples/customer-auth/src/server.ts
|
|
|
180
216
|
|
|
181
217
|
Against a deployed customer-protected environment, set a short-lived real customer token only in
|
|
182
218
|
`NOODLE_CUSTOMER_TOKEN` and add `--live --org <org> --app <app> --env <env>`. The live doctor performs
|
|
183
|
-
credential exchanges without invoking
|
|
219
|
+
credential exchanges without invoking any business tool.
|
|
184
220
|
|
|
185
221
|
## Run locally
|
|
186
222
|
|
|
@@ -487,6 +523,8 @@ https://cloud.noodleseed.dev/o/noodleseed/customer-auth/mcp
|
|
|
487
523
|
- Tool `list_my_organizations`: calls `GET /api/organizations` and returns the organizations the signed-in
|
|
488
524
|
customer is a member of. Takes no arguments; the org set is scoped by the verified customer session.
|
|
489
525
|
- Tool `list_org_apps`: calls `GET /api/organizations/{org_id}/apps` for one organization `org_id`.
|
|
526
|
+
- Tool `archive_org_app`: after confirmation, calls
|
|
527
|
+
`POST /api/organizations/{org_id}/apps/{app_id}/archive`.
|
|
490
528
|
|
|
491
529
|
## Auth boundary
|
|
492
530
|
|
|
@@ -496,4 +534,5 @@ private request state.
|
|
|
496
534
|
|
|
497
535
|
Connector-backed tools ask the broker for a route-bound delegated credential; only the endpoint key and
|
|
498
536
|
fingerprint enter broker cache/single-flight state or the assertion. The route claim and inbound MCP bearer
|
|
499
|
-
token never reach tools, connectors, widgets, model output, or downstream systems.
|
|
537
|
+
token never reach tools, connectors, widgets, model output, or downstream systems. Confirmed actions keep
|
|
538
|
+
the same URL-blind binding only in private continuation state and reject acceptance-time drift.
|
|
@@ -25,7 +25,7 @@ const noodleseedApi = connector('noodleseed_app_api')
|
|
|
25
25
|
tokenUrl: 'https://id.noodleseed.dev/oauth/token',
|
|
26
26
|
clientId: variable('CUSTOMER_API_CLIENT_ID'),
|
|
27
27
|
clientSecret: secret('CUSTOMER_API_CLIENT_SECRET'),
|
|
28
|
-
scopes: ['organizations:read', 'org_apps:read'],
|
|
28
|
+
scopes: ['organizations:read', 'org_apps:read', 'org_apps:write'],
|
|
29
29
|
audience: 'noodleseed-customer-api',
|
|
30
30
|
},
|
|
31
31
|
operations: {
|
|
@@ -53,6 +53,19 @@ const noodleseedApi = connector('noodleseed_app_api')
|
|
|
53
53
|
organizations: '${response.organizations}',
|
|
54
54
|
},
|
|
55
55
|
},
|
|
56
|
+
archive_org_app: {
|
|
57
|
+
type: 'action',
|
|
58
|
+
method: 'POST',
|
|
59
|
+
path: '/api/organizations/${args.org_id}/apps/${args.app_id}/archive',
|
|
60
|
+
input: z.object({
|
|
61
|
+
org_id: z.string(),
|
|
62
|
+
app_id: z.string(),
|
|
63
|
+
}),
|
|
64
|
+
output: z.object({ archived: z.boolean() }),
|
|
65
|
+
response: {
|
|
66
|
+
archived: '${response.archived}',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
56
69
|
},
|
|
57
70
|
});
|
|
58
71
|
|
|
@@ -73,6 +86,7 @@ export default server(
|
|
|
73
86
|
},
|
|
74
87
|
},
|
|
75
88
|
use: { app_api: noodleseedApi },
|
|
89
|
+
interactions: { confirmationFallback: 'host' },
|
|
76
90
|
auth: customerAuth.oidc({
|
|
77
91
|
issuer: 'https://id.noodleseed.dev',
|
|
78
92
|
audience: 'https://org.cloud.noodleseed.dev/app/mcp',
|
|
@@ -91,7 +105,7 @@ export default server(
|
|
|
91
105
|
},
|
|
92
106
|
}),
|
|
93
107
|
instructions:
|
|
94
|
-
'Direct/federated MCP OIDC demo. The customer IdP proves identity and privately selects the tenant API base URL
|
|
108
|
+
'Direct/federated MCP OIDC demo. The customer IdP proves identity and privately selects the tenant API base URL, while the broker supplies delegated credentials and confirmed actions stay bound to the reviewed route.',
|
|
95
109
|
assistant: embeddedAssistant({
|
|
96
110
|
model: openAICompatible({
|
|
97
111
|
baseUrl: variable('ASSISTANT_MODEL_BASE_URL'),
|
|
@@ -169,5 +183,30 @@ export default server(
|
|
|
169
183
|
};
|
|
170
184
|
},
|
|
171
185
|
}),
|
|
186
|
+
tool('archive_org_app', {
|
|
187
|
+
title: 'Archive organization app',
|
|
188
|
+
description: 'Archive one NoodleSeed.com app through its customer API after confirmation.',
|
|
189
|
+
authorization: {
|
|
190
|
+
requiredScopes: ['org_apps:write'],
|
|
191
|
+
allowedRoles: ['org_admin'],
|
|
192
|
+
},
|
|
193
|
+
input: z.object({
|
|
194
|
+
org_id: z.string().meta({ title: 'Organization' }),
|
|
195
|
+
app_id: z.string().meta({ title: 'App' }),
|
|
196
|
+
}),
|
|
197
|
+
output: z.object({
|
|
198
|
+
archived: z.boolean(),
|
|
199
|
+
}),
|
|
200
|
+
annotations: annotations.openAction({ destructive: false, confirm: true }),
|
|
201
|
+
fulfil({ input, connectors }) {
|
|
202
|
+
const result = connectors.app_api.archiveOrgApp({
|
|
203
|
+
org_id: input.org_id,
|
|
204
|
+
app_id: input.app_id,
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
archived: result.archived,
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
}),
|
|
172
211
|
],
|
|
173
212
|
);
|
|
@@ -41,6 +41,7 @@ describe('customer-auth example', () => {
|
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
});
|
|
44
|
+
expect(manifest.server.interactions).toEqual({ confirmationFallback: 'host' });
|
|
44
45
|
const catalog = app.toConnectorCatalog();
|
|
45
46
|
expect(catalog?.connectors).toHaveLength(1);
|
|
46
47
|
expect(catalog?.connectors[0]?.http).toMatchObject({
|
|
@@ -56,11 +57,11 @@ describe('customer-auth example', () => {
|
|
|
56
57
|
clientSecret: 'CUSTOMER_API_CLIENT_SECRET',
|
|
57
58
|
},
|
|
58
59
|
});
|
|
59
|
-
expect(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
60
|
+
expect(catalog?.connectors[0]?.operations).toMatchObject({
|
|
61
|
+
list_org_apps: { type: 'read' },
|
|
62
|
+
list_organizations: { type: 'read' },
|
|
63
|
+
archive_org_app: { type: 'action', method: 'POST' },
|
|
64
|
+
});
|
|
64
65
|
expect(catalog?.connectors[0]?.http).not.toHaveProperty('allowedOrigins');
|
|
65
66
|
expect(JSON.stringify({ manifest, catalog })).not.toContain('tenant-a.api.noodleseed.dev');
|
|
66
67
|
expect(manifest.tools.find((tool) => tool.name === 'list_org_apps')?.authorization).toEqual({
|
|
@@ -70,5 +71,17 @@ describe('customer-auth example', () => {
|
|
|
70
71
|
expect(
|
|
71
72
|
manifest.tools.find((tool) => tool.name === 'list_my_organizations')?.authorization,
|
|
72
73
|
).toBeUndefined();
|
|
74
|
+
expect(manifest.tools.find((tool) => tool.name === 'archive_org_app')).toMatchObject({
|
|
75
|
+
authorization: {
|
|
76
|
+
requiredScopes: ['org_apps:write'],
|
|
77
|
+
allowedRoles: ['org_admin'],
|
|
78
|
+
},
|
|
79
|
+
annotations: {
|
|
80
|
+
readOnlyHint: false,
|
|
81
|
+
destructiveHint: false,
|
|
82
|
+
openWorldHint: true,
|
|
83
|
+
confirm: true,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
73
86
|
});
|
|
74
87
|
});
|
|
@@ -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.56.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.56.0 hash:efffbf82007f935d -->
|
|
7
7
|
|
|
8
8
|
# publishing-mcp-integrations
|
|
9
9
|
|
|
@@ -115,7 +115,7 @@ That metadata must expose HTTPS `authorization_endpoint`, `token_endpoint`, `jwk
|
|
|
115
115
|
Use a customer endpoint when the verified IdP selects a different API base URL for each SaaS customer. The claim contains the complete base URL; tool input and `${user}` do not select it. Declare one named policy, use that reference as the connector `baseUrl`, and map its claim path in direct OIDC or on every federated issuer:
|
|
116
116
|
|
|
117
117
|
```ts
|
|
118
|
-
import { connector, customerAuth, customerEndpoint, secret, server, tool, variable, z } from '@noodleseed/one';
|
|
118
|
+
import { annotations, connector, customerAuth, customerEndpoint, secret, server, tool, variable, z } from '@noodleseed/one';
|
|
119
119
|
|
|
120
120
|
const customerApi = customerEndpoint('customer_api', {
|
|
121
121
|
allowedHttpsHostSuffixes: ['api.noodleseed.dev'],
|
|
@@ -137,6 +137,13 @@ const api = connector('customer_api_connector').version('1.0.0').http({
|
|
|
137
137
|
input: z.object({}),
|
|
138
138
|
output: z.object({ records: z.array(z.unknown()).max(100) }),
|
|
139
139
|
},
|
|
140
|
+
archive_record: {
|
|
141
|
+
type: 'action',
|
|
142
|
+
method: 'POST',
|
|
143
|
+
path: '/records/${args.record_id}/archive',
|
|
144
|
+
input: z.object({ record_id: z.string() }),
|
|
145
|
+
output: z.object({ archived: z.boolean() }),
|
|
146
|
+
},
|
|
140
147
|
},
|
|
141
148
|
});
|
|
142
149
|
|
|
@@ -146,6 +153,7 @@ export default server(
|
|
|
146
153
|
title: 'Customer records',
|
|
147
154
|
version: '1.0.0',
|
|
148
155
|
use: { api },
|
|
156
|
+
interactions: { confirmationFallback: 'host' },
|
|
149
157
|
auth: customerAuth.oidc({
|
|
150
158
|
issuer: 'https://id.noodleseed.dev',
|
|
151
159
|
audience: 'https://org.cloud.noodleseed.dev/app/mcp',
|
|
@@ -166,17 +174,29 @@ export default server(
|
|
|
166
174
|
return { records: result.records };
|
|
167
175
|
},
|
|
168
176
|
}),
|
|
177
|
+
tool('archive_record', {
|
|
178
|
+
description: 'Archive one record for the signed-in customer.',
|
|
179
|
+
input: z.object({ record_id: z.string() }),
|
|
180
|
+
output: z.object({ archived: z.boolean() }),
|
|
181
|
+
annotations: annotations.openAction({ destructive: false, confirm: true }),
|
|
182
|
+
fulfil({ input, connectors }) {
|
|
183
|
+
const result = connectors.api.archiveRecord({ record_id: input.record_id });
|
|
184
|
+
return { archived: result.archived };
|
|
185
|
+
},
|
|
186
|
+
}),
|
|
169
187
|
],
|
|
170
188
|
);
|
|
171
189
|
```
|
|
172
190
|
|
|
173
191
|
`customerEndpoint` accepts exactly one non-empty policy arm: exact HTTPS origins, or HTTPS hostname suffixes. Exact policies may authorize an explicit non-default port; suffix policies allow port 443 and match only the exact host or dot-boundary subdomains. Do not add connector `allowedOrigins` to a customer-routed connector. Its fixed credential/token endpoints are validated independently and cannot come from caller claims.
|
|
174
192
|
|
|
193
|
+
On a bidirectional MCP transport whose client negotiated form elicitation, Noodle sends the standard confirmation form. The current stateless hosted MCP transport cannot initiate that exchange, so the example explicitly declares `server.interactions.confirmationFallback: 'host'`. That fallback trusts the MCP host to have collected native write approval before the tool call reaches Noodle; it is never inferred from client identity and does not replace authentication, authorization, policy, or accurate action/destructive annotations. Omit it when connected hosts are not trusted to provide that approval; confirmation then fails closed with `interaction_unavailable` when the standard exchange is unavailable.
|
|
194
|
+
|
|
175
195
|
Every federated issuer must repeat every endpoint key used by the app, although each issuer may choose a different claim path. Endpoint names use lowercase letters, numbers, and underscores. Resolved claims must be exact absolute HTTPS URLs of at most 2,048 UTF-8 bytes with no userinfo, query, fragment, IP literal, special-use host, or unsafe whitespace/control characters. The runtime preserves a canonical optional base path.
|
|
176
196
|
|
|
177
|
-
Resolved customer URLs are private routing authority: they never enter the manifest/artifact, `${user}`, logs, model output, widgets, confirmation review, cache keys, or delegated-token-exchange assertions. Routed
|
|
197
|
+
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`.
|
|
178
198
|
|
|
179
|
-
At runtime,
|
|
199
|
+
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` remains based only on roles and scopes, so route availability neither reveals tenant topology nor changes the existing authorization filter.
|
|
180
200
|
|
|
181
201
|
## Per-tool authorization
|
|
182
202
|
|
|
@@ -67,9 +67,10 @@ Run `noodle validate` (add `--json` for the machine-readable envelope, `--fix-pr
|
|
|
67
67
|
| `customer_endpoint_mapping_required` | Add the endpoint key at the cited auth routing path; every direct/federated issuer must map every customer endpoint used by the app. |
|
|
68
68
|
| `customer_endpoint_unknown_mapping` | Remove the unknown or unused auth routing key, or use that exact declared `customerEndpoint` key from a reachable connector operation. |
|
|
69
69
|
| `customer_endpoint_bridge_unsupported` | Replace the Firebase/Microsoft bridge with direct or federated OIDC before using auth-derived customer connector endpoints. |
|
|
70
|
-
| `customer_endpoint_action_unsupported` |
|
|
70
|
+
| `customer_endpoint_action_unsupported` | Set exact `annotations.confirm: true` on the enclosing tool, or keep the customer-routed operation read-only; action hints alone do not enable confirmation. |
|
|
71
71
|
| `customer_endpoint_surface_unsupported` | Move the customer-routed call into a tool fulfilment; routed resources, prompts, and ambient providers are unsupported. |
|
|
72
72
|
| `customer_endpoint_credential_source_unsupported` | Remove the manifest connection binding; a customer-routed connector uses its declared delegated token exchange auth or no auth. |
|
|
73
73
|
| `customer_endpoint_policy_conflict` | Give every reachable declaration of this endpoint key one identical policy, or rename keys whose allowed origins differ. |
|
|
74
|
+
| `customer_endpoint_routing_inconsistent` | Regenerate the connector catalog so every action route includes all of its ordinary customer endpoint dependencies. |
|
|
74
75
|
| `unused_connector_alias` | A declared connector alias is never called; remove the unused `use` entry or wire it into a tool. |
|
|
75
76
|
| `arg_mismatch` | A connector call is missing or adds arguments; match the operation signature under `expected`/`got`. |
|
|
@@ -14,7 +14,7 @@ Paths are relative to this skill directory. Assets (images/fonts) are omitted fr
|
|
|
14
14
|
| `acme-discovery` | Top-of-funnel discovery→handoff: a discovery carousel, a `create_handoff` deep link, and a design-first UX spec + wireframe. | `examples/acme-discovery/src/server.ts` + `design/` |
|
|
15
15
|
| `acme-tasks` | A two-way productivity app designed around its top-3 prioritized flows (capture/prioritize/complete), with a design-first flow spec + wireframe. | `examples/acme-tasks/src/server.ts` + `design/` |
|
|
16
16
|
| `acme-bistro` | End-to-end ordering with a payment-only handoff; ships a gold-standard `design/` set (UX doc, wireframe with compliance audit, API contract). | `examples/acme-bistro/src/server.ts` + `design/` |
|
|
17
|
-
| `customer-auth` | End-user
|
|
17
|
+
| `customer-auth` | End-user OIDC, private customer API routing, route-bound confirmed actions, roles/scopes, and delegated credentials. | `examples/customer-auth/src/server.ts` |
|
|
18
18
|
| `gmail-multi-account` | One curated Gmail connector reused by two account bindings, canonical account arrays, exact mutation confirmation, and an accompanying personal-automation skill. | `examples/gmail-multi-account/src/server.ts` |
|
|
19
19
|
| `google-bigquery` | Keyless Google Workload Identity Federation with optional service-account impersonation, a BigQuery REST connector, and complete developer/operator setup. | `examples/google-bigquery/src/server.ts` |
|
|
20
20
|
|
|
@@ -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.
|
|
6
|
+
<!-- noodle-skill version:0.56.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.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:6ef6ef551e26b78e -->
|
|
7
7
|
|
|
8
8
|
# verifying-mcp-delivery
|
|
9
9
|
|
package/skills/codex/SKILL.md
CHANGED
|
@@ -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.56.0 hash:ec5bfcd0d8165205 -->
|
|
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.56.0 hash:0b2fd8c7e43fc69f -->
|
|
7
7
|
|
|
8
8
|
# authoring-mcp-servers
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: building-mcp-apps
|
|
|
3
3
|
description: "Use when a Noodle Seed MCP App, widget, interactive card, visual interaction, or host-visible UI is the primary requested outcome."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:f7fa54992c8d7692 -->
|
|
7
7
|
|
|
8
8
|
# building-mcp-apps
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: connecting-apis-to-mcp
|
|
|
3
3
|
description: "Use when credentials, an API URL, an OpenAPI document, or an observed response must become real Noodle Seed MCP behavior."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:1e86b8704f407bd3 -->
|
|
7
7
|
|
|
8
8
|
# connecting-apis-to-mcp
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: debugging-mcp-delivery
|
|
|
3
3
|
description: "Use when an existing Noodle Seed MCP project has a concrete validation, runtime, connector, App, host, deployment, or production failure."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.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.
|
|
6
|
+
<!-- noodle-skill version:0.56.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.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:76cce86729cffbee -->
|
|
7
7
|
|
|
8
8
|
# designing-mcp-products
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: embedding-mcp-assistants
|
|
|
3
3
|
description: "Use when embedding a Noodle assistant into an existing SaaS or web application with browser, identity, session, and credential boundaries."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.56.0 hash:cc54a67f21c0ecdb -->
|
|
7
7
|
|
|
8
8
|
# embedding-mcp-assistants
|
|
9
9
|
|