An MCP server for Umbraco Forms. Point it at an Umbraco instance and your AI assistant can build forms, manage data sources and prevalue sources, read submissions, query analytics, and submit entries — 118 tools across 25 collections.
Built on @umbraco-cms/mcp-server-sdk.
- Node.js 22.23.4+, 24.22.1+ or 26.12.1+. Earlier releases are affected by CVE-2026-111497 (Brotli decoder out-of-bounds write), which Node's built-in
fetchreaches when it decompresses a Brotli response from Umbraco. Upgrading Node.js is the only fix. - An Umbraco instance with Umbraco Forms installed, reachable over HTTP(S)
- An API user on that instance (see below)
This version targets Umbraco 18 with Umbraco Forms 18.x. Connecting to a different major
version warns and blocks the first tool call; set UMBRACO_EXPECTED_MAJOR to override if you know
what you're doing.
| Umbraco | Umbraco Forms | Package |
|---|---|---|
| 18 | 18.x | @umbraco-forms/mcp-dev |
| 17 | 17.x | @umbraco-forms/mcp-dev@lts-17-beta |
Install the version that matches your site's Umbraco major — the API client and the version check differ between them.
The Umbraco 17 line is in beta and published under the lts-17-beta dist-tag. A range such as
@17 doesn't match prereleases and won't find a version until 17.0.0 is released.
Every Umbraco Forms release on the matching major works. Some endpoints arrived partway through a line, at a different minor on each major; on an older release the tools that need them fail with a message naming the version they need, and the rest are unaffected:
| Tools | Forms 18.x | Forms 17.x |
|---|---|---|
The nine recycle-bin tools, list-form-versions, get-form-version, rollback-form-version, set-form-version-prevent-cleanup, get-form-audit-log, create-record, delete-record |
18.2+ | 17.6+ |
get-member-linkable-properties, get-member-form-summaries |
18.1+ | 17.5+ |
get-prevalue-source-text-file |
18.0+ | 17.4+ |
list-forms (use list-all-forms before 17.3), the six query-analytics-* tools |
18.0+ | 17.3+ |
search-forms, get-forms-are-referenced, get-form-referenced-by, get-form-referenced-descendants |
18.0+ | 17.2+ |
get-form-tree-ancestors, get-data-source-ancestors, get-prevalue-source-ancestors |
18.0+ | 17.1+ |
From Forms 18.2, delete-form and delete-folder move items to the Forms recycle bin instead of
deleting them; the recycle-bin tools restore them or delete them for good.
In the Umbraco backoffice:
- Go to Settings → Users
- Create a new API user
- Note its Client ID and Client Secret
- Grant it permissions for the Forms sections you want the assistant to reach
The server authenticates with those credentials via OAuth client credentials.
Add to your .mcp.json (or claude_desktop_config.json):
{
"mcpServers": {
"umbraco-forms": {
"command": "npx",
"args": ["-y", "@umbraco-forms/mcp-dev"],
"env": {
"UMBRACO_BASE_URL": "https://your-site.example.com",
"UMBRACO_CLIENT_ID": "your-client-id",
"UMBRACO_CLIENT_SECRET": "your-client-secret"
}
}
}
}Restart your client and the tools appear.
The server speaks MCP over stdio. Run it however your client spawns servers:
UMBRACO_BASE_URL=https://your-site.example.com \
UMBRACO_CLIENT_ID=your-client-id \
UMBRACO_CLIENT_SECRET=your-client-secret \
npx -y @umbraco-forms/mcp-devAdd "NODE_TLS_REJECT_UNAUTHORIZED": "0" to env. Only do this against local development
instances — it disables certificate verification process-wide.
Without wiring up a client:
# List every tool this server exposes
npx -y @umbraco-forms/mcp-dev --list-tools
# Show resolved configuration and where each value came from
npx -y @umbraco-forms/mcp-dev --debug-config
# Call a tool directly
UMBRACO_BASE_URL=... UMBRACO_CLIENT_ID=... UMBRACO_CLIENT_SECRET=... \
npx -y @umbraco-forms/mcp-dev --call list-forms --call-args '{}'--describe-tool <name> prints a single tool's full input schema.
Every option is an environment variable, and most also have a CLI flag (--help lists them).
| Variable | Required | Purpose |
|---|---|---|
UMBRACO_BASE_URL |
yes | Base URL of your Umbraco instance |
UMBRACO_CLIENT_ID |
yes | API user's client ID |
UMBRACO_CLIENT_SECRET |
yes | API user's client secret |
UMBRACO_FORMS_API_KEY |
no | Forms Delivery API key — see below |
UMBRACO_EXPECTED_MAJOR |
no | Override the expected Umbraco major version |
118 tools is a lot of context. Narrow it down:
| Variable | Purpose |
|---|---|
UMBRACO_TOOL_MODES |
Enable named groups of collections (see below) |
UMBRACO_INCLUDE_TOOL_COLLECTIONS |
Only these collections |
UMBRACO_EXCLUDE_TOOL_COLLECTIONS |
Everything except these |
UMBRACO_INCLUDE_TOOLS / UMBRACO_EXCLUDE_TOOLS |
Individual tools by name |
UMBRACO_INCLUDE_SLICES / UMBRACO_EXCLUDE_SLICES |
By operation type, e.g. delete |
UMBRACO_READONLY |
Block every write operation |
UMBRACO_DRY_RUN |
Log writes instead of performing them |
Available modes:
| Mode | Includes |
|---|---|
forms-authoring |
Building forms: forms, templates, field types, pickers, folders, recycle bin, themes |
data-sources |
Data sources and prevalue sources |
submissions |
Submitted records, analytics, workflow types |
admin |
Config, licensing, updates, members, email templates, export/import |
forms-management-all |
All 22 Forms management collections |
umbraco-server |
Server information only |
"env": {
"UMBRACO_TOOL_MODES": "forms-authoring,submissions",
"UMBRACO_READONLY": "true"
}Note: the Delivery API tools (
form-submission) aren't part of any mode. If you setUMBRACO_TOOL_MODES, add"UMBRACO_INCLUDE_TOOL_COLLECTIONS": "form-submission"to keep them.
| Collection | Tools | What it covers |
|---|---|---|
form |
33 | Create, edit, copy, move, export and inspect forms; version history and audit log |
data-source / data-source-type |
12 | External data sources backing form fields |
prevalue-source / prevalue-source-type |
12 | Dropdown/checkbox value sources |
record |
11 | Submitted entries — search, read, create, update, delete, workflow actions |
recycle-bin |
9 | Browse, restore and permanently delete trashed forms and folders |
folder |
7 | Organising forms into folders |
analytics |
6 | Submission and workflow analytics |
picker |
4 | Document type and data type pickers |
field-type |
4 | Available field types and validation patterns |
export |
3 | Export forms and submissions |
form-submission |
2 | Delivery API: read definitions, submit entries |
member, email-template, workflow-type |
6 | Members, email templates, workflow types |
config, licensing, updates, theme, media, form-template, acceptance-tests, umbraco-server |
8 | Server-wide settings and status |
chained |
1 | Info about the chained CMS server |
Run --list-tools for the full list with descriptions.
Three ways, in order of preference:
create-simple-form— a name and a flat list of{label, type}fields. Generates every GUID, page, fieldset and default for you. Use this for ordinary forms.add-form-fields/delete-form-field— edit an existing form without restating it.create-form/update-form— the full design, for conditions, workflows, multiple pages or custom field types.
Two tools — get-form-definition and submit-form-entry — use Umbraco's public Forms Delivery
API rather than the Management API. They let an assistant read a form the way a frontend sees it
(including field aliases) and submit entries against it.
These need extra setup, because the Delivery API is off by default and authenticates with an
Api-Key header instead of OAuth.
In your Umbraco project's appsettings.json:
{
"Umbraco": {
"Forms": {
"Options": {
"EnableFormsApi": true
},
"Security": {
"EnableAntiForgeryTokenForFormsApi": false,
"FormsApiKey": "<a long random string>"
}
}
}
}EnableFormsApi— the master switch; defaults tofalse.FormsApiKey— the shared secret sent as theApi-Keyheader.EnableAntiForgeryTokenForFormsApi: false— needed for server-to-server callers. The default (true) expects a browser-issued antiforgery token that an MCP server can't obtain, so leaving it on rejects requests that carry a valid key.
Restart the site, then set the matching key:
"env": {
"UMBRACO_FORMS_API_KEY": "<the same value as FormsApiKey>"
}Treat the key as a credential. Turning off the antiforgery token disables CSRF protection for the Forms API on that instance, and anyone holding
FormsApiKeycan submit entries to any form on it. Consider carefully before enabling this on production.
Full details in Umbraco's Headless/AJAX Forms docs.
By default this server also chains to @umbraco-cms/mcp-dev
(@18 on this line, the CMS MCP's Umbraco 18 releases), exposing CMS tools (documents, media, members) alongside the Forms ones, prefixed cms--
(e.g. cms--get-document). It reuses the same credentials.
Set DISABLE_MCP_CHAINING=true to turn this off and run Forms tools only.
| Symptom | Likely cause |
|---|---|
401 on every tool |
Wrong UMBRACO_CLIENT_ID / UMBRACO_CLIENT_SECRET, or the API user lacks permissions |
| Self-signed certificate errors | Local HTTPS instance — set NODE_TLS_REJECT_UNAUTHORIZED=0 |
| Version mismatch warning, first tool call blocked | Instance isn't Umbraco 18 — use @umbraco-forms/mcp-dev@lts-17-beta for Umbraco 17, or set UMBRACO_EXPECTED_MAJOR |
| A tool says it needs a newer Umbraco Forms | The endpoint arrived later in the line — see the table under Requirements |
403 from the Delivery API tools |
UMBRACO_FORMS_API_KEY missing or not matching FormsApiKey, or EnableAntiForgeryTokenForFormsApi is still true |
404 from the Delivery API for a form that exists |
EnableFormsApi isn't true, or the site wasn't restarted |
| A tool you expected isn't listed | Check UMBRACO_TOOL_MODES and the include/exclude variables with --debug-config |
Setting up the repo, running the demo Umbraco site and the test suites: see CONTRIBUTING.md.
MIT