@noodleseed/agent-kit 0.48.2 → 0.50.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 +38 -4
- package/skills/claude-code/examples/customer-auth/src/server.ts +5 -0
- package/skills/claude-code/examples/customer-auth/test/server.test.ts +13 -0
- 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 -0
- package/skills/claude-code/references/embedded-assistant.md +17 -4
- package/skills/claude-code/references/troubleshooting.md +7 -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/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 +38 -4
- package/skills/codex/examples/customer-auth/src/server.ts +5 -0
- package/skills/codex/examples/customer-auth/test/server.test.ts +13 -0
- 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 -0
- package/skills/codex/references/embedded-assistant.md +17 -4
- package/skills/codex/references/troubleshooting.md +7 -0
- 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.50.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.50.0 hash:cd6ca0d915e6acb9 -->
|
|
7
7
|
|
|
8
8
|
# Noodle Seed
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: authoring-mcp-servers
|
|
|
3
3
|
description: "Use when creating or extending a headless Noodle Seed MCP server, tool, resource, prompt, or typed model-facing capability."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.50.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.50.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.50.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.50.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.50.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.50.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.50.0 hash:cc54a67f21c0ecdb -->
|
|
7
7
|
|
|
8
8
|
# embedding-mcp-assistants
|
|
9
9
|
|
|
@@ -15,7 +15,9 @@ surface for org discovery:
|
|
|
15
15
|
|
|
16
16
|
- `list_my_organizations` lists the NoodleSeed.com organizations the signed-in customer belongs to (no
|
|
17
17
|
arguments — the org set comes from the verified customer session).
|
|
18
|
-
- `list_org_apps` lists apps for one of those organizations through the dev app API.
|
|
18
|
+
- `list_org_apps` lists apps for one of those organizations through the dev app API. It is visible and
|
|
19
|
+
callable only when the verified customer has the `org_apps:read` scope and either the `org_admin` or
|
|
20
|
+
`org_member` role.
|
|
19
21
|
|
|
20
22
|
The two tools chain: `list_my_organizations` surfaces the `org_id`s the customer can act on, and
|
|
21
23
|
`list_org_apps` takes one of those `org_id`s. There is no NoodleSeed-specific SDK helper. The downstream API
|
|
@@ -34,6 +36,19 @@ bounded read-only GET checks and never register a client. A successful
|
|
|
34
36
|
`noodle deploy --access customers` reports the same findings as nonblocking warnings; the application team
|
|
35
37
|
repairs the issuer rather than adding a Noodle OAuth proxy.
|
|
36
38
|
|
|
39
|
+
Adding the embedded assistant does not choose or rewrite MCP customer auth. Inspect the exact active
|
|
40
|
+
deployment before changing configuration:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
noodle deployments list --org <org> --app <app> --env <env> --json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This Firebase bridge intentionally advertises the Noodle authorization server. A direct or federated
|
|
47
|
+
replacement must advertise its configured tenant issuer. If the exact active direct/federated `customers`
|
|
48
|
+
deployment instead advertises the platform issuer, report `customer_auth_state_inconsistent` with only the
|
|
49
|
+
endpoint, deployment ID, server version, and sanitized protected-resource metadata. Do not share tokens or
|
|
50
|
+
secrets, proxy or rewrite metadata, rotate credentials, or redeploy repeatedly to conceal the mismatch.
|
|
51
|
+
|
|
37
52
|
During MCP OAuth login, Noodle Cloud hosts the Firebase bridge page at
|
|
38
53
|
`https://cloud.noodleseed.dev/oauth/customer/firebase/authorize`. The customer app does not add an
|
|
39
54
|
authorization route. The SaaS operator only configures Firebase Auth to allow the Noodle Cloud origin, and
|
|
@@ -61,9 +76,10 @@ auth: customerAuth.firebase({
|
|
|
61
76
|
email: 'email',
|
|
62
77
|
name: 'name',
|
|
63
78
|
tenant: 'firebase.tenant',
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
orgs: 'claims.orgs',
|
|
80
|
+
roles: 'claims.roles',
|
|
81
|
+
scopes: 'claims.scopes',
|
|
82
|
+
},
|
|
67
83
|
}),
|
|
68
84
|
```
|
|
69
85
|
|
|
@@ -79,6 +95,24 @@ auth: {
|
|
|
79
95
|
},
|
|
80
96
|
```
|
|
81
97
|
|
|
98
|
+
The mapped `roles` and `scopes` paths are read only after Firebase verifies the ID token. The restricted
|
|
99
|
+
tool declares its rule beside the rest of its public contract:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
tool('list_org_apps', {
|
|
103
|
+
authorization: {
|
|
104
|
+
requiredScopes: ['org_apps:read'],
|
|
105
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
106
|
+
},
|
|
107
|
+
// input, output, and fulfilment...
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Every required scope must be present and at least one allowed role must match. When both lists are declared,
|
|
112
|
+
both conditions apply. A restricted tool is omitted from `tools/list` for an ineligible customer and a
|
|
113
|
+
direct `tools/call` still fails closed. Do not use unverified page context, request arguments, connector
|
|
114
|
+
responses, or an arbitrary generic `roles` claim as authorization input.
|
|
115
|
+
|
|
82
116
|
Tool code calls the connector normally:
|
|
83
117
|
|
|
84
118
|
```ts
|
|
@@ -80,6 +80,7 @@ export default server(
|
|
|
80
80
|
tenant: 'firebase.tenant',
|
|
81
81
|
orgs: 'claims.orgs',
|
|
82
82
|
roles: 'claims.roles',
|
|
83
|
+
scopes: 'claims.scopes',
|
|
83
84
|
},
|
|
84
85
|
}),
|
|
85
86
|
instructions:
|
|
@@ -117,6 +118,10 @@ export default server(
|
|
|
117
118
|
tool('list_org_apps', {
|
|
118
119
|
title: 'List organization apps',
|
|
119
120
|
description: 'List NoodleSeed.com apps for an organization from the dev app API.',
|
|
121
|
+
authorization: {
|
|
122
|
+
requiredScopes: ['org_apps:read'],
|
|
123
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
124
|
+
},
|
|
120
125
|
input: z.object({
|
|
121
126
|
org_id: z.string().meta({ title: 'Organization' }),
|
|
122
127
|
skip: z.number().int().min(0).optional().meta({ title: 'Starting item' }),
|
|
@@ -24,9 +24,22 @@ describe('customer-auth example', () => {
|
|
|
24
24
|
colorScheme: 'auto',
|
|
25
25
|
});
|
|
26
26
|
expect(manifest.server.auth).toMatchObject({
|
|
27
|
+
kind: 'bridge',
|
|
28
|
+
provider: 'firebase',
|
|
27
29
|
projectId: '${env.FIREBASE_PROJECT_ID}',
|
|
28
30
|
apiKey: '${env.FIREBASE_WEB_API_KEY}',
|
|
29
31
|
authDomain: '${env.FIREBASE_AUTH_DOMAIN}',
|
|
32
|
+
user: {
|
|
33
|
+
roles: 'claims.roles',
|
|
34
|
+
scopes: 'claims.scopes',
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
expect(manifest.tools.find((tool) => tool.name === 'list_org_apps')?.authorization).toEqual({
|
|
38
|
+
requiredScopes: ['org_apps:read'],
|
|
39
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
30
40
|
});
|
|
41
|
+
expect(
|
|
42
|
+
manifest.tools.find((tool) => tool.name === 'list_my_organizations')?.authorization,
|
|
43
|
+
).toBeUndefined();
|
|
31
44
|
});
|
|
32
45
|
});
|
|
@@ -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.50.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.50.0 hash:efffbf82007f935d -->
|
|
7
7
|
|
|
8
8
|
# publishing-mcp-integrations
|
|
9
9
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- Connectors
|
|
9
9
|
- HTTP connector example (full server)
|
|
10
10
|
- Customer OAuth for remote MCP clients
|
|
11
|
+
- Per-tool authorization
|
|
11
12
|
- Delegated downstream auth (call your API as the signed-in user)
|
|
12
13
|
- Invocation context
|
|
13
14
|
- Compute connector example
|
|
@@ -108,6 +109,28 @@ For `customerAuth.oidc(...)` and `.federatedOidc(...)`, the application develope
|
|
|
108
109
|
|
|
109
110
|
That metadata must expose HTTPS `authorization_endpoint`, `token_endpoint`, `jwks_uri`, and RFC 7591 `registration_endpoint`; advertise authorization-code and refresh-token grants, Dynamic Client Registration, PKCE with `code_challenge_methods_supported: ["S256"]`, and public clients with `token_endpoint_auth_methods_supported: ["none"]`. Implement RFC 8707 `resource`, mint access-token `aud` for the exact MCP resource URL, and publish only public signing keys in JWKS. Run `noodle auth doctor src/server.ts`; its issuer-readiness probes perform bounded read-only GET checks and never register a client. A successful `noodle deploy --access customers` reports the same readiness without turning a diagnostic failure into a failed deployment.
|
|
110
111
|
|
|
112
|
+
## Per-tool authorization
|
|
113
|
+
|
|
114
|
+
Keep endpoint authentication in `customerAuth.*(...)`, then narrow individual tools with the optional typed `authorization` rule. Every `requiredScopes` value is required; any one `allowedRoles` value is sufficient; when both lists are present, both conditions apply. Omit `authorization` for an unrestricted tool. Do not invent a policy expression language or infer authorization from tool arguments, page context, connector output, email domains, or other unverified data.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
auth: customerAuth.oidc({
|
|
118
|
+
issuer: 'https://id.example.com',
|
|
119
|
+
audience: 'https://api.example.com/mcp',
|
|
120
|
+
claims: { roles: 'permissions.roles', scopes: 'permissions.scopes' },
|
|
121
|
+
}),
|
|
122
|
+
|
|
123
|
+
tool('list_org_apps', {
|
|
124
|
+
authorization: {
|
|
125
|
+
requiredScopes: ['org_apps:read'],
|
|
126
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
127
|
+
},
|
|
128
|
+
// input, output, and fulfilment...
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
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. Eligible tools remain in authored order in `tools/list`; ineligible tools are omitted and a guessed direct call is still denied before argument validation or connector execution. Scope denials use MCP OAuth step-up metadata without disclosing role names.
|
|
133
|
+
|
|
111
134
|
## Delegated downstream auth (call your API as the signed-in user)
|
|
112
135
|
|
|
113
136
|
Use delegated connector auth when the downstream API must enforce its own per-user authorization — a shared service credential plus a forwarded user id would bypass it. Three shapes exist; pick by who owns the downstream:
|
|
@@ -110,7 +110,9 @@ Do not put these model values in the embedding SaaS environment. A production de
|
|
|
110
110
|
|
|
111
111
|
## Access modes and customer auth
|
|
112
112
|
|
|
113
|
-
Session exchange authenticates with the backend client credentials, so the embed works under any `--access` mode.
|
|
113
|
+
Session exchange authenticates with the backend client credentials, so the embed works under any `--access` mode. The assistant does not select direct MCP access or protected-resource discovery. If protected-resource metadata advertises an unexpected issuer, inspect the exact active deployment before changing auth by following `references/troubleshooting.md`.
|
|
114
|
+
|
|
115
|
+
Add `--access customers` only when verified end customers should also call the MCP endpoint directly. That mode requires `server.auth`; `noodle deploy` preflights the rule locally and fails with `server_auth_required` before contacting the service. Fix by adding auth to server options:
|
|
114
116
|
|
|
115
117
|
```ts
|
|
116
118
|
auth: customerAuth.federatedOidc({
|
|
@@ -154,7 +156,12 @@ export async function POST(request: Request) {
|
|
|
154
156
|
clientId: process.env.NOODLE_ASSISTANT_CLIENT_ID!,
|
|
155
157
|
clientSecret: process.env.NOODLE_ASSISTANT_CLIENT_SECRET!,
|
|
156
158
|
origin: process.env.PUBLIC_APP_ORIGIN!,
|
|
157
|
-
user: {
|
|
159
|
+
user: {
|
|
160
|
+
id: user.id,
|
|
161
|
+
email: user.email,
|
|
162
|
+
roles: user.roles,
|
|
163
|
+
scopes: user.scopes,
|
|
164
|
+
},
|
|
158
165
|
context,
|
|
159
166
|
// Saved, backend-verified user preferences outrank browser hints.
|
|
160
167
|
preferences: { locale: user.locale, timeZone: user.timeZone },
|
|
@@ -163,7 +170,7 @@ export async function POST(request: Request) {
|
|
|
163
170
|
}
|
|
164
171
|
```
|
|
165
172
|
|
|
166
|
-
Authenticate before exchange. Source `origin` from trusted server configuration or strictly match the request origin against the same exact allowlist; never accept an arbitrary request header. Treat page context as untrusted model context, never authorization. Forward the helper response unchanged.
|
|
173
|
+
Authenticate before exchange. Pass backend-verified `user.roles` and OAuth-style `user.scopes` separately; they govern the same per-tool authorization rules as verified MCP bearer claims. Source `origin` from trusted server configuration or strictly match the request origin against the same exact allowlist; never accept an arbitrary request header. Treat page context as untrusted model context, never authorization. Forward the helper response unchanged.
|
|
167
174
|
|
|
168
175
|
`serviceUrl` is the Noodle Seed control-plane base URL: the value `noodle assistant clients create` prints, also stored as `serviceUrl` in `deployment.json`. It is NOT the deployment MCP endpoint (`url`, which ends in `/v1/mcp` and rejects session exchange). Never probe or guess endpoints with real credentials.
|
|
169
176
|
|
|
@@ -204,7 +211,13 @@ The embedding developer defines what authenticated session context the assistant
|
|
|
204
211
|
```ts
|
|
205
212
|
const session = await createAssistantSession({
|
|
206
213
|
serviceUrl, clientId, clientSecret, origin,
|
|
207
|
-
user: {
|
|
214
|
+
user: {
|
|
215
|
+
id: user.id,
|
|
216
|
+
email: user.email,
|
|
217
|
+
name: user.name,
|
|
218
|
+
roles: user.roles,
|
|
219
|
+
scopes: user.scopes,
|
|
220
|
+
},
|
|
208
221
|
claims: { displayName: user.name, accountTier: account.tier, region: account.region },
|
|
209
222
|
});
|
|
210
223
|
```
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
## Contents
|
|
4
4
|
|
|
5
5
|
- First moves
|
|
6
|
+
- Customer-auth metadata
|
|
6
7
|
- Symptom map
|
|
7
8
|
|
|
8
9
|
## First moves
|
|
@@ -11,6 +12,12 @@ Re-run the local gates before debugging in-host: `noodle validate`, `noodle chec
|
|
|
11
12
|
|
|
12
13
|
For protocol/conformance checks, the headless harness is `@mcpjam/cli`, not a `noodle` subcommand. Use it against a local `noodle dev` URL without an access token, or against hosted URLs through the host/OAuth flow printed by `noodle connect`.
|
|
13
14
|
|
|
15
|
+
## Customer-auth metadata
|
|
16
|
+
|
|
17
|
+
Adding `embeddedAssistant(...)` does not select the MCP access mode or authorization server. Before changing auth, inspect the exact active deployment with `noodle deployments list --org <org> --app <app> --env <env> --json` and match its active deployment ID, server version, and access mode to the endpoint being tested.
|
|
18
|
+
|
|
19
|
+
For `customers` access, Direct or federated customer auth must advertise the configured tenant issuer; a managed Noodle bridge must advertise the Noodle authorization server. Owner-only access advertises the platform authorization server. If a direct or federated `customers` deployment still advertises the platform issuer, treat it as `customer_auth_state_inconsistent` and escalate with the endpoint, active deployment ID, and sanitized protected-resource metadata. Do not proxy, rewrite, rotate, or redeploy to hide the mismatch. Never share bearer tokens, refresh tokens, client secrets, or credential files.
|
|
20
|
+
|
|
14
21
|
## Symptom map
|
|
15
22
|
|
|
16
23
|
| Symptom | Likely cause | Fix |
|
|
@@ -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.50.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.50.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.50.0 hash:cd6ca0d915e6acb9 -->
|
|
7
7
|
|
|
8
8
|
# Noodle Seed
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: authoring-mcp-servers
|
|
|
3
3
|
description: "Use when creating or extending a headless Noodle Seed MCP server, tool, resource, prompt, or typed model-facing capability."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- noodle-skill version:0.
|
|
6
|
+
<!-- noodle-skill version:0.50.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.50.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.50.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.50.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.50.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.50.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.50.0 hash:cc54a67f21c0ecdb -->
|
|
7
7
|
|
|
8
8
|
# embedding-mcp-assistants
|
|
9
9
|
|
|
@@ -15,7 +15,9 @@ surface for org discovery:
|
|
|
15
15
|
|
|
16
16
|
- `list_my_organizations` lists the NoodleSeed.com organizations the signed-in customer belongs to (no
|
|
17
17
|
arguments — the org set comes from the verified customer session).
|
|
18
|
-
- `list_org_apps` lists apps for one of those organizations through the dev app API.
|
|
18
|
+
- `list_org_apps` lists apps for one of those organizations through the dev app API. It is visible and
|
|
19
|
+
callable only when the verified customer has the `org_apps:read` scope and either the `org_admin` or
|
|
20
|
+
`org_member` role.
|
|
19
21
|
|
|
20
22
|
The two tools chain: `list_my_organizations` surfaces the `org_id`s the customer can act on, and
|
|
21
23
|
`list_org_apps` takes one of those `org_id`s. There is no NoodleSeed-specific SDK helper. The downstream API
|
|
@@ -34,6 +36,19 @@ bounded read-only GET checks and never register a client. A successful
|
|
|
34
36
|
`noodle deploy --access customers` reports the same findings as nonblocking warnings; the application team
|
|
35
37
|
repairs the issuer rather than adding a Noodle OAuth proxy.
|
|
36
38
|
|
|
39
|
+
Adding the embedded assistant does not choose or rewrite MCP customer auth. Inspect the exact active
|
|
40
|
+
deployment before changing configuration:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
noodle deployments list --org <org> --app <app> --env <env> --json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This Firebase bridge intentionally advertises the Noodle authorization server. A direct or federated
|
|
47
|
+
replacement must advertise its configured tenant issuer. If the exact active direct/federated `customers`
|
|
48
|
+
deployment instead advertises the platform issuer, report `customer_auth_state_inconsistent` with only the
|
|
49
|
+
endpoint, deployment ID, server version, and sanitized protected-resource metadata. Do not share tokens or
|
|
50
|
+
secrets, proxy or rewrite metadata, rotate credentials, or redeploy repeatedly to conceal the mismatch.
|
|
51
|
+
|
|
37
52
|
During MCP OAuth login, Noodle Cloud hosts the Firebase bridge page at
|
|
38
53
|
`https://cloud.noodleseed.dev/oauth/customer/firebase/authorize`. The customer app does not add an
|
|
39
54
|
authorization route. The SaaS operator only configures Firebase Auth to allow the Noodle Cloud origin, and
|
|
@@ -61,9 +76,10 @@ auth: customerAuth.firebase({
|
|
|
61
76
|
email: 'email',
|
|
62
77
|
name: 'name',
|
|
63
78
|
tenant: 'firebase.tenant',
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
orgs: 'claims.orgs',
|
|
80
|
+
roles: 'claims.roles',
|
|
81
|
+
scopes: 'claims.scopes',
|
|
82
|
+
},
|
|
67
83
|
}),
|
|
68
84
|
```
|
|
69
85
|
|
|
@@ -79,6 +95,24 @@ auth: {
|
|
|
79
95
|
},
|
|
80
96
|
```
|
|
81
97
|
|
|
98
|
+
The mapped `roles` and `scopes` paths are read only after Firebase verifies the ID token. The restricted
|
|
99
|
+
tool declares its rule beside the rest of its public contract:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
tool('list_org_apps', {
|
|
103
|
+
authorization: {
|
|
104
|
+
requiredScopes: ['org_apps:read'],
|
|
105
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
106
|
+
},
|
|
107
|
+
// input, output, and fulfilment...
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Every required scope must be present and at least one allowed role must match. When both lists are declared,
|
|
112
|
+
both conditions apply. A restricted tool is omitted from `tools/list` for an ineligible customer and a
|
|
113
|
+
direct `tools/call` still fails closed. Do not use unverified page context, request arguments, connector
|
|
114
|
+
responses, or an arbitrary generic `roles` claim as authorization input.
|
|
115
|
+
|
|
82
116
|
Tool code calls the connector normally:
|
|
83
117
|
|
|
84
118
|
```ts
|
|
@@ -80,6 +80,7 @@ export default server(
|
|
|
80
80
|
tenant: 'firebase.tenant',
|
|
81
81
|
orgs: 'claims.orgs',
|
|
82
82
|
roles: 'claims.roles',
|
|
83
|
+
scopes: 'claims.scopes',
|
|
83
84
|
},
|
|
84
85
|
}),
|
|
85
86
|
instructions:
|
|
@@ -117,6 +118,10 @@ export default server(
|
|
|
117
118
|
tool('list_org_apps', {
|
|
118
119
|
title: 'List organization apps',
|
|
119
120
|
description: 'List NoodleSeed.com apps for an organization from the dev app API.',
|
|
121
|
+
authorization: {
|
|
122
|
+
requiredScopes: ['org_apps:read'],
|
|
123
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
124
|
+
},
|
|
120
125
|
input: z.object({
|
|
121
126
|
org_id: z.string().meta({ title: 'Organization' }),
|
|
122
127
|
skip: z.number().int().min(0).optional().meta({ title: 'Starting item' }),
|
|
@@ -24,9 +24,22 @@ describe('customer-auth example', () => {
|
|
|
24
24
|
colorScheme: 'auto',
|
|
25
25
|
});
|
|
26
26
|
expect(manifest.server.auth).toMatchObject({
|
|
27
|
+
kind: 'bridge',
|
|
28
|
+
provider: 'firebase',
|
|
27
29
|
projectId: '${env.FIREBASE_PROJECT_ID}',
|
|
28
30
|
apiKey: '${env.FIREBASE_WEB_API_KEY}',
|
|
29
31
|
authDomain: '${env.FIREBASE_AUTH_DOMAIN}',
|
|
32
|
+
user: {
|
|
33
|
+
roles: 'claims.roles',
|
|
34
|
+
scopes: 'claims.scopes',
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
expect(manifest.tools.find((tool) => tool.name === 'list_org_apps')?.authorization).toEqual({
|
|
38
|
+
requiredScopes: ['org_apps:read'],
|
|
39
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
30
40
|
});
|
|
41
|
+
expect(
|
|
42
|
+
manifest.tools.find((tool) => tool.name === 'list_my_organizations')?.authorization,
|
|
43
|
+
).toBeUndefined();
|
|
31
44
|
});
|
|
32
45
|
});
|
|
@@ -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.50.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.50.0 hash:efffbf82007f935d -->
|
|
7
7
|
|
|
8
8
|
# publishing-mcp-integrations
|
|
9
9
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- Connectors
|
|
9
9
|
- HTTP connector example (full server)
|
|
10
10
|
- Customer OAuth for remote MCP clients
|
|
11
|
+
- Per-tool authorization
|
|
11
12
|
- Delegated downstream auth (call your API as the signed-in user)
|
|
12
13
|
- Invocation context
|
|
13
14
|
- Compute connector example
|
|
@@ -108,6 +109,28 @@ For `customerAuth.oidc(...)` and `.federatedOidc(...)`, the application develope
|
|
|
108
109
|
|
|
109
110
|
That metadata must expose HTTPS `authorization_endpoint`, `token_endpoint`, `jwks_uri`, and RFC 7591 `registration_endpoint`; advertise authorization-code and refresh-token grants, Dynamic Client Registration, PKCE with `code_challenge_methods_supported: ["S256"]`, and public clients with `token_endpoint_auth_methods_supported: ["none"]`. Implement RFC 8707 `resource`, mint access-token `aud` for the exact MCP resource URL, and publish only public signing keys in JWKS. Run `noodle auth doctor src/server.ts`; its issuer-readiness probes perform bounded read-only GET checks and never register a client. A successful `noodle deploy --access customers` reports the same readiness without turning a diagnostic failure into a failed deployment.
|
|
110
111
|
|
|
112
|
+
## Per-tool authorization
|
|
113
|
+
|
|
114
|
+
Keep endpoint authentication in `customerAuth.*(...)`, then narrow individual tools with the optional typed `authorization` rule. Every `requiredScopes` value is required; any one `allowedRoles` value is sufficient; when both lists are present, both conditions apply. Omit `authorization` for an unrestricted tool. Do not invent a policy expression language or infer authorization from tool arguments, page context, connector output, email domains, or other unverified data.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
auth: customerAuth.oidc({
|
|
118
|
+
issuer: 'https://id.example.com',
|
|
119
|
+
audience: 'https://api.example.com/mcp',
|
|
120
|
+
claims: { roles: 'permissions.roles', scopes: 'permissions.scopes' },
|
|
121
|
+
}),
|
|
122
|
+
|
|
123
|
+
tool('list_org_apps', {
|
|
124
|
+
authorization: {
|
|
125
|
+
requiredScopes: ['org_apps:read'],
|
|
126
|
+
allowedRoles: ['org_admin', 'org_member'],
|
|
127
|
+
},
|
|
128
|
+
// input, output, and fulfilment...
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
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. Eligible tools remain in authored order in `tools/list`; ineligible tools are omitted and a guessed direct call is still denied before argument validation or connector execution. Scope denials use MCP OAuth step-up metadata without disclosing role names.
|
|
133
|
+
|
|
111
134
|
## Delegated downstream auth (call your API as the signed-in user)
|
|
112
135
|
|
|
113
136
|
Use delegated connector auth when the downstream API must enforce its own per-user authorization — a shared service credential plus a forwarded user id would bypass it. Three shapes exist; pick by who owns the downstream:
|