@noeva/formify-mcp
v1.10.0
Published
MCP server for Noeva Formify (forms and responses) — protocol adapter over the noeva-server-api REST API. Ships an HTTP service (central deploy) and a stdio package (client-distributable).
Readme
@my-ginkgo/noeva-formify-mcp
An MCP server for Noeva Formify — the form /
survey builder. It is a thin protocol adapter: it translates MCP tools/call
requests into HTTP calls against the existing noeva-server-api Formify REST API. It
holds no business logic, never talks to a database, and stores no Noeva secrets.
It is the sibling of noeva-mcp-core and
noeva-mcp-crm: same architecture, same two transports, same
token pass-through trust model.
Public install (npm)
Installazione pubblica senza credenziali GitHub:
npx -y @noeva/formify-mcpConfig MCP (es. Claude Desktop):
{
"mcpServers": {
"noeva-formify": {
"command": "npx",
"args": ["-y", "@noeva/formify-mcp"],
"env": {
"NOEVA_API_BASE_URL": "https://api.noeva.ai",
"NOEVA_API_KEY": "noeva_sk_..."
}
}
}
}Il canale
@my-ginkgo/noeva-formify-mcpsu GitHub Packages resta disponibile per uso interno (richiede un PATread:packages).
The same codebase ships two transports:
| Transport | Who runs it | Auth source | How it's distributed |
| --------- | ---------------------- | -------------------------------------------- | -------------------------- |
| HTTP | Noeva (central deploy) | per-request bearer token | Docker image |
| stdio | the customer (local) | NOEVA_API_KEY env (a noeva_sk_… API key) | npm package, run via npx |
Scope
This server adapts the authenticated, workspace-owner surface of Formify
(/api/workspaces/:id/formify/…): managing forms and their responses. The public
respondent flows (submit/draft a response, upload files, redeem a reward) are
intentionally not exposed — they target the person filling the form, not the
workspace owner driving the agent.
Tools
Two consolidated tools, each with an action selector. Every action takes a
workspace_id (UUID).
| Tool | Actions |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| formify_forms | list, get, check_slug, get_notifications (read); create, update, update_settings, update_reward, update_notifications, duplicate, delete (write) |
| formify_responses | list (read); delete (write) |
Write actions require confirmation (elicitation or a HMAC-bound confirm_token).
delete is destructive: deleting a form cascades to all its responses.
The complex nested fields — schema (the form definition: fields, sections,
settings), settings, reward, and notification rules — are passed through as
free-form JSON objects. noeva-server-api is the authoritative validation boundary.
Install for a client (stdio)
You run the server locally; your MCP client (Claude Desktop, an IDE, …) launches it.
1. Generate a NOEVA API key
In the Noeva app, go to Profile → API Keys and create a key. It looks like
noeva_sk_…, is long-lived, personal and revocable, and acts with your own
permissions; every operation is scoped to the workspaces you belong to. (A normal
session JWT expires after ~1 hour and is rejected here — the key must start with
noeva_sk_.)
2. Add the server to your MCP client config
{
"mcpServers": {
"noeva-formify": {
"command": "npx",
"args": ["-y", "@my-ginkgo/noeva-formify-mcp"],
"env": {
"NOEVA_API_KEY": "noeva_sk_…",
"NOEVA_API_BASE_URL": "https://api.noeva.ai",
},
},
},
}Package registry. This package is published to GitHub Packages under the private
@my-ginkgoscope, sonpxneeds read access. Add to your~/.npmrc:@my-ginkgo:registry=https://npm.pkg.github.com //npm.pkg.github.com/:_authToken=<GitHub PAT with read:packages>The PAT must belong to an account granted access to the
my-ginkgoorg.
NOEVA_API_BASE_URL must be https (plain http is allowed only for localhost).
3. Revoke access
Revoke the API key in the Noeva app (Profile → API Keys). The server has no other credentials, so revoking the key fully revokes the integration.
Confirmation for writes
Writes never execute silently. The server confirms first, via one of two channels:
- Elicitation (if your client supports it): you get a confirmation prompt.
- Dry-run + confirmation token (fallback): the first call returns a preview and a
confirm_token; call again with the identical arguments plus that token to execute. The token is bound to the exact arguments and expires.
Security model
noeva-server-api is the only trust boundary. This server:
- forwards your token as an opaque bearer credential and never verifies or decodes it;
- holds no Noeva secrets (no
SUPABASE_JWT_SECRET, no service key) — the stdio package is fully inspectable and contains nothing privileged; - can do nothing your token cannot already do — there is no escalation path.
Logs (always on stderr in stdio mode) never contain tokens or PII.
Development
pnpm install
pnpm dev:stdio # run the stdio transport (reads .env)
pnpm dev:http # run the HTTP transport
pnpm inspect # launch the MCP Inspector against the stdio build
pnpm test # vitest
pnpm lint
pnpm buildCopy .env.example to .env for local dev (gitignored; never used in production).
HTTP deploy (central)
Built as a Docker image (Dockerfile). It is stateless and scales horizontally; set a
shared MCP_CONFIRMATION_SECRET across instances so dry-run and execute can land on
different replicas. Health check: GET /health. OAuth resource metadata is advertised
at /.well-known/oauth-protected-resource.
Status / known limitations (v1)
- stdio distribution depends on
noeva-server-apiaccepting long-lived personal API keys (noeva_sk_…, sent asAuthorization: Bearer) on the Formify routes — the same P1 prerequisite shared withnoeva-mcp-core/noeva-mcp-crm. The HTTP transport (per-request session bearer, for Mastra) is not blocked. - Rate limiting in-process is a courtesy guard only; authoritative per-token
limiting lives in
noeva-server-api(prerequisite P2).
