@noodleseed/agent-kit 0.41.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 +275 -259
- package/package.json +1 -1
- package/skills/claude-code/SKILL.md +6 -5
- 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 +7 -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/agent-contract.md +4 -3
- 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 +6 -5
- 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 +7 -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/agent-contract.md +4 -3
- 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
|
@@ -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
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Tool design
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Design tools for the model
|
|
6
|
+
- Title and annotations
|
|
7
|
+
- Bound every output
|
|
8
|
+
- Keep the tool surface small
|
|
9
|
+
- Provision context deliberately
|
|
10
|
+
- Errors an agent can act on
|
|
11
|
+
- What `noodle check` reports
|
|
12
|
+
|
|
13
|
+
## Design tools for the model
|
|
14
|
+
|
|
15
|
+
Design tools around what a user says, not 1:1 around API endpoints. A raw wrapper per endpoint (`get_task`, `list_tasks`, `close_task`) forces the model to orchestrate low-level calls and to know identifiers the user never sees — an MCP connector, but not a usable product. Instead:
|
|
16
|
+
|
|
17
|
+
- **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.
|
|
18
|
+
- **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.
|
|
19
|
+
- **Return only what the model needs.** Map the response to a small, typed `output` (a few labelled fields), not the raw API payload.
|
|
20
|
+
|
|
21
|
+
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`.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { connector, secret, server, tool, z } from '@noodleseed/one';
|
|
25
|
+
|
|
26
|
+
const tasks = connector('tasks').version('1.0.0').http({
|
|
27
|
+
baseUrl: 'https://api.tasks.example',
|
|
28
|
+
allowedOrigins: ['https://api.tasks.example'],
|
|
29
|
+
auth: { kind: 'bearer', secret: secret('TASKS_TOKEN') },
|
|
30
|
+
operations: {
|
|
31
|
+
search_tasks: {
|
|
32
|
+
type: 'read',
|
|
33
|
+
method: 'GET',
|
|
34
|
+
path: '/tasks',
|
|
35
|
+
query: ['query'],
|
|
36
|
+
input: z.object({ query: z.string() }),
|
|
37
|
+
output: z.object({ matches: z.array(z.unknown()) }),
|
|
38
|
+
response: { matches: '${response.results}' },
|
|
39
|
+
},
|
|
40
|
+
close_task: {
|
|
41
|
+
type: 'action',
|
|
42
|
+
method: 'POST',
|
|
43
|
+
path: '/tasks/{id}/close',
|
|
44
|
+
input: z.object({ id: z.string() }),
|
|
45
|
+
output: z.object({ ok: z.boolean() }),
|
|
46
|
+
response: { ok: '${response.ok}' },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export default server('todo', { title: 'Tasks', version: '1.0.0', use: { tasks } }, [
|
|
52
|
+
tool('find_tasks', {
|
|
53
|
+
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.',
|
|
54
|
+
input: z.object({ query: z.string() }),
|
|
55
|
+
output: z.object({ matches: z.array(z.object({ id: z.string(), title: z.string() })) }),
|
|
56
|
+
fulfil: ({ input, connectors }) => {
|
|
57
|
+
const found = connectors.tasks.search_tasks({ query: input.query });
|
|
58
|
+
return { matches: found.matches };
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
tool('complete_task', {
|
|
62
|
+
description: 'Mark a task complete by its id (get the id from find_tasks).',
|
|
63
|
+
input: z.object({ id: z.string() }),
|
|
64
|
+
output: z.object({ ok: z.boolean() }),
|
|
65
|
+
fulfil: ({ input, connectors }) => {
|
|
66
|
+
const result = connectors.tasks.close_task({ id: input.id });
|
|
67
|
+
return { ok: result.ok };
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
]);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
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.
|
|
74
|
+
|
|
75
|
+
## Title and annotations
|
|
76
|
+
|
|
77
|
+
Every model-visible tool needs a `title` — the action name hosts show in tool pickers and confirmation prompts — and `annotations`. `annotations.readOnly()` is a closed-world safe read; `annotations.action()` affects the world; `annotations.localAction()` affects only this app's data; `annotations.openAction()` reaches the open internet. Keep reads and writes in separate tools: one tool that both lists and mutates cannot be annotated honestly, so no host can gate it correctly. Missing titles and hints are also the most common consumer-directory rejection.
|
|
78
|
+
|
|
79
|
+
## Bound every output
|
|
80
|
+
|
|
81
|
+
Always declare `output`. Without it the model has to parse prose and hosts have no structured result to render. Then bound any list: cap the array with `z.array(item).max(50)`, or take a bounded pagination input (`limit`, `cursor`). An unbounded list either exhausts the context window or is truncated somewhere you do not control. Map the response to the few labelled fields the model needs, never the raw upstream payload — every field you pass through is context paid for on every later turn.
|
|
82
|
+
|
|
83
|
+
## Keep the tool surface small
|
|
84
|
+
|
|
85
|
+
`noodle check` warns above 20 model-visible tools. That is a documented heuristic, not a host limit: no host publishes a hard number, and the real threshold depends on how distinct your descriptions are. Collapse variants that differ only by a filter into one intent-shaped tool with a typed enum, and mark widget-only helpers `visibility: ['app']` so they stay callable from the app surface without entering the model's list.
|
|
86
|
+
|
|
87
|
+
## Provision context deliberately
|
|
88
|
+
|
|
89
|
+
Most “the model guessed wrong” bugs are missing context, not a missing tool. Every invocation already carries a server-authoritative instant plus locale and time zone, so never ask the model for today's date. Set `server(..., { context: { defaults: { locale, timeZone } } })` for ambient defaults, and mark one zero-input tool `contextProvider: true` when the model needs portable application context such as workspace, plan, or permissions. `references/authoring-workflow.md` owns the full invocation-context contract.
|
|
90
|
+
|
|
91
|
+
## Errors an agent can act on
|
|
92
|
+
|
|
93
|
+
An agent cannot recover from “Request failed”. Say which argument was wrong, which tool resolves it, and whether retrying helps. Error text is part of the tool interface and is read far more often by a model than by a human.
|
|
94
|
+
|
|
95
|
+
## What `noodle check` reports
|
|
96
|
+
|
|
97
|
+
- `tool_design_titles` — a model-visible tool has no `title`.
|
|
98
|
+
- `tool_design_output_shape` — a model-visible tool has no `output` schema.
|
|
99
|
+
- `tool_design_output_bounds` — an output array has no `maxItems` and the tool takes no pagination input.
|
|
100
|
+
- `tool_design_surface_budget` — more than 20 model-visible tools.
|
|
101
|
+
- `tool_design_context` — which tool provides application context (informational).
|
|
102
|
+
|
|
103
|
+
All five are warnings, never failures, so they never change the exit code. Use `noodle check --min-severity warn` to see only what needs fixing and `noodle check --json` to consume them programmatically.
|
|
@@ -3,11 +3,11 @@ 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.43.0 hash:0f404109f4845683 -->
|
|
7
7
|
|
|
8
8
|
# reporting-noodle-feedback
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Preview one sanitized feedback proposal and submit it once only after informed explicit approval.
|
|
11
11
|
|
|
12
12
|
## Use when
|
|
13
13
|
|
|
@@ -23,7 +23,7 @@ Offer one sanitized feedback command and submit it only after informed explicit
|
|
|
23
23
|
|
|
24
24
|
- One distinct finding.
|
|
25
25
|
- Sanitized observed and expected behavior.
|
|
26
|
-
- User approval for the exact command.
|
|
26
|
+
- User approval for the exact dry-run preview and live command.
|
|
27
27
|
|
|
28
28
|
## Workflow
|
|
29
29
|
|
|
@@ -31,15 +31,15 @@ Read and follow the canonical playbook `references/feedback.md` at `../noodle-se
|
|
|
31
31
|
|
|
32
32
|
## Verification evidence
|
|
33
33
|
|
|
34
|
-
The user saw the exact sanitized command; only a returned reference proves submission.
|
|
34
|
+
The user saw the exact sanitized preview, diagnostics, destination, and live command; only a returned reference proves submission.
|
|
35
35
|
|
|
36
36
|
## Recovery paths
|
|
37
37
|
|
|
38
|
-
If login or rate limits block submission, report that nothing was sent and
|
|
38
|
+
If login or rate limits block the one live submission, report that nothing was sent. A recording failure has an unknown outcome: report no reference and never auto-login or retry-loop.
|
|
39
39
|
|
|
40
40
|
## Stop conditions
|
|
41
41
|
|
|
42
|
-
Stop before
|
|
42
|
+
Stop after the local dry-run and before the live command until the user explicitly approves it.
|
|
43
43
|
|
|
44
44
|
## Handoff contract
|
|
45
45
|
|
|
@@ -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.43.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.43.0 hash:cd6ca0d915e6acb9 -->
|
|
7
7
|
|
|
8
8
|
# Noodle Seed
|
|
9
9
|
|
|
@@ -35,11 +35,11 @@ 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
|
|
|
42
|
-
|
|
42
|
+
Every `--json` command speaks the canonical envelope on stdout. Parse machine state instead of scraping human prose; `references/agent-contract.md` owns the envelope, streaming records, and exit codes.
|
|
43
43
|
|
|
44
44
|
1. **Discover** — use `noodle commands --json` when the required command or flags are uncertain; don't read CLI source.
|
|
45
45
|
2. **Author** — for build routes, edit the configured TypeScript entrypoint, usually `src/server.ts`.
|
|
@@ -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,13 @@ 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.
|
|
17
|
+
Every `--json` command writes its canonical success or failure envelope to stdout and leaves stderr
|
|
18
|
+
empty. One-shot commands write one envelope; streaming commands write NDJSON snapshot, event, and
|
|
19
|
+
terminal-failure envelopes so agents can parse each line independently.
|
|
15
20
|
|
|
16
21
|
```sh
|
|
17
22
|
noodle dev examples/hello/src/server.ts --app hello
|
|
@@ -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.
|