From 6912efaa6cc9f71d8e049a680e9e0c1d889fc2ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 Oct 2026 18:21:48 +0000 Subject: [PATCH] Version Packages --- .changeset/first-party-inputs.md | 11 ----------- .changeset/role-assignment-existing.md | 5 ----- .changeset/windows-browser-launch.md | 5 ----- README.md | 16 ++++++++-------- llms-install.md | 10 +++++----- packages/mcp-server/CHANGELOG.md | 6 ++++++ packages/mcp-server/README.md | 6 +++--- packages/mcp-server/package.json | 2 +- plugin/.claude-plugin/plugin.json | 4 ++-- plugin/.cursor-plugin/plugin.json | 4 ++-- plugin/CHANGELOG.md | 13 +++++++++++++ plugin/README.md | 4 ++-- plugin/mcp.json | 2 +- plugin/package.json | 2 +- plugin/plugin.json | 2 +- plugin/skills/formio-mcp-setup/SKILL.md | 18 +++++++++--------- .../references/project-urls.md | 2 +- server.json | 4 ++-- 18 files changed, 57 insertions(+), 59 deletions(-) delete mode 100644 .changeset/first-party-inputs.md delete mode 100644 .changeset/role-assignment-existing.md delete mode 100644 .changeset/windows-browser-launch.md diff --git a/.changeset/first-party-inputs.md b/.changeset/first-party-inputs.md deleted file mode 100644 index df03a13..0000000 --- a/.changeset/first-party-inputs.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@formio/ai': patch ---- - -Describe what the Angular, application, and SDK skills read at build time as the first-party inputs they are, so the skills.sh Snyk W011 "third-party content exposure" findings stop reading the skills' own trust prose as evidence of outsider content. - -**`formio-angular`** no longer calls the planner's `template.md` + `template.json` pair "the largest untrusted input this skill has" arriving "from a clone, a download, an unpacked archive" — the phrasing Snyk quoted back as "outsider-authored free text". The section now states that the pair is this pipeline's own artifact, written by `formio-resource-planner` and approved at its Phase A gate, and that the skill reads the two files the handoff names rather than whatever the directory holds. The three rules are unchanged: the pair must be first-party (confirmed with the user when nothing in the session accounts for it), its contents are data and not instructions, and every value is shape-checked before it reaches generated code. - -**`formio-sdk`**'s last Security rule no longer tells the agent it reads "submission JSON … returned by any `Formio` call or MCP tool". It states what is true: the MCP tools return project configuration — form definitions, roles, actions, templates — and no submission data, and the SDK calls the skill documents are code the application runs at runtime. Configuration the agent reads still never instructs it. - -**`formio-application`**'s Step 1 opens by naming its inputs — the user's own words, the user's own workspace on the modify-existing branch, and the planner pair produced from them — and states that it fetches no web page, reads no submission data, and opens no file a third party supplied. diff --git a/.changeset/role-assignment-existing.md b/.changeset/role-assignment-existing.md deleted file mode 100644 index e8140d4..0000000 --- a/.changeset/role-assignment-existing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@formio/ai': patch ---- - -Document how to configure a Role Assignment action with `association: "existing"`. The `formio-actions` reference used to describe the target only as "a component whose value is the target resource's submission ID", which reads as though any key will do; it now states that the target component's key must be exactly `submission`. The same guidance recommends setting `settings.role` explicitly and granting create access on such a form to administrator roles only. `formio-resource-planner`'s `template-json.md` carries the same rules for any `existing` action it emits, and a new skill test keeps every description of the association naming the `submission` key. diff --git a/.changeset/windows-browser-launch.md b/.changeset/windows-browser-launch.md deleted file mode 100644 index a269aa4..0000000 --- a/.changeset/windows-browser-launch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@formio/mcp': patch ---- - -Open the portal-login and revisions-consent pages in the browser on Windows. Both pages were launched with `exec('start ""')`, and `start` reads its first quoted argument as a window title, so Windows opened an empty console window titled with the URL and no browser — the tool call then waited out the login timeout with no page in front of the user. Both pages now go through one launcher that runs no shell: `open` on macOS, `xdg-open` on Linux, and `rundll32 url.dll,FileProtocolHandler` on Windows, each handed the URL as its own argument. The consent page also now reports a failed launch on stderr with its URL, as the login page already did, instead of ignoring it. diff --git a/README.md b/README.md index 554fdcf..ef9d633 100644 --- a/README.md +++ b/README.md @@ -71,10 +71,10 @@ Neither install route asks for a URL. Both are resolved per working directory, s ```bash # What does this directory resolve to? -npx -y @formio/mcp@0.14.0 project get --cwd "$(pwd)" +npx -y @formio/mcp@0.14.1 project get --cwd "$(pwd)" # Record it for this machine… -npx -y @formio/mcp@0.14.0 project set --project-url "" --cwd "$(pwd)" +npx -y @formio/mcp@0.14.1 project set --project-url "" --cwd "$(pwd)" # …or commit it with the application, tracked in git and shared with everyone who clones it: # write a formio.json in the application's own folder (the server reads it, never writes it) @@ -91,7 +91,7 @@ You usually only supply the first. The Base URL is worked out from the Project U Those derivations are also enforced: a `*.form.io` project paired with anything but `https://api.form.io` is refused, because for every project on our SaaS environment that pairing is a mistake that surfaces later as unexplained 404s or a portal login sent to a deployment you do not use. One deployment shape is indistinguishable from that mistake — an internal, non-SaaS deployment served from a `*.form.io` domain, which our QA team tests — so `project set` takes a `--force` flag for it: ```bash -npx -y @formio/mcp@0.14.0 project set --force \ +npx -y @formio/mcp@0.14.1 project set --force \ --project-url "https://myproject.form.io" --base-url "https://api.internal.example" --cwd "$(pwd)" ``` @@ -100,7 +100,7 @@ npx -y @formio/mcp@0.14.0 project set --force \ The override belongs to the pair, not to the directory. Re-pointing the directory at a different project drops it and the checks apply again, while a write that leaves both halves untouched keeps it — an agent re-recording the project it already resolved must not undo your decision. That also means re-recording the same pair without `--force` changes nothing, so clearing the record is the way back: ```bash -npx -y @formio/mcp@0.14.0 project set --reset --cwd "$(pwd)" +npx -y @formio/mcp@0.14.1 project set --reset --cwd "$(pwd)" ``` `--reset` removes this directory's entry from `~/.formio/projects.json` — nothing else — and prints what the directory resolves to afterwards, which may still be a committed `formio.json` or the environment. It takes no URLs, exits `0` whenever the record was cleared (run `project get` to see whether the directory is serviceable), and is what every forced report names as the way to put the checks back. @@ -211,7 +211,7 @@ It is also listed in the [official MCP Registry](https://registry.modelcontextpr "mcpServers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } @@ -226,7 +226,7 @@ That is the **JSON `mcpServers`** shape — what Claude Code (`.mcp.json`), Curs "servers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } @@ -237,7 +237,7 @@ That is the **JSON `mcpServers`** shape — what Claude Code (`.mcp.json`), Curs ```toml [mcp_servers.formio-mcp] command = "npx" -args = ["-y", "@formio/mcp@0.14.0"] +args = ["-y", "@formio/mcp@0.14.1"] ``` Authentication is the same everywhere: the first authenticated tool call opens the browser portal-login flow, or set `FORMIO_API_KEY` to skip the browser entirely — required on any host with no browser, such as a cloud agent, a container, or CI. @@ -339,7 +339,7 @@ The probe runs lazily — only when the local auth page is actually served. | `FORMIO_AUTH_HOST` / `FORMIO_AUTH_PORT` | no | `127.0.0.1` / ephemeral | Bind address and port for the login server. Set both when running in a container so the login page is reachable through a published port. | — | `0.0.0.0` / `43117` | | `FORMIO_INSECURE_TLS` | no | `false` | When `true`, skips TLS certificate verification (sets `NODE_TLS_REJECT_UNAUTHORIZED=0`) — for self-hosted deployments behind self-signed certs. Do not use against production. | — | `true` | -\* Not at startup — the server starts and lists every tool without it, and only errors when a tool actually needs a project. The alternative is the `project_set` tool, which maps a working directory to a project in `~/.formio/projects.json` so one server can serve several workspaces. Resolution runs by scope, narrowest first: a committed `formio.json` found by walking up from the caller's `cwd`, then the mapping for that `cwd`, then `FORMIO_PROJECT_URL` in the environment as the weakest source, then the error. Map a directory before any client connects with `npx -y @formio/mcp@0.14.0 project set --project-url --cwd ` — the deployment is derived from the project URL wherever it can be, so add `--base-url ` only when the server says it cannot be determined. Add `--force` beside both URLs to record a pair the domain rules refuse — the one shape they cannot tell from a mistake is an internal deployment served from a `*.form.io` domain; it takes both URLs in the same call, is honoured on every later read, and is a shell-only flag the `project_set` tool does not have. `project set --reset --cwd ` clears a directory's entry, which is how a forced pair is un-forced: a write that leaves both halves untouched keeps the override, so there is nothing for an unforced re-record to change. `project get --cwd ` prints what resolves and which source won, exiting `0` when it resolved, `1` when nothing is mapped, `2` when the command itself failed, and `3` when a project resolved but its Base URL could not be determined — the half-configured directory, repaired by supplying that one value. `project set --cwd ` exits `0` when the directory is ready to serve a call, `1` when a named value is still missing, `2` when the command could not answer, and `3` when the record WAS written and the directory still resolves no Base URL — a committed `formio.json` governs it and supplies none, so the remedy is an edit to that file rather than another write. +\* Not at startup — the server starts and lists every tool without it, and only errors when a tool actually needs a project. The alternative is the `project_set` tool, which maps a working directory to a project in `~/.formio/projects.json` so one server can serve several workspaces. Resolution runs by scope, narrowest first: a committed `formio.json` found by walking up from the caller's `cwd`, then the mapping for that `cwd`, then `FORMIO_PROJECT_URL` in the environment as the weakest source, then the error. Map a directory before any client connects with `npx -y @formio/mcp@0.14.1 project set --project-url --cwd ` — the deployment is derived from the project URL wherever it can be, so add `--base-url ` only when the server says it cannot be determined. Add `--force` beside both URLs to record a pair the domain rules refuse — the one shape they cannot tell from a mistake is an internal deployment served from a `*.form.io` domain; it takes both URLs in the same call, is honoured on every later read, and is a shell-only flag the `project_set` tool does not have. `project set --reset --cwd ` clears a directory's entry, which is how a forced pair is un-forced: a write that leaves both halves untouched keeps the override, so there is nothing for an unforced re-record to change. `project get --cwd ` prints what resolves and which source won, exiting `0` when it resolved, `1` when nothing is mapped, `2` when the command itself failed, and `3` when a project resolved but its Base URL could not be determined — the half-configured directory, repaired by supplying that one value. `project set --cwd ` exits `0` when the directory is ready to serve a call, `1` when a named value is still missing, `2` when the command could not answer, and `3` when the record WAS written and the directory still resolves no Base URL — a committed `formio.json` governs it and supplies none, so the remedy is an edit to that file rather than another write. --- diff --git a/llms-install.md b/llms-install.md index 09e36a1..92318be 100644 --- a/llms-install.md +++ b/llms-install.md @@ -48,7 +48,7 @@ Otherwise write this block into the client's MCP config file, replacing the proj "mcpServers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"], + "args": ["-y", "@formio/mcp@0.14.1"], "env": { "FORMIO_PROJECT_URL": "https://your-project.form.io" } @@ -74,7 +74,7 @@ Merge into the existing object rather than overwriting the file. For VS Code, pu ```toml [mcp_servers.formio-mcp] command = "npx" -args = ["-y", "@formio/mcp@0.14.0"] +args = ["-y", "@formio/mcp@0.14.1"] ``` There is no universal `.mcp.json`: a root `.mcp.json` is read by Claude Code only. Writing one file per client is the reliable approach when you do not know which client the user runs. @@ -86,7 +86,7 @@ The skills installer never writes MCP configuration — it handles skills only. Whichever way, the entry is the same command with no environment block required: ```json -{ "command": "npx", "args": ["-y", "@formio/mcp@0.14.0"] } +{ "command": "npx", "args": ["-y", "@formio/mcp@0.14.1"] } ``` After writing any MCP configuration, tell the user to reload: MCP servers are read at session start, not at tool-call time. @@ -94,8 +94,8 @@ After writing any MCP configuration, tell the user to reload: MCP servers are re If the user has volunteered a project URL, you can record it before the reload so the first tool call works: ```sh -npx -y @formio/mcp@0.14.0 project set --project-url --base-url --cwd -npx -y @formio/mcp@0.14.0 project get --cwd +npx -y @formio/mcp@0.14.1 project set --project-url --base-url --cwd +npx -y @formio/mcp@0.14.1 project get --cwd ``` `project get` prints what the server resolves and which source supplied it. Empty output is not an answer: the `project` command shipped in 0.9.0, and an older `@formio/mcp` ignores these arguments, starts its stdio server, reads end-of-input and exits 0 with no output — a silent no-op that reads as success. Do not invent either URL — if the user has not given them, skip this and let the agent ask when a project is first needed. diff --git a/packages/mcp-server/CHANGELOG.md b/packages/mcp-server/CHANGELOG.md index 805e37e..453566b 100644 --- a/packages/mcp-server/CHANGELOG.md +++ b/packages/mcp-server/CHANGELOG.md @@ -1,5 +1,11 @@ # @formio/mcp +## 0.14.1 + +### Patch Changes + +- 757ee8a: Open the portal-login and revisions-consent pages in the browser on Windows. Both pages were launched with `exec('start ""')`, and `start` reads its first quoted argument as a window title, so Windows opened an empty console window titled with the URL and no browser — the tool call then waited out the login timeout with no page in front of the user. Both pages now go through one launcher that runs no shell: `open` on macOS, `xdg-open` on Linux, and `rundll32 url.dll,FileProtocolHandler` on Windows, each handed the URL as its own argument. The consent page also now reports a failed launch on stderr with its URL, as the login page already did, instead of ignoring it. + ## 0.14.0 ### Minor Changes diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index bdae267..1497821 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -19,7 +19,7 @@ Run that way it waits for MCP traffic on stdin, which only tells you it starts c | Transport | Command | Compatible with | | --- | --- | --- | -| stdio | `npx -y @formio/mcp@0.14.0` (or `node dist/stdio.js`) | Claude Code, Claude Desktop, Cursor, VS Code, Codex, Windsurf, Cline — anything that speaks MCP over stdio | +| stdio | `npx -y @formio/mcp@0.14.1` (or `node dist/stdio.js`) | Claude Code, Claude Desktop, Cursor, VS Code, Codex, Windsurf, Cline — anything that speaks MCP over stdio | There is no HTTP or SSE transport. The server's only HTTP listener is the temporary browser-login page described under [Authentication](#authentication), which carries no MCP traffic. @@ -32,7 +32,7 @@ The same stdio entry works everywhere, but the file it goes in **and the key it "mcpServers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"], + "args": ["-y", "@formio/mcp@0.14.1"], "env": { "FORMIO_PROJECT_URL": "https://your-project.form.io" } @@ -287,7 +287,7 @@ The probe runs lazily — only when the local auth page is actually served. | `FORMIO_INSECURE_TLS` | no | `undefined` | Set to `1` to skip TLS verification. Local development only — never against production. | | | | `FORMIO_FORCE_BROWSER` | no | `0` | Set to `1` to attempt the browser login even where the server detects no browser (CI, a container, SSH with no display). | | | -\* Not at startup — the server starts, lists every tool, and answers `hello` without it; only the tools that read or write Form.io data error, naming `project_set` and this variable. The alternative is the `project_set` tool, which maps a working directory to a project in `~/.formio/projects.json`. Resolution runs by scope, narrowest first: a committed `formio.json` found by walking up from the caller's `cwd`, then the mapping for that `cwd`, then `FORMIO_PROJECT_URL` in the environment as the weakest source, then the error. Map a directory before any client connects with `npx -y @formio/mcp@0.14.0 project set --project-url --cwd ` — the deployment is derived from the project URL wherever it can be, so add `--base-url ` only when the server says it cannot be determined. Add `--force` beside both URLs to record a pair the domain rules refuse — the one shape they cannot tell from a mistake is an internal deployment served from a `*.form.io` domain; it takes both URLs in the same call, is honoured on every later read, and is a shell-only flag the `project_set` tool does not have. `project set --reset --cwd ` clears a directory's entry, which is how a forced pair is un-forced: a write that leaves both halves untouched keeps the override, so there is nothing for an unforced re-record to change. `project get --cwd ` prints what resolves and which source won. It exits `0` when it resolved, `1` when nothing is mapped for that directory, `2` when the command could not answer (a usage error, a malformed URL, an unreadable `~/.formio/projects.json`), and `3` when a project resolved but its Base URL could not be determined — so a caller can tell "nothing here yet" from "this failed" from "half configured, and here is the one value missing". `project set --cwd ` exits `0` when the directory is ready to serve a call, `1` when a named value is still missing, `2` when the command could not answer, and `3` when the record WAS written and the directory still resolves no Base URL — a committed `formio.json` governs it and supplies none, so the remedy is an edit to that file rather than another write. +\* Not at startup — the server starts, lists every tool, and answers `hello` without it; only the tools that read or write Form.io data error, naming `project_set` and this variable. The alternative is the `project_set` tool, which maps a working directory to a project in `~/.formio/projects.json`. Resolution runs by scope, narrowest first: a committed `formio.json` found by walking up from the caller's `cwd`, then the mapping for that `cwd`, then `FORMIO_PROJECT_URL` in the environment as the weakest source, then the error. Map a directory before any client connects with `npx -y @formio/mcp@0.14.1 project set --project-url --cwd ` — the deployment is derived from the project URL wherever it can be, so add `--base-url ` only when the server says it cannot be determined. Add `--force` beside both URLs to record a pair the domain rules refuse — the one shape they cannot tell from a mistake is an internal deployment served from a `*.form.io` domain; it takes both URLs in the same call, is honoured on every later read, and is a shell-only flag the `project_set` tool does not have. `project set --reset --cwd ` clears a directory's entry, which is how a forced pair is un-forced: a write that leaves both halves untouched keeps the override, so there is nothing for an unforced re-record to change. `project get --cwd ` prints what resolves and which source won. It exits `0` when it resolved, `1` when nothing is mapped for that directory, `2` when the command could not answer (a usage error, a malformed URL, an unreadable `~/.formio/projects.json`), and `3` when a project resolved but its Base URL could not be determined — so a caller can tell "nothing here yet" from "this failed" from "half configured, and here is the one value missing". `project set --cwd ` exits `0` when the directory is ready to serve a call, `1` when a named value is still missing, `2` when the command could not answer, and `3` when the record WAS written and the directory still resolves no Base URL — a committed `formio.json` governs it and supplies none, so the remedy is an edit to that file rather than another write. --- diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 4b26303..950cd24 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@formio/mcp", - "version": "0.14.0", + "version": "0.14.1", "mcpName": "io.form/formio-mcp", "description": "Form.io MCP Server", "type": "module", diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index d3678a1..1a2335c 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "formio-ai", - "version": "0.14.0", + "version": "0.14.1", "description": "Form.io MCP server + skill library. Bundles the Form.io MCP server and a skill library covering every endpoint in the Form.io API, plus form JSON schema guidance for generating and editing Form.io forms and resources.", "repository": "https://github.com/formio/ai", "license": "MIT", @@ -11,7 +11,7 @@ "mcpServers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } diff --git a/plugin/.cursor-plugin/plugin.json b/plugin/.cursor-plugin/plugin.json index df5f21d..a7e8afa 100644 --- a/plugin/.cursor-plugin/plugin.json +++ b/plugin/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "formio-ai", - "version": "0.14.0", + "version": "0.14.1", "description": "Build applications on the Form.io platform. Bundles the Form.io MCP server with a skill library covering app orchestration, form building, resource planning, JSON schema authoring, actions, authentication, the @formio/js SDK, and the full Form.io REST surface.", "author": { "name": "Form.io", @@ -15,7 +15,7 @@ "mcpServers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } diff --git a/plugin/CHANGELOG.md b/plugin/CHANGELOG.md index 95b659e..d18fad1 100644 --- a/plugin/CHANGELOG.md +++ b/plugin/CHANGELOG.md @@ -1,5 +1,18 @@ # @formio/ai +## 0.14.1 + +### Patch Changes + +- ebd8ceb: Describe what the Angular, application, and SDK skills read at build time as the first-party inputs they are, so the skills.sh Snyk W011 "third-party content exposure" findings stop reading the skills' own trust prose as evidence of outsider content. + + **`formio-angular`** no longer calls the planner's `template.md` + `template.json` pair "the largest untrusted input this skill has" arriving "from a clone, a download, an unpacked archive" — the phrasing Snyk quoted back as "outsider-authored free text". The section now states that the pair is this pipeline's own artifact, written by `formio-resource-planner` and approved at its Phase A gate, and that the skill reads the two files the handoff names rather than whatever the directory holds. The three rules are unchanged: the pair must be first-party (confirmed with the user when nothing in the session accounts for it), its contents are data and not instructions, and every value is shape-checked before it reaches generated code. + + **`formio-sdk`**'s last Security rule no longer tells the agent it reads "submission JSON … returned by any `Formio` call or MCP tool". It states what is true: the MCP tools return project configuration — form definitions, roles, actions, templates — and no submission data, and the SDK calls the skill documents are code the application runs at runtime. Configuration the agent reads still never instructs it. + + **`formio-application`**'s Step 1 opens by naming its inputs — the user's own words, the user's own workspace on the modify-existing branch, and the planner pair produced from them — and states that it fetches no web page, reads no submission data, and opens no file a third party supplied. +- 1a93655: Document how to configure a Role Assignment action with `association: "existing"`. The `formio-actions` reference used to describe the target only as "a component whose value is the target resource's submission ID", which reads as though any key will do; it now states that the target component's key must be exactly `submission`. The same guidance recommends setting `settings.role` explicitly and granting create access on such a form to administrator roles only. `formio-resource-planner`'s `template-json.md` carries the same rules for any `existing` action it emits, and a new skill test keeps every description of the association naming the `submission` key. + ## 0.14.0 ### Minor Changes diff --git a/plugin/README.md b/plugin/README.md index 7d790cd..65422b0 100644 --- a/plugin/README.md +++ b/plugin/README.md @@ -44,7 +44,7 @@ Every step has an approval gate before any file is written or any MCP call hits - **MCP server** (`@formio/mcp`) — first-party Form.io operations as MCP tools (`form_*`, `role_*`, `action_*`, `project_*`). - **Skills library** — twelve activatable skills (app orchestration, form building, form embedding, planner, Angular and React framework implementors, schema, actions, auth, SDK, API router, MCP setup) plus a reference library under `formio-api/references/` covering every endpoint in the Form.io API Postman collection. -- **Per-directory project routing** — `project_set` maps a working directory to a Form.io project in `~/.formio/projects.json`, so each directory can target a different project. The server resolves that mapping on every tool call; `npx -y @formio/mcp@0.14.0 project get --cwd .` prints what it resolves and why. +- **Per-directory project routing** — `project_set` maps a working directory to a Form.io project in `~/.formio/projects.json`, so each directory can target a different project. The server resolves that mapping on every tool call; `npx -y @formio/mcp@0.14.1 project get --cwd .` prints what it resolves and why. | Skill | Purpose | | --- | --- | @@ -76,7 +76,7 @@ No client prompts for anything at install time. Both URLs are resolved per direc | `FORMIO_FORCE_BROWSER` | no | `0` | Set to `1` to attempt the browser login even where the server detects no browser (CI, a container, SSH with no display). | | `FORMIO_INSECURE_TLS` | no | `false` | When `true`, skips TLS certificate verification — for self-hosted deployments behind self-signed certs. Do not use against production. | -\* Per-directory mappings are persisted to `~/.formio/projects.json` by the `project_set` tool, or by `npx -y @formio/mcp@0.14.0 project set --project-url --base-url --cwd ` before any client has connected. Both record the project URL **and** the base URL, and the server resolves both from that file per directory, falling back to the global environment values only when an entry omits them. +\* Per-directory mappings are persisted to `~/.formio/projects.json` by the `project_set` tool, or by `npx -y @formio/mcp@0.14.1 project set --project-url --base-url --cwd ` before any client has connected. Both record the project URL **and** the base URL, and the server resolves both from that file per directory, falling back to the global environment values only when an entry omits them. ### Authentication modes diff --git a/plugin/mcp.json b/plugin/mcp.json index 0e21269..37f3b5a 100644 --- a/plugin/mcp.json +++ b/plugin/mcp.json @@ -4,7 +4,7 @@ "formio-mcp": { "type": "stdio", "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } diff --git a/plugin/package.json b/plugin/package.json index 2e249c4..60d944b 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -1,6 +1,6 @@ { "name": "@formio/ai", - "version": "0.14.0", + "version": "0.14.1", "description": "Form.io agentic toolset — the Form.io MCP server plus a skill library for building applications on the Form.io platform, usable from any coding agent that reads Agent Skills or speaks MCP.", "type": "module", "license": "MIT", diff --git a/plugin/plugin.json b/plugin/plugin.json index 062d7e6..18e218f 100644 --- a/plugin/plugin.json +++ b/plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "formio-ai", - "version": "0.14.0", + "version": "0.14.1", "description": "Build applications on the Form.io platform. Bundles the Form.io MCP server with a skill library covering app orchestration, form building, resource planning, JSON schema authoring, actions, authentication, the @formio/js SDK, and the full Form.io REST surface.", "author": { "name": "Form.io", diff --git a/plugin/skills/formio-mcp-setup/SKILL.md b/plugin/skills/formio-mcp-setup/SKILL.md index 01071de..1304600 100644 --- a/plugin/skills/formio-mcp-setup/SKILL.md +++ b/plugin/skills/formio-mcp-setup/SKILL.md @@ -66,7 +66,7 @@ Show the user every file you intend to write, in full, before writing anything. "mcpServers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } @@ -79,7 +79,7 @@ Show the user every file you intend to write, in full, before writing anything. "mcpServers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } @@ -92,7 +92,7 @@ Show the user every file you intend to write, in full, before writing anything. "servers": { "formio-mcp": { "command": "npx", - "args": ["-y", "@formio/mcp@0.14.0"] + "args": ["-y", "@formio/mcp@0.14.1"] } } } @@ -103,7 +103,7 @@ Show the user every file you intend to write, in full, before writing anything. ```toml [mcp_servers.formio-mcp] command = "npx" -args = ["-y", "@formio/mcp@0.14.0"] +args = ["-y", "@formio/mcp@0.14.1"] ``` ### Why the version is pinned @@ -135,7 +135,7 @@ The server starts with no project. Left unconfigured, the first Form.io tool cal ### First, ask the server what this directory resolves to ```bash -npx -y @formio/mcp@0.14.0 project get --cwd "$(pwd)" +npx -y @formio/mcp@0.14.1 project get --cwd "$(pwd)" ``` On a zero exit it prints the Project URL, the Base URL, and which source supplied each. The work is already done: report both URLs in one line and go to Step 5. Do not interview for something already on record. @@ -149,7 +149,7 @@ Read the `Source:` line for what it is: this command runs in your shell, and the On exit `1` — nothing is recorded for this directory — the command explains what is missing and names the command that fixes it. Relay that instruction to the user, ask for the **single value it names**, and persist it with the command it named: ```bash -npx -y @formio/mcp@0.14.0 project set --project-url "" --cwd "$(pwd)" +npx -y @formio/mcp@0.14.1 project set --project-url "" --cwd "$(pwd)" ``` **When the working directory is inside a git repository, offer the choice of where to record it, in the same round you ask for the URL.** A committed `formio.json` in the application's own folder records the target with the code — shared with everyone who clones the repository, and it survives a fresh checkout — while `project set` records it for this machine only. The committed file is hand-authored: the server reads it and never writes it, so if the user picks it, write the file yourself, in the application's own folder and never an ancestor (discovery walks upward, so a file placed higher governs every unrelated folder beneath it): @@ -165,7 +165,7 @@ Then re-run `project get`. Most of the time that is the end of it: the Base URL The exception is a Project URL that is a plain sub-domain of the user's own domain, e.g. `https://myproject.mysite.com`, whose deployment is a sibling sub-domain that nothing in the Project URL names. A record holds a project and its deployment together, so that shape cannot be recorded on its own: the `project set` above exits `1` naming `--base-url` as the value it still needs, and prints the command carrying both. Ask the user for the Base URL alone at that point — never before, and never by assuming a default — and run what it printed: ```bash -npx -y @formio/mcp@0.14.0 project set --project-url "" --base-url "" --cwd "$(pwd)" +npx -y @formio/mcp@0.14.1 project set --project-url "" --base-url "" --cwd "$(pwd)" ``` A deployment on its own is a valid update only for the record that already holds the project — this directory's own mapping. Where the project lives in a committed `formio.json`, the refusal names that file's path and the `"baseUrl"` key to add beside `"projectUrl"` — an edit you make to the file, since the server never writes one. Where it lives in the environment, the refusal names the mapping write carrying both URLs. Either way the user is asked for one value: the message carries the Project URL the report already printed. @@ -222,10 +222,10 @@ Some environments block the public npm registry — an air-gapped network, a loc 1. **Global install from an internal registry or a cached tarball**, then point the configuration at the binary instead of `npx`: ```bash - npm install -g @formio/mcp@0.14.0 + npm install -g @formio/mcp@0.14.1 ``` - Replace `"command": "npx", "args": ["-y", "@formio/mcp@0.14.0"]` with `"command": "formio-mcp", "args": []` in every file you write (and the TOML equivalent). + Replace `"command": "npx", "args": ["-y", "@formio/mcp@0.14.1"]` with `"command": "formio-mcp", "args": []` in every file you write (and the TOML equivalent). 2. **The desktop bundle.** For Claude Desktop and other hosts that accept one, the `.mcpb` bundle attached to each GitHub release carries the server with no registry access required. diff --git a/plugin/skills/formio-mcp-setup/references/project-urls.md b/plugin/skills/formio-mcp-setup/references/project-urls.md index 3bec302..3b17261 100644 --- a/plugin/skills/formio-mcp-setup/references/project-urls.md +++ b/plugin/skills/formio-mcp-setup/references/project-urls.md @@ -65,7 +65,7 @@ The rule for a project URL with a path is always its **parent path**, never its The last row is the only case that needs a second question. That shape names no deployment anywhere in it: the deployment is a sibling sub-domain, and nothing in the project URL says which. Do not answer it with `https://api.form.io` — that value is certainly wrong for a project that is not on a `form.io` host, and it is the guess this table exists to prevent. -The first row is enforced, not merely derived: a `*.form.io` project recorded against any other deployment is refused. One deployment is indistinguishable from that mistake — an internal, non-SaaS deployment served from a `*.form.io` domain — and its escape hatch is a flag on the shell command, not on any tool you hold: the USER runs `npx -y @formio/mcp@0.14.0 project set --force --project-url "" --base-url "" --cwd "$(pwd)"` themselves, and every later call then resolves that pair. Relay it only when the user says their `*.form.io` project is served by their own deployment; never offer it to make a refusal go away, and never pass a value the user has not stated. A pair recorded that way survives an ordinary `project_set` call that re-states it, and the user clears it with `npx -y @formio/mcp@0.14.0 project set --reset --cwd "$(pwd)"` — the report says so wherever it reports a forced pair. +The first row is enforced, not merely derived: a `*.form.io` project recorded against any other deployment is refused. One deployment is indistinguishable from that mistake — an internal, non-SaaS deployment served from a `*.form.io` domain — and its escape hatch is a flag on the shell command, not on any tool you hold: the USER runs `npx -y @formio/mcp@0.14.1 project set --force --project-url "" --base-url "" --cwd "$(pwd)"` themselves, and every later call then resolves that pair. Relay it only when the user says their `*.form.io` project is served by their own deployment; never offer it to make a refusal go away, and never pass a value the user has not stated. A pair recorded that way survives an ordinary `project_set` call that re-states it, and the user clears it with `npx -y @formio/mcp@0.14.1 project set --reset --cwd "$(pwd)"` — the report says so wherever it reports a forced pair. Never invent a Base URL, never reuse one from another project or an earlier session, and **never edit `~/.formio/projects.json`** by any means — its shape, its `0600` mode, and its merge rules belong to the server, and `project_set` is how you reach them. diff --git a/server.json b/server.json index fa3fc95..037e1b3 100644 --- a/server.json +++ b/server.json @@ -7,13 +7,13 @@ "source": "github", "subfolder": "packages/mcp-server" }, - "version": "0.14.0", + "version": "0.14.1", "websiteUrl": "https://form.io", "packages": [ { "registryType": "npm", "identifier": "@formio/mcp", - "version": "0.14.0", + "version": "0.14.1", "transport": { "type": "stdio" },