* feat: replace the AI input filling toggle with an additional prompt for AI
* feat: pass the additional prompt for AI to MCP clients and shared AI guidance
* feat: shrink the run page AI card to a button and a collapsed prompt
* fix: offer writers a way to add a prompt for AI from the run page
* docs: teach agents to pass a resource as $res:<path> in run arguments
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk
* docs: extend run-argument rule to in-editor chats, fix run-as wording
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk
* docs: tighten resource run-argument rule after review
- Drop the false rationale that "$var:" only works inside a resource value
from the write_variable description and its runtime rejection message; keep
the rule (a variable cannot reference itself).
- MCP resource-argument description: the title fallback renders "No title",
so say the title is only a label rather than that it can be empty. Guard the
real-newline fix with asserts in the existing enrichment test.
- Eval: assert the full "$res:f/evals/global/github_main" value as one prefix
so a wrong path with a right prefix fails.
- resources.md: narrow "a trigger's payload" to its configured static args.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk
* docs: scope the run-argument rule to global chat, add an exact eval matcher
The ai_evals A/B on the two in-editor modes showed no effect: script mode
sonnet 5/5 both with and without the description, flow mode sonnet 5/5 and
haiku 5/5 on the baseline alone. A flow's input schema already carries
`format: resource-<type>`, so those modes have a signal global mode does not
give. Revert both files to keep the tool schemas free of a description that
buys nothing per iteration; global mode keeps it, where haiku goes 0/5 -> 5/5.
Add `stringEqualsAnyOf` to toolCallArgs and use it for the resource reference:
nothing in the eval resolves the value, so a prefix match accepted a near-miss
path like `$res:f/evals/global/github_main_backup`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk
* docs: address cubic review — CLI wording, mock resource getter
- `-d --data` help on all four run/preview commands: give $res: and $var:
their own clauses instead of a parenthetical that read as if a resource
were a kind of variable.
- Mock backend: `getBenchmarkResource` now resolves AI-provider seeds as well
as plain ones, so it agrees with `existsResource` and `listResource` — both
report either kind, and a case that listed a resource and then read it by
path got a row it could not fetch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: tell MCP clients which tool parameters may be omitted
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor: make the mcp property-key rename testable and shorten the hint
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the mcp omission hint from calling flow inputs optional
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: skip the mcp omission hint on a parameterless tool
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Flow input schemas omit `required` (they carry an `order` key instead),
which made `serde_json::from_str::<SchemaType>` fail in
`convert_schema_to_schema_type`. The error was swallowed and callers fell
back to an empty `SchemaType::default()`, so MCP flow tools advertised no
inputs. Add `#[serde(default)]` to `type`, `properties`, and `required` on
`SchemaType` so these schemas deserialize correctly. Scripts always include
`required` and were unaffected.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mcp): add multi-workspace MCP tokens via the gateway endpoint
A single MCP token with no bound workspace (workspace_id NULL + mcp scope)
now works across every workspace the token owner can access, served through
the existing /api/mcp/gateway endpoint. This avoids having to register one
MCP server entry per workspace in clients like Claude/Cursor.
In multi-workspace mode the runner exposes a synthetic `list_workspaces`
tool plus the generic API endpoint tools, each workspace-scoped one gaining
a required `workspace_id` argument (mirroring the proxy pattern users built
externally). Per-workspace scripts/flows are not enumerated to avoid
flooding the tool list — they are run via runScriptByPath/runFlowByPath
with an explicit workspace_id.
Auth is resolved per tool call: the gateway middleware detects a
workspace-less mcp token and marks the request MultiWorkspaceMcp, and the
runner resolves a per-workspace ApiAuthed from the raw token via the
AuthCache (validating membership; superadmins may act in any workspace).
Single-workspace tokens are unchanged.
Frontend: the MCP token creation flow gains an "All workspaces" option that
produces a workspace-less token and the gateway URL.
Fixes WIN-2153
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(mcp): cover multi-workspace endpoint tool transformation
Unit tests for endpoint_tool_to_mcp_tool_multi and list_workspaces_tool:
workspace-scoped tools gain a required workspace_id arg, global tools are
left unchanged, workspace_id is not duplicated, and list_workspaces takes
no arguments.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(mcp): forward script/flow args for runScriptByPath/runFlowByPath
These endpoints have an additionalProperties body (no declared properties),
so build_request_body previously returned an empty body and dropped every
script/flow argument. This was latent for the per-path run endpoints and
became load-bearing in multi-workspace mode, where scripts/flows can only be
run via runScriptByPath/runFlowByPath — parameterized runs silently lost
their arguments.
build_request_body now forwards all arguments not consumed by a path/query
parameter for pass-through (additionalProperties) bodies, keeping the strict
declared-only behavior for endpoints with explicit properties. The runner
strips the synthetic workspace_id argument before dispatch so it can't leak
into the forwarded body.
Reported by Codex review on #10043.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mcp): note workspace_id requirement in multi-workspace tool descriptions
Workspace-scoped tools already gain a required workspace_id parameter (with
its own schema description) in multi-workspace mode, but the tool's prose
description was unchanged. Append a note so models/clients that read the
description text know to pass workspace_id (and to call list_workspaces
first). Global tool descriptions are left untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(mcp): trim multi-workspace tool/arg descriptions
The workspace_id note repeats across every workspace-scoped tool in each
tools/list, so keep it terse: description suffix "Requires `workspace_id`."
and arg description "Target workspace id (from list_workspaces)." to avoid
spending tokens on repeated boilerplate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(mcp): enforce script/flow path scopes for multi-workspace run-by-path
In multi-workspace mode runScriptByPath/runFlowByPath are the only way to run
scripts/flows, but they were authorized against the endpoint scope only — never
the caller's mcp:scripts:/mcp:flows: path scopes. A granular token could run
items outside its allowed paths (e.g. mcp:scripts:f/team/* + mcp:endpoints:*
running f/other/secret), and a mcp:endpoints:* token could run arbitrary
scripts.
Now these two endpoints are authorized by the script/flow scope of the
requested path (matching single-workspace mode's per-item tools): exposed in
list_tools only when the token grants some script/flow (McpScopeConfig::has_any),
and at call time the path is checked via is_allowed("script"/"flow", path).
Verified e2e: mcp:scripts:f/team/* runs f/team/* but is denied f/other/*;
mcp:endpoints:* alone no longer exposes or runs run-by-path.
Reported by Codex + Pi review on #10043.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(mcp): deny run-by-path for mcp:favorites multi-workspace tokens
mcp:favorites sets granular=false, so the previous run-by-path scope check
(gated on `granular`) was skipped entirely — a default "Favorites only"
all-workspaces token could run any script/flow by naming its path, bypassing
the favorites restriction.
Favorites are an enumerated set reachable only through per-item tools, not by
arbitrary path, so they grant nothing for run-by-path. has_any() now returns
true only for mcp:all (not favorites), and the call-time check drops the
`granular` gate and relies on is_allowed() directly (already false for
favorites, true for mcp:all, pattern-matched for granular).
Verified e2e: mcp:favorites no longer exposes or runs run-by-path; mcp:all
still runs; granular script scopes still path-enforced.
Reported by Codex review on #10043.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: re-enforce per-path token scope on store rename, delete and interpolation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: enforce token scope on workspace export and resume-url minting
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: enforce per-item and runnable scope on trigger create paths
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: enforce app write scope before persistence and on rename
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: enforce scope containment on mcp oauth approval
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: scope mcp endpoint-proxy jwt to the proxied route
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: treat resource-linked variables and resources as covered by resource scope
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: only require variables:read for plaintext-secret workspace export
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: handle singlestepflow resume, reject empty mcp grant, scope var-skipped tarball
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop empty/unknown `type` values (Windmill emits `type: ""` for untyped fields) and infer `type: array` for nodes carrying `items`, so generated MCP tool schemas validate against JSON Schema draft 2020-12. Anthropic's tool registration rejected the whole tool list otherwise.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: replace _TRUNC with hash-based MCP tool names (50 char limit)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: reduce MCP tool name limit from 50 to 40 chars
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: use path prefix filtering instead of separate DB query for hashed name resolution
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: remove long path warning from MCP token creation (hashing handles long names)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: unify tool prefix parsing and fix extract_path_prefix_from_hashed for Hs- names
- Replace `is_hashed_name` + `parse_hashed_name` with unified `parse_tool_prefix`
that returns `(type_str, is_hub, is_hashed)` in one call
- Fix `extract_path_prefix_from_hashed` to dynamically determine prefix length
(3 for `Hs-`, 2 for `S-`/`F-`) instead of hardcoding index 2
- Simplify `reverse_transform` to reuse `parse_tool_prefix`
- Add tests for invalid prefixes and `Hs-` prefix handling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: escape LIKE wildcards in MCP hashed name path prefix query
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: respect favorites scope in hashed tool name resolution
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: deduplicate MCP tool name resolution and rename get_path_or_id
- Extract `unescape_path` helper in transform.rs to deduplicate the
3-step placeholder unescape logic
- Extract `find_matching_path` helper in runner.rs to deduplicate
script/flow candidate matching via ToolableItem trait
- Remove verbose tracing::info! logs from hashed tool resolution hot path
- Fix doc comment referencing nonexistent `is_hashed_name` function
- Rename `get_path_or_id` to `get_transformed_path` for clarity
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: update stale doc comments to reflect MAX_PATH_LENGTH=40
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>