@noodleseed/agent-kit 0.42.0 → 0.43.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 +273 -257
- package/package.json +1 -1
- package/skills/claude-code/SKILL.md +5 -4
- 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/acme-bistro/src/server.ts +5 -1
- package/skills/claude-code/examples/acme-discovery/src/server.ts +5 -1
- package/skills/claude-code/examples/acme-tasks/src/server.ts +4 -1
- package/skills/claude-code/examples/customer-auth/src/server.ts +5 -1
- package/skills/claude-code/examples/food-ordering/src/server.ts +14 -5
- package/skills/claude-code/examples/gmail-multi-account/src/server.ts +20 -3
- package/skills/claude-code/examples/hello/README.md +4 -2
- package/skills/claude-code/examples/hello/src/server.ts +3 -0
- package/skills/claude-code/examples/weather/src/server.ts +10 -2
- package/skills/claude-code/publishing-mcp-integrations/SKILL.md +1 -1
- package/skills/claude-code/references/authoring-workflow.md +1 -60
- package/skills/claude-code/references/build-an-mcp-server.md +1 -1
- package/skills/claude-code/references/cli-commands.md +1 -1
- package/skills/claude-code/references/connect-an-api.md +4 -0
- package/skills/claude-code/references/embedded-assistant.md +3 -3
- package/skills/claude-code/references/feedback.md +11 -9
- package/skills/claude-code/references/tool-design.md +103 -0
- package/skills/claude-code/reporting-noodle-feedback/SKILL.md +6 -6
- package/skills/claude-code/verifying-mcp-delivery/SKILL.md +1 -1
- package/skills/codex/SKILL.md +5 -4
- 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/acme-bistro/src/server.ts +5 -1
- package/skills/codex/examples/acme-discovery/src/server.ts +5 -1
- package/skills/codex/examples/acme-tasks/src/server.ts +4 -1
- package/skills/codex/examples/customer-auth/src/server.ts +5 -1
- package/skills/codex/examples/food-ordering/src/server.ts +14 -5
- package/skills/codex/examples/gmail-multi-account/src/server.ts +20 -3
- package/skills/codex/examples/hello/README.md +4 -2
- package/skills/codex/examples/hello/src/server.ts +3 -0
- package/skills/codex/examples/weather/src/server.ts +10 -2
- package/skills/codex/publishing-mcp-integrations/SKILL.md +1 -1
- package/skills/codex/references/authoring-workflow.md +1 -60
- package/skills/codex/references/build-an-mcp-server.md +1 -1
- package/skills/codex/references/cli-commands.md +1 -1
- package/skills/codex/references/connect-an-api.md +4 -0
- package/skills/codex/references/embedded-assistant.md +3 -3
- package/skills/codex/references/feedback.md +11 -9
- package/skills/codex/references/tool-design.md +103 -0
- package/skills/codex/reporting-noodle-feedback/SKILL.md +6 -6
- 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.43.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.43.0 hash:cd6ca0d915e6acb9 -->
|
|
7
7
|
|
|
8
8
|
# Noodle Seed
|
|
9
9
|
|
|
@@ -35,7 +35,7 @@ Negative routing examples: “Inspect hosted logs/status” → `inspect-hosted`
|
|
|
35
35
|
| Deploy, configure, connect with writes, change access, or roll back a hosted MCP service when explicitly requested | `deploying-mcp-services` | `references/deploy-and-ops.md` (`references/cli-commands.md`) | The requested hosted state is evidenced without claiming unperformed host or production checks. |
|
|
36
36
|
| Embed a Noodle assistant in an existing SaaS or web application | `embedding-mcp-assistants` | `references/embedded-assistant.md` (`references/authoring-workflow.md`) | The requested embed boundary works with verified identity and credential separation at the tested level. |
|
|
37
37
|
| Prepare or submit an integration to a host directory | `publishing-mcp-integrations` | `references/publishing.md` (`references/app-directory-compliance.md`) | The requested submission evidence is complete and any host-review uncertainty is explicit. |
|
|
38
|
-
| Report a Noodle Seed bug, documentation gap, or product improvement | `reporting-noodle-feedback` | `references/feedback.md` (None) | A sanitized command
|
|
38
|
+
| Report a Noodle Seed bug, documentation gap, or product improvement | `reporting-noodle-feedback` | `references/feedback.md` (None) | A sanitized dry-run preview and exact live command are shown, then one submission occurs only after explicit approval. |
|
|
39
39
|
|
|
40
40
|
## Common machine loop
|
|
41
41
|
|
|
@@ -57,7 +57,8 @@ This is a lookup catalog, not a discovery checklist. Return here only when the s
|
|
|
57
57
|
- `references/cli-commands.md` — every `noodle` command, grouped by area.
|
|
58
58
|
- `references/compile-errors.md` — fix `noodle validate` errors by code.
|
|
59
59
|
- `references/build-an-mcp-server.md` — outcome-first workflow for a focused, tested, model-facing MCP product.
|
|
60
|
-
- `references/authoring-workflow.md` — input paths, fit checks, connector patterns, authentication,
|
|
60
|
+
- `references/authoring-workflow.md` — input paths, fit checks, connector patterns, authentication, invocation context, testing, and managed config.
|
|
61
|
+
- `references/tool-design.md` — intent-shaped tools, titles and annotations, bounded outputs, tool-surface budget, and context provisioning.
|
|
61
62
|
- `references/embedded-assistant.md` — HTTPS origins, managed model config, deploy sequencing, session exchange, browser mounting, and credential boundaries.
|
|
62
63
|
- `references/connect-an-api.md` — secure credentials, probe the live API, model the observed shape, and prove real output.
|
|
63
64
|
- `references/build-an-mcp-app.md` — product-fit, output-boundary, fallback, and evidence workflow for an MCP App.
|
|
@@ -75,7 +76,7 @@ This is a lookup catalog, not a discovery checklist. Return here only when the s
|
|
|
75
76
|
|
|
76
77
|
## Product feedback
|
|
77
78
|
|
|
78
|
-
When you discover a bug, missing capability, misleading doc, or improvement idea, draft one
|
|
79
|
+
When you discover a bug, missing capability, misleading doc, or improvement idea, discover current fields with `noodle commands --json`, draft and sanitize one finding, then run `noodle feedback ... --dry-run --json`. Inspect and show the exact normalized submission, diagnostics, private destination, and POSIX-safely quoted live command. Ask for explicit approval of that exact proposal; do not submit it until approval. Then submit once without `--dry-run`. Follow `references/feedback.md`; never include customer code, secrets, personal data, or identifying project details, and never auto-login or retry-loop.
|
|
79
80
|
|
|
80
81
|
## Safety
|
|
81
82
|
|
|
@@ -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.43.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.43.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.43.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.43.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.43.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.43.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.43.0 hash:5d8f40f904d6ab4b -->
|
|
7
7
|
|
|
8
8
|
# embedding-mcp-assistants
|
|
9
9
|
|
|
@@ -53,13 +53,16 @@ export default server(
|
|
|
53
53
|
},
|
|
54
54
|
[
|
|
55
55
|
tool('show_menu', {
|
|
56
|
+
title: 'Show the menu',
|
|
56
57
|
description: 'Show the Acme Bistro menu and render the ordering widget.',
|
|
57
58
|
annotations: readOnly,
|
|
58
59
|
input: z.object({ customer: z.string().default('Guest') }),
|
|
59
60
|
output: z.object({
|
|
60
61
|
status: z.string(),
|
|
61
62
|
customer: z.string(),
|
|
62
|
-
|
|
63
|
+
// Bounded list: the menu is a fixed catalog, so the ceiling is declared on the shape rather
|
|
64
|
+
// than taken as a pagination input. `noodle check` reports `tool_design_output_bounds`.
|
|
65
|
+
items: z.array(menuItemOutput).max(50),
|
|
63
66
|
}),
|
|
64
67
|
fulfil: ({ input }) => ({
|
|
65
68
|
status: `Acme Bistro menu is ready for ${input.customer}. Build the order here; pay at checkout.`,
|
|
@@ -125,6 +128,7 @@ export default server(
|
|
|
125
128
|
// The only handoff: payment. The widget computes the total (live React) and passes a url-safe cart
|
|
126
129
|
// token + total; the card is entered on Acme's PCI-scoped checkout, never in chat.
|
|
127
130
|
tool('create_checkout', {
|
|
131
|
+
title: 'Create checkout',
|
|
128
132
|
description:
|
|
129
133
|
'Create the Acme Bistro payment checkout link for the current order. Pass a url-safe cart token ' +
|
|
130
134
|
'and the numeric total computed in the widget. Payment happens off-app; the card never reaches this app.',
|
|
@@ -116,6 +116,7 @@ export default server(
|
|
|
116
116
|
},
|
|
117
117
|
[
|
|
118
118
|
tool('discover_getaways', {
|
|
119
|
+
title: 'Discover getaways',
|
|
119
120
|
description:
|
|
120
121
|
'Suggest Acme Getaways destinations for a vibe and month and render a discovery carousel.',
|
|
121
122
|
annotations: readOnly,
|
|
@@ -125,7 +126,9 @@ export default server(
|
|
|
125
126
|
vibe: z.string(),
|
|
126
127
|
month: z.string(),
|
|
127
128
|
travelers: z.number(),
|
|
128
|
-
|
|
129
|
+
// Bounded list: the curated catalog is fixed and small, and the declared ceiling tells the
|
|
130
|
+
// model and host the payload cannot grow. `noodle check` reports `tool_design_output_bounds`.
|
|
131
|
+
options: z.array(destinationOutput).max(20),
|
|
129
132
|
}),
|
|
130
133
|
// The carousel presents Acme's curated catalog; the model narrates which fit the stated vibe.
|
|
131
134
|
// (A tool cannot filter on an input value — that is connector/flow work — so all are returned.)
|
|
@@ -154,6 +157,7 @@ export default server(
|
|
|
154
157
|
},
|
|
155
158
|
}),
|
|
156
159
|
tool('create_handoff', {
|
|
160
|
+
title: 'Create booking handoff',
|
|
157
161
|
description:
|
|
158
162
|
'Create the Acme booking deep link for a chosen destination, carrying the configured trip. ' +
|
|
159
163
|
'Pass the destination id (url-safe slug, e.g. "coral_bay") and its display name.',
|
|
@@ -62,10 +62,13 @@ export default server(
|
|
|
62
62
|
description: 'Show today’s Acme Tasks and render the task-list widget.',
|
|
63
63
|
annotations: readOnly,
|
|
64
64
|
input: z.object({ focus: z.string().default('today') }),
|
|
65
|
+
// Bound the list output. A recorded `fulfil` cannot slice an array, so the honest bound here is
|
|
66
|
+
// a cap on the shape itself; a connector-backed list takes a pagination input instead (see the
|
|
67
|
+
// `weather` example). `noodle check` reports an unbounded array as `tool_design_output_bounds`.
|
|
65
68
|
output: z.object({
|
|
66
69
|
status: z.string(),
|
|
67
70
|
focus: z.string(),
|
|
68
|
-
tasks: z.array(taskOutput),
|
|
71
|
+
tasks: z.array(taskOutput).max(20),
|
|
69
72
|
}),
|
|
70
73
|
fulfil: ({ input }) => ({
|
|
71
74
|
status: `Acme Tasks for ${input.focus}: ${today.length} open items, highest priority first.`,
|
|
@@ -142,8 +142,12 @@ export default server(
|
|
|
142
142
|
description: 'List the NoodleSeed.com organizations the signed-in customer belongs to.',
|
|
143
143
|
contextProvider: true,
|
|
144
144
|
input: z.object({}),
|
|
145
|
+
// The dev app API returns every organization for the signed-in customer in one response, with no
|
|
146
|
+
// page parameter to pass through, so the bound is declared on the shape. A customer belongs to a
|
|
147
|
+
// handful of organizations; `noodle check` reports an unbounded list as
|
|
148
|
+
// `tool_design_output_bounds`.
|
|
145
149
|
output: z.object({
|
|
146
|
-
organizations: z.array(z.unknown()),
|
|
150
|
+
organizations: z.array(z.unknown()).max(100),
|
|
147
151
|
}),
|
|
148
152
|
annotations: annotations.readOnly(),
|
|
149
153
|
fulfil({ connectors }) {
|
|
@@ -132,7 +132,9 @@ const menuItemShape = z.object({
|
|
|
132
132
|
name: z.string(),
|
|
133
133
|
price: z.number(),
|
|
134
134
|
description: z.string(),
|
|
135
|
-
|
|
135
|
+
// Nested lists count toward the output budget too: unbounded modifiers multiply by every item in a
|
|
136
|
+
// menu payload, so the ceiling is declared here rather than only on the outer array.
|
|
137
|
+
modifiers: z.array(z.string()).max(10),
|
|
136
138
|
});
|
|
137
139
|
|
|
138
140
|
const cartOutput = z.object({
|
|
@@ -240,6 +242,7 @@ export default server(
|
|
|
240
242
|
},
|
|
241
243
|
[
|
|
242
244
|
tool('open_ordering', {
|
|
245
|
+
title: 'Open food ordering',
|
|
243
246
|
description:
|
|
244
247
|
'Open a complete food-ordering widget with store discovery, menu browsing, cart review, and checkout handoff.',
|
|
245
248
|
annotations: readOnly,
|
|
@@ -247,11 +250,14 @@ export default server(
|
|
|
247
250
|
query: z.string().optional(),
|
|
248
251
|
customer: z.string().default('Guest'),
|
|
249
252
|
}),
|
|
253
|
+
// List outputs declare a ceiling so a host and the model both know the payload is bounded.
|
|
254
|
+
// A recorded `fulfil` cannot slice, so the cap belongs on the shape; connector-backed lists take
|
|
255
|
+
// a pagination input instead. `noodle check` reports `tool_design_output_bounds` without one.
|
|
250
256
|
output: z.object({
|
|
251
257
|
status: z.string(),
|
|
252
258
|
customer: z.string(),
|
|
253
|
-
stores: z.array(storeShape),
|
|
254
|
-
featuredItems: z.array(menuItemShape),
|
|
259
|
+
stores: z.array(storeShape).max(20),
|
|
260
|
+
featuredItems: z.array(menuItemShape).max(20),
|
|
255
261
|
localDate: z.string(),
|
|
256
262
|
serviceArea: z.string(),
|
|
257
263
|
fallback: z.string(),
|
|
@@ -371,16 +377,18 @@ export default server(
|
|
|
371
377
|
},
|
|
372
378
|
}),
|
|
373
379
|
tool('summarize_ordering_options', {
|
|
380
|
+
title: 'Summarize ordering options',
|
|
374
381
|
description: 'Summarize available stores and menu examples without opening the widget.',
|
|
375
382
|
annotations: readOnly,
|
|
376
383
|
input: z.object({}),
|
|
377
384
|
output: z.object({
|
|
378
|
-
stores: z.array(storeShape),
|
|
379
|
-
featuredItems: z.array(menuItemShape),
|
|
385
|
+
stores: z.array(storeShape).max(20),
|
|
386
|
+
featuredItems: z.array(menuItemShape).max(20),
|
|
380
387
|
}),
|
|
381
388
|
fulfil: () => ({ stores, featuredItems: menu }),
|
|
382
389
|
}),
|
|
383
390
|
tool('plan_order', {
|
|
391
|
+
title: 'Plan an order',
|
|
384
392
|
description:
|
|
385
393
|
'Collect a fulfilment method and requested date as structured input, then return a reviewable order plan without placing an order.',
|
|
386
394
|
annotations: readOnly,
|
|
@@ -409,6 +417,7 @@ export default server(
|
|
|
409
417
|
},
|
|
410
418
|
}),
|
|
411
419
|
tool('show_capabilities', {
|
|
420
|
+
title: 'Show capabilities',
|
|
412
421
|
description: 'Return a concise summary for the standalone widget capability preview.',
|
|
413
422
|
annotations: readOnly,
|
|
414
423
|
input: z.object({}),
|
|
@@ -35,10 +35,13 @@ const vacationOptionalFields = {
|
|
|
35
35
|
start_time: epochMillis.optional(),
|
|
36
36
|
end_time: epochMillis.optional(),
|
|
37
37
|
};
|
|
38
|
+
// One shared output shape for every tool: one entry per account the call fanned out to. The cap is
|
|
39
|
+
// exactly the number of canonical accounts, so it is a true bound rather than a guess — `noodle check`
|
|
40
|
+
// reports an unbounded array output as `tool_design_output_bounds`.
|
|
38
41
|
const output = z.object({
|
|
39
|
-
results: z
|
|
40
|
-
z.object({ account: z.enum([PERSONAL_ACCOUNT, WORK_ACCOUNT]), data: z.unknown() })
|
|
41
|
-
|
|
42
|
+
results: z
|
|
43
|
+
.array(z.object({ account: z.enum([PERSONAL_ACCOUNT, WORK_ACCOUNT]), data: z.unknown() }))
|
|
44
|
+
.max(2),
|
|
42
45
|
});
|
|
43
46
|
|
|
44
47
|
const gmail = gmailConnector();
|
|
@@ -84,6 +87,7 @@ export default server(
|
|
|
84
87
|
},
|
|
85
88
|
[
|
|
86
89
|
tool('search_messages', {
|
|
90
|
+
title: 'Search messages',
|
|
87
91
|
description: 'Search one connected Gmail account or the canonical personal-and-work pair.',
|
|
88
92
|
input: z.object({
|
|
89
93
|
accounts: readAccounts,
|
|
@@ -119,6 +123,7 @@ export default server(
|
|
|
119
123
|
},
|
|
120
124
|
}),
|
|
121
125
|
tool('get_message', {
|
|
126
|
+
title: 'Get message',
|
|
122
127
|
description: 'Get one Gmail message from one connected account or both canonical accounts.',
|
|
123
128
|
input: z.object({
|
|
124
129
|
accounts: readAccounts,
|
|
@@ -154,6 +159,7 @@ export default server(
|
|
|
154
159
|
},
|
|
155
160
|
}),
|
|
156
161
|
tool('get_thread', {
|
|
162
|
+
title: 'Get thread',
|
|
157
163
|
description: 'Get one Gmail thread from one connected account or both canonical accounts.',
|
|
158
164
|
input: z.object({
|
|
159
165
|
accounts: readAccounts,
|
|
@@ -189,6 +195,7 @@ export default server(
|
|
|
189
195
|
},
|
|
190
196
|
}),
|
|
191
197
|
tool('list_drafts', {
|
|
198
|
+
title: 'List drafts',
|
|
192
199
|
description: 'List drafts from one connected Gmail account or both canonical accounts.',
|
|
193
200
|
input: z.object({
|
|
194
201
|
accounts: readAccounts,
|
|
@@ -224,6 +231,7 @@ export default server(
|
|
|
224
231
|
},
|
|
225
232
|
}),
|
|
226
233
|
tool('get_draft', {
|
|
234
|
+
title: 'Get draft',
|
|
227
235
|
description: 'Get one draft from one connected Gmail account or both canonical accounts.',
|
|
228
236
|
input: z.object({
|
|
229
237
|
accounts: readAccounts,
|
|
@@ -259,6 +267,7 @@ export default server(
|
|
|
259
267
|
},
|
|
260
268
|
}),
|
|
261
269
|
tool('get_vacation', {
|
|
270
|
+
title: 'Get vacation responder',
|
|
262
271
|
description: 'Read vacation-responder settings from one connected account or both accounts.',
|
|
263
272
|
input: z.object({ accounts: readAccounts }),
|
|
264
273
|
output,
|
|
@@ -281,6 +290,7 @@ export default server(
|
|
|
281
290
|
},
|
|
282
291
|
}),
|
|
283
292
|
tool('create_draft', {
|
|
293
|
+
title: 'Create draft',
|
|
284
294
|
description:
|
|
285
295
|
'Create a Gmail draft in exactly one selected account from a base64url MIME message.',
|
|
286
296
|
annotations: confirmedWrite,
|
|
@@ -301,6 +311,7 @@ export default server(
|
|
|
301
311
|
},
|
|
302
312
|
}),
|
|
303
313
|
tool('update_draft', {
|
|
314
|
+
title: 'Update draft',
|
|
304
315
|
description:
|
|
305
316
|
'Replace a Gmail draft in exactly one selected account with a base64url MIME message.',
|
|
306
317
|
annotations: confirmedWrite,
|
|
@@ -322,6 +333,7 @@ export default server(
|
|
|
322
333
|
},
|
|
323
334
|
}),
|
|
324
335
|
tool('send_draft', {
|
|
336
|
+
title: 'Send draft',
|
|
325
337
|
description: 'Send an existing Gmail draft from exactly one selected account.',
|
|
326
338
|
annotations: confirmedWrite,
|
|
327
339
|
input: z.object({ accounts: writeAccounts, draft_id: identifier }),
|
|
@@ -341,6 +353,7 @@ export default server(
|
|
|
341
353
|
},
|
|
342
354
|
}),
|
|
343
355
|
tool('modify_message_labels', {
|
|
356
|
+
title: 'Change message labels',
|
|
344
357
|
description: 'Add or remove Gmail label ids on one message in exactly one selected account.',
|
|
345
358
|
annotations: confirmedWrite,
|
|
346
359
|
input: z.object({
|
|
@@ -370,6 +383,7 @@ export default server(
|
|
|
370
383
|
},
|
|
371
384
|
}),
|
|
372
385
|
tool('archive_message', {
|
|
386
|
+
title: 'Archive message',
|
|
373
387
|
description: 'Archive one Gmail message in exactly one account by removing INBOX.',
|
|
374
388
|
annotations: confirmedWrite,
|
|
375
389
|
input: z.object({ accounts: writeAccounts, message_id: identifier }),
|
|
@@ -389,6 +403,7 @@ export default server(
|
|
|
389
403
|
},
|
|
390
404
|
}),
|
|
391
405
|
tool('send_message', {
|
|
406
|
+
title: 'Send message',
|
|
392
407
|
description: 'Send one base64url MIME message from exactly one selected Gmail account.',
|
|
393
408
|
annotations: confirmedWrite,
|
|
394
409
|
input: z.object({
|
|
@@ -413,6 +428,7 @@ export default server(
|
|
|
413
428
|
},
|
|
414
429
|
}),
|
|
415
430
|
tool('trash_message', {
|
|
431
|
+
title: 'Move message to trash',
|
|
416
432
|
description: 'Move one Gmail message to trash in exactly one account. This is reversible.',
|
|
417
433
|
annotations: confirmedTrash,
|
|
418
434
|
input: z.object({ accounts: writeAccounts, message_id: identifier }),
|
|
@@ -432,6 +448,7 @@ export default server(
|
|
|
432
448
|
},
|
|
433
449
|
}),
|
|
434
450
|
tool('update_vacation', {
|
|
451
|
+
title: 'Update vacation responder',
|
|
435
452
|
description: 'Update vacation-responder settings on exactly one selected Gmail account.',
|
|
436
453
|
annotations: confirmedWrite,
|
|
437
454
|
input: z.object({
|
|
@@ -10,8 +10,10 @@ When an installed Noodle Developer plugin drives this example, its skill runs th
|
|
|
10
10
|
Do not install or update a global CLI: the coding agent writes and tests this source while Noodle
|
|
11
11
|
guides and operates the validate, preview, deploy, inspect, and debug workflow.
|
|
12
12
|
If that agent discovers a Noodle Seed product gap while working, the installed skill prepares a
|
|
13
|
-
sanitized `noodle feedback` proposal, discovers current fields from `noodle commands --json`,
|
|
14
|
-
|
|
13
|
+
sanitized `noodle feedback` proposal, discovers current fields from `noodle commands --json`, runs
|
|
14
|
+
`--dry-run --json` to inspect the exact normalized submission, diagnostics, and private destination,
|
|
15
|
+
then shows a POSIX-safely quoted live command. It submits once without `--dry-run` only after explicit
|
|
16
|
+
user approval of that exact preview; it never auto-logs in or retry-loops.
|
|
15
17
|
Every `--json` command writes its canonical success or failure envelope to stdout and leaves stderr
|
|
16
18
|
empty. One-shot commands write one envelope; streaming commands write NDJSON snapshot, event, and
|
|
17
19
|
terminal-failure envelopes so agents can parse each line independently.
|
|
@@ -14,6 +14,9 @@ export default server(
|
|
|
14
14
|
},
|
|
15
15
|
[
|
|
16
16
|
tool('greet', {
|
|
17
|
+
// Every model-visible tool declares a title: hosts show it in tool pickers and confirmation
|
|
18
|
+
// prompts, and both consumer directories reject tools without one.
|
|
19
|
+
title: 'Greet someone',
|
|
17
20
|
description: 'Greet someone by name.',
|
|
18
21
|
input: z.object({
|
|
19
22
|
// Defaults are advertised to the model and applied at runtime when the argument is omitted.
|
|
@@ -189,6 +189,7 @@ export default server(
|
|
|
189
189
|
},
|
|
190
190
|
[
|
|
191
191
|
tool('weather_briefing', {
|
|
192
|
+
title: 'Weather briefing',
|
|
192
193
|
description:
|
|
193
194
|
'Look up a city, fetch its current weather, and return a human-readable briefing. Runs a ' +
|
|
194
195
|
'three-step flow: geocode the city, fetch the forecast, then derive the briefing in a sandboxed compute step.',
|
|
@@ -233,14 +234,21 @@ export default server(
|
|
|
233
234
|
// the whole array; the compute connector narrows each element to the two fields the model speaks
|
|
234
235
|
// from. Append new tools AFTER existing ones so `tools[0]` stays stable for host harnesses.
|
|
235
236
|
tool('search_places', {
|
|
237
|
+
title: 'Search places',
|
|
236
238
|
description:
|
|
237
239
|
'Search a place name and return the matching locations as a list of { id, label } options.',
|
|
238
|
-
|
|
240
|
+
// Bound the list at the source: `limit` is capped in the schema and passed through to the
|
|
241
|
+
// upstream `count` parameter, so the model can never pull an unbounded page into its context.
|
|
242
|
+
// `noodle check` reports an unbounded array output as `tool_design_output_bounds`.
|
|
243
|
+
input: z.object({
|
|
244
|
+
query: z.string(),
|
|
245
|
+
limit: z.number().int().min(1).max(10).default(5),
|
|
246
|
+
}),
|
|
239
247
|
output: z.object({
|
|
240
248
|
places: z.array(z.object({ id: z.string(), label: z.string() })),
|
|
241
249
|
}),
|
|
242
250
|
fulfil: ({ input, connectors }) => {
|
|
243
|
-
const found = connectors.geo.search_list({ name: input.query });
|
|
251
|
+
const found = connectors.geo.search_list({ name: input.query, count: input.limit });
|
|
244
252
|
const narrowed = connectors.places.narrow({ results: found.results });
|
|
245
253
|
return { places: narrowed.places };
|
|
246
254
|
},
|
|
@@ -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.43.0 hash:efffbf82007f935d -->
|
|
7
7
|
|
|
8
8
|
# publishing-mcp-integrations
|
|
9
9
|
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
- Connectors
|
|
9
9
|
- HTTP connector example (full server)
|
|
10
10
|
- Delegated downstream auth (call your API as the signed-in user)
|
|
11
|
-
- Design tools for the model
|
|
12
11
|
- Invocation context
|
|
13
12
|
- Compute connector example
|
|
14
13
|
- Tests
|
|
@@ -173,65 +172,7 @@ Diagnose statically with `noodle auth doctor`; set a short-lived real customer t
|
|
|
173
172
|
|
|
174
173
|
## Design tools for the model
|
|
175
174
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
- **Shape by intent.** Name and scope tools for the job to be done — "find my overdue tasks", "complete the task matching this text" — combining multiple backing calls in one recorded flow (`when(...)`) where it helps.
|
|
179
|
-
- **Prefer names/text over raw IDs.** When an action needs an id the user does not know, pair the id-taking operation with a find/search operation that returns model-friendly summaries (id + a human label), so the model resolves text → id itself. Write descriptions that tell the model when to use each tool and how they chain.
|
|
180
|
-
- **Return only what the model needs.** Map the response to a small, typed `output` (a few labelled fields), not the raw API payload.
|
|
181
|
-
|
|
182
|
-
This example pairs a name resolver with an id-taking action: the model calls `find_tasks` to turn the user’s words into an id, then `complete_task`. It is compile-verified on every `pnpm test`.
|
|
183
|
-
|
|
184
|
-
```ts
|
|
185
|
-
import { connector, secret, server, tool, z } from '@noodleseed/one';
|
|
186
|
-
|
|
187
|
-
const tasks = connector('tasks').version('1.0.0').http({
|
|
188
|
-
baseUrl: 'https://api.tasks.example',
|
|
189
|
-
allowedOrigins: ['https://api.tasks.example'],
|
|
190
|
-
auth: { kind: 'bearer', secret: secret('TASKS_TOKEN') },
|
|
191
|
-
operations: {
|
|
192
|
-
search_tasks: {
|
|
193
|
-
type: 'read',
|
|
194
|
-
method: 'GET',
|
|
195
|
-
path: '/tasks',
|
|
196
|
-
query: ['query'],
|
|
197
|
-
input: z.object({ query: z.string() }),
|
|
198
|
-
output: z.object({ matches: z.array(z.unknown()) }),
|
|
199
|
-
response: { matches: '${response.results}' },
|
|
200
|
-
},
|
|
201
|
-
close_task: {
|
|
202
|
-
type: 'action',
|
|
203
|
-
method: 'POST',
|
|
204
|
-
path: '/tasks/{id}/close',
|
|
205
|
-
input: z.object({ id: z.string() }),
|
|
206
|
-
output: z.object({ ok: z.boolean() }),
|
|
207
|
-
response: { ok: '${response.ok}' },
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
export default server('todo', { title: 'Tasks', version: '1.0.0', use: { tasks } }, [
|
|
213
|
-
tool('find_tasks', {
|
|
214
|
-
description: 'Find tasks whose text matches a query — call this first to resolve a task the user names by text into its id, then pass that id to complete_task.',
|
|
215
|
-
input: z.object({ query: z.string() }),
|
|
216
|
-
output: z.object({ matches: z.array(z.object({ id: z.string(), title: z.string() })) }),
|
|
217
|
-
fulfil: ({ input, connectors }) => {
|
|
218
|
-
const found = connectors.tasks.search_tasks({ query: input.query });
|
|
219
|
-
return { matches: found.matches };
|
|
220
|
-
},
|
|
221
|
-
}),
|
|
222
|
-
tool('complete_task', {
|
|
223
|
-
description: 'Mark a task complete by its id (get the id from find_tasks).',
|
|
224
|
-
input: z.object({ id: z.string() }),
|
|
225
|
-
output: z.object({ ok: z.boolean() }),
|
|
226
|
-
fulfil: ({ input, connectors }) => {
|
|
227
|
-
const result = connectors.tasks.close_task({ id: input.id });
|
|
228
|
-
return { ok: result.ok };
|
|
229
|
-
},
|
|
230
|
-
}),
|
|
231
|
-
]);
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
The model never sees a task id from the user; `find_tasks` returns `{ id, title }` summaries it can pick from, then `complete_task` acts by id. Keep write actions (`complete_task`) separate and explicitly described so the host can gate them.
|
|
175
|
+
Shape tools around what a user says, not 1:1 around API endpoints. `references/tool-design.md` owns the doctrine: intent-shaped tools, titles and annotations, bounded outputs, a small tool surface, and deliberate context.
|
|
235
176
|
|
|
236
177
|
## Invocation context
|
|
237
178
|
|
|
@@ -22,7 +22,7 @@ Establish only the inputs needed for the requested stopping point. Follow `refer
|
|
|
22
22
|
1. **Confirm conversational fit.** Name one to three focused jobs where saying the request is easier than navigating the underlying system, and identify the data or action the model cannot provide by itself.
|
|
23
23
|
2. **Define the product contract.** For each job, write the user phrase, the intent-shaped tool or resource, its minimal typed input, the useful output, read/write effect, and backing operation. Design for user intent, not a 1:1 API endpoint wrapper.
|
|
24
24
|
3. **Choose the smallest implementation.** Use native tools, resources, or prompts for local/static behavior; add a connector only when external data or actions are required. Keep response output small and model-readable.
|
|
25
|
-
4. **Author in TypeScript.** Follow `references/authoring-workflow.md` for connector and flow patterns and `references/sdk-surface.md` for exact builders. These are this route’s complete canonical support set; use the router lookup catalog only when observed evidence names a different concern.
|
|
25
|
+
4. **Author in TypeScript.** Follow `references/authoring-workflow.md` for connector and flow patterns, `references/tool-design.md` for the model-facing tool surface, and `references/sdk-surface.md` for exact builders. These are this route’s complete canonical support set; use the router lookup catalog only when observed evidence names a different concern.
|
|
26
26
|
5. **Validate and repair.** Run `noodle validate --json`. Parse `error.errors[]`, repair the cited `path`, and rerun validation. Consult the lookup catalog only for the specific reported error code; do not open another reference speculatively.
|
|
27
27
|
6. **Run the local smoke.** After validation succeeds, run `noodle test --json` and repair any failure at that evidence layer.
|
|
28
28
|
7. **Prove external behavior.** For connector-backed reads, set credentials through the effective local target and run a safe representative `noodle tools call`. Confirm populated mapped fields from real output, not merely successful registration.
|
|
@@ -27,7 +27,7 @@ Developer-facing `noodle` commands, grouped by area. Local authoring commands (`
|
|
|
27
27
|
| `noodle import` | Import an OpenAPI spec into a starter `server.ts`. |
|
|
28
28
|
| `noodle export` | Compile locally and write the portable manifest JSON (no service). |
|
|
29
29
|
| `noodle validate` | Author-time compile/schema/connector check; no service (`--json`, `--fix-prompt`). |
|
|
30
|
-
| `noodle check` | Check MCP Apps/widget readiness; no service. |
|
|
30
|
+
| `noodle check` | Check tool design (`tool_design_*`) and MCP Apps/widget readiness; no service. `--min-severity warn` shows only what needs fixing. |
|
|
31
31
|
| `noodle test` | Local compile plus a loopback MCP smoke. |
|
|
32
32
|
|
|
33
33
|
## Local run & inspect
|
|
@@ -157,8 +157,12 @@ Local `dev`, smoke commands, secrets, and variables resolve one effective target
|
|
|
157
157
|
noodle secrets set SOME_API_KEY --runtime local --from-env SOME_API_KEY
|
|
158
158
|
# Explicit flags remain available when intentionally testing a different local target:
|
|
159
159
|
noodle secrets set SOME_API_KEY --runtime local --scope env --org <org> --app <app> --env <env> --from-env SOME_API_KEY
|
|
160
|
+
# Configuring a deployed environment is a different store — say so:
|
|
161
|
+
noodle secrets set SOME_API_KEY --runtime cloud --scope env --org <org> --app <app> --env <env> --from-env SOME_API_KEY
|
|
160
162
|
```
|
|
161
163
|
|
|
164
|
+
`--runtime` is required whenever `--org`, `--app`, and `--env` together name a complete hosted target: a command that looks remote must never fall back to writing `.env.noodle`. Omitting it fails with `runtime_required` before anything is written.
|
|
165
|
+
|
|
162
166
|
Local secrets live in `./.env.noodle` (never commit it). A required `secret(...)` or `variable(...)` that cannot resolve fails boot closed. `noodle tools call` / `noodle test` / `noodle dev` / `noodle devtools` stop before exposing an empty endpoint and print the exact effective target plus recovery command.
|
|
163
167
|
|
|
164
168
|
### Prove real output
|
|
@@ -91,9 +91,9 @@ Give every business action a portable `tool(..., { title: "Complete task", descr
|
|
|
91
91
|
Local MCP authoring and tests need no account, but an external browser embed needs an active assistant-enabled deployment before a backend client can be created. Set the model values on the target org/app/env, then deploy:
|
|
92
92
|
|
|
93
93
|
```sh
|
|
94
|
-
noodle variables set ASSISTANT_MODEL_BASE_URL --scope env --org <org> --app <app> --env <env> --value <https-model-base-url>
|
|
95
|
-
noodle variables set ASSISTANT_MODEL --scope env --org <org> --app <app> --env <env> --value <model>
|
|
96
|
-
noodle secrets set ASSISTANT_MODEL_API_KEY --scope env --org <org> --app <app> --env <env> --from-env ASSISTANT_MODEL_API_KEY
|
|
94
|
+
noodle variables set ASSISTANT_MODEL_BASE_URL --scope env --runtime cloud --org <org> --app <app> --env <env> --value <https-model-base-url>
|
|
95
|
+
noodle variables set ASSISTANT_MODEL --scope env --runtime cloud --org <org> --app <app> --env <env> --value <model>
|
|
96
|
+
noodle secrets set ASSISTANT_MODEL_API_KEY --scope env --runtime cloud --org <org> --app <app> --env <env> --from-env ASSISTANT_MODEL_API_KEY
|
|
97
97
|
noodle deploy --org <org> --app <app> --env <env>
|
|
98
98
|
```
|
|
99
99
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Send product feedback
|
|
2
2
|
|
|
3
|
-
When you — the coding agent — discover a way Noodle Seed could be better, prepare one sanitized feedback proposal. Feedback crosses the customer project boundary and lands in Noodle Seed
|
|
3
|
+
When you — the coding agent — discover a way Noodle Seed could be better, prepare one sanitized feedback proposal. Feedback crosses the customer project boundary and lands in the Noodle Seed private feedback tracker, so the user must make an informed choice. Preview the exact normalized submission locally, show it with the exact live command, and ask for explicit user approval. Do not submit it until approval is given.
|
|
4
4
|
|
|
5
5
|
## Contents
|
|
6
6
|
|
|
@@ -26,20 +26,22 @@ Do not batch several findings into one proposal, and do not re-propose the same
|
|
|
26
26
|
|
|
27
27
|
## Approval workflow
|
|
28
28
|
|
|
29
|
-
1.
|
|
30
|
-
2.
|
|
31
|
-
3.
|
|
32
|
-
4.
|
|
29
|
+
1. Discover the current positional arguments, flags, choices, defaults, and limits from `noodle commands --json`; `noodle feedback --help` is the human-readable view. Do not guess or rely on a remembered catalog.
|
|
30
|
+
2. Draft one finding, then sanitize its title and message using the rules below.
|
|
31
|
+
3. Run the proposal with `--dry-run --json`. This local preview needs no login and sends nothing. Parse `{"ok":true,"data":{"mode":"preview","willSubmit":false,"destination":"Noodle Seed private feedback tracker","submission":{...}}}`.
|
|
32
|
+
4. Inspect the complete `submission`, including its normalized defaults and automatically attached diagnostics. Show the user the exact previewed proposal, its `destination`, and a POSIX-safely quoted live command containing the same fields but without `--dry-run`.
|
|
33
|
+
5. Ask for explicit approval of that exact previewed proposal. If the user changes any field, preview the changed proposal again before asking.
|
|
34
|
+
6. Only after approval, submit it once by running the disclosed live command without `--dry-run`. Never auto-login and never retry-loop. If authentication fails before the request or a rate limit denies it, report that nothing was sent. For `feedback_recording_failed`, report that no reference was returned and the outcome may be unknown; do not retry because the private issue might already exist.
|
|
33
35
|
|
|
34
36
|
## The command
|
|
35
37
|
|
|
36
38
|
```sh
|
|
37
|
-
noodle feedback
|
|
38
|
-
--title
|
|
39
|
-
--type fix --severity P2 --area cli --json
|
|
39
|
+
noodle feedback 'resources list --json omits the truncated flag the docs promise' \
|
|
40
|
+
--title 'resources list --json missing truncated flag' \
|
|
41
|
+
--type fix --severity P2 --area cli --dry-run --json
|
|
40
42
|
```
|
|
41
43
|
|
|
42
|
-
This is
|
|
44
|
+
This is a preview example only. Build the exact command for the finding using current `noodle commands --json` metadata, POSIX-quote every user-controlled value, and inspect the returned submission instead of reconstructing it. The message is required (1–4000 chars). The CLI attaches only the disclosed light diagnostics automatically: CLI version, OS/platform, Node version. Nothing else is collected. After approval, the live success envelope is `{ok:true,data:{reference,labels}}`; a `429` means the per-user hourly budget (5) is spent — report that it was not sent and never retry-loop.
|
|
43
45
|
|
|
44
46
|
## Choose the structured fields
|
|
45
47
|
|