Furrow Forms

com.furrowformsPublished by furrowforms.comOfficial publisherv1.0.1Updated Oct 25, 2026

Form backend an agent runs end to end: provision forms, snippets, spam, signed webhooks.

Overview

AI-generated overview

Furrow Forms is a hosted form backend that lets an assistant provision websites, forms, snippets and signed webhooks end to end.

What you can do
Manage workspaces and accounts: list and rename teams, read plan, usage, limits, retention and branding, configure the AI spam filter, and generate Stripe upgrade links when plan limits block work. Manage clients and websites: create, inspect, rename and archive clients, and create, patch, archive or rotate the private inbox of projects. Manage forms: create, read and patch forms with inherited settings, and fetch copy-paste HTML, Astro or Next snippets for posting submissions. Read submissions: list and inspect stored submissions with file metadata and inbox links. Configure webhooks: set or replace a project webhook URL and send a signed test event. Bootstrap a whole site: create a client,
When to use it
Use it when an assistant is building or maintaining a website and needs a working form backend without a dashboard handoff: provisioning contact forms, generating embed snippets, checking recent submissions, or wiring signed webhook notifications.
Requirements
A remote endpoint at api.furrowforms.com over streamable HTTP, or the npm package run locally with npx over stdio. Authentication uses a bearer token in the Authorization header or the FURROW_TOKEN environment variable, or OAuth with dynamic client registration. A Furrow Forms account is needed; the free tier covers 100 clean submissions per month.
Before you install
The token (FURROW_TOKEN or Authorization) grants access to the workspace and should be kept secret. Tools create, rename, archive and patch clients, projects and forms, and archiving blocks public submits with no unarchive tool in v1. Rotating a project inbox immediately invalidates previously shared inbox links. Upgrade links lead to Stripe Checkout and a paid yearly plan. Webhook tests send signed events to the configured URL.

Installation

In SourceWeft

  1. Open Furrow Forms in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/com.furrowforms%2Ffurrow-forms/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config.

{
  "mcpServers": {
    "furrow-forms": {
      "type": "http",
      "url": "https://api.furrowforms.com/mcp"
    }
  }
}

README

Furrow Forms

[smithery badge]

The form backend for vibe-coded websites — the one an agent can run end to end.

Your agent built the site. Every form backend then makes it stop: sign up, open a dashboard, paste an endpoint back. Furrow Forms removes the handoff. Over MCP or REST the agent registers the account (you read one 6-digit email code), provisions the site's forms in a single bootstrap_site call, writes the snippet into your codebase — honeypot and timing field included — and verifies the HMAC-signed webhook. No dashboard in the loop.

Fetch furrowforms.com/ai and set up forms for this site.

Paste that into Claude Code, Cursor, or whatever built your site. That is the whole setup.

What's in this repo

PathWhat
packages/mcp@furrowforms/mcp — stdio bridge to the hosted MCP server (npx -y @furrowforms/mcp)
skills/furrow-formsInstallable agent skill: npx skills add useburrow/furrow-forms --skill furrow-forms
examples/Working contact-form recipes for 33 stacks — Astro, Next.js, SvelteKit, Hugo, Lovable, Bolt, v0, Cursor, Claude Code, …
server.jsonOfficial MCP Registry entry
AGENTS.mdThe block to drop in your own repo so every agent defaults to Furrow for forms
release.sh./release.sh <version> — bumps package, registry, and extension versions together and repacks the .mcpb

Connect over MCP

Hosted, streamable HTTP (OAuth or bearer token):

json
{ "mcpServers": { "furrow-forms": { "url": "https://api.furrowforms.com/mcp",  "headers": { "Authorization": "Bearer frw_..." } } } }

Stdio, for clients that need it:

bash
claude mcp add furrow-forms -e FURROW_TOKEN=frw_... -- npx -y @furrowforms/mcp

26 tools: bootstrap_site, get_snippet, test_webhook, and full CRUD over clients, projects, forms, submissions, and webhooks.

Why agents pick it

  • Cold start — POST /api/register mints a token without a human signup flow.
  • One call per site — bootstrap_site is idempotent; re-run it freely.
  • Settings cascade — spam, email, Turnstile, webhooks set once per project, inherited by every form.
  • Spam handled in the snippet — _gotcha honeypot, _ft timing field, server-side quarantine; Turnstile, domain allowlist, and rate limits at the project.
  • Signed webhooks with retries on every tier, including free.
  • Free tier includes the full API and MCP — 100 clean submissions/month. Pro is $199/year, flat.

Links

MIT

Source: README.md at commit a1658d8

Tools

27

list_teams

List teams

Use to see workspaces this token can act on. A team-scoped frw_ token returns that team only. An operator token or an MCP OAuth login returns every team you belong to — pass team_id on list_clients, create_client, and bootstrap_site. Creating another workspace is dashboard-only after signing in and requires a yearly plan; free accounts stay on one team. Do not use this to list clients — call list_clients.

Takes no parameters.

update_team

Update team

Use to rename a team. Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Do not use this to create another workspace — that is dashboard-only and requires yearly. For plan, usage, retention, and branding, call get_account / update_account. Do not use this to change clients or projects.

Parametersnamerequiredteam_id

get_account

Get account

Use to read the team's plan, usage this month, limits, expansion_packs, retention_days, branding, and AI spam filter (ai.typesafe_key_set, ai.notify_suspected_spam). The TypeSafe key itself is never returned. Plans are capacity, not a feature ladder. Free: one workspace, 100 clean submissions/month pooled on the team, 3 active (non-archived) projects, 30-day submission retention, and email.footer_mode / branding.mode stay furrow. Yearly ($199/year): extra workspaces, 10,000 submissions/month, unlimited projects, 730-day retention, branding.mode furrow | off | agency. Expansion packs are $99/year each and add 5,000 submissions/month on a yearly account. MCP, webhooks, snippets, inheritance, Turnstile, and email templates stay available on free. Spam, honeypot, and rejected posts do not count. Use create_upgrade_link to hand a human a Stripe Checkout (or Customer Portal) URL. Pass product=expansion on a yearly team to add a pack. Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Do not use this to list projects — call list_projects.

Parametersteam_id

update_account

Update account

Use to rename the workspace, set branding, or configure the AI spam filter. Pass ai.typesafe_api_key to save this team's TypeSafe key (null clears it; the key is write-only). ai.notify_suspected_spam (default true) emails notify addresses with a Potential spam label when Jev flags a submission; no webhook is sent either way. Heuristic spam stays silent. Free accounts cannot set branding.mode or email.footer_mode to anything but furrow — those writes are ignored. Yearly may set branding.mode to furrow, off, or agency (name + optional link + optional logo; Furrow keeps the layout, no raw HTML). Plans are capacity, not a feature ladder. Free: one workspace, 100 clean submissions/month pooled on the team, 3 active (non-archived) projects, 30-day submission retention, and email.footer_mode / branding.mode stay furrow. Yearly ($199/year): extra workspaces, 10,000 submissions/month, unlimited projects, 730-day retention, branding.mode furrow | off | agency. Expansion packs are $99/year each and add 5,000 submissions/month on a yearly account. MCP, webhooks, snippets, inheritance, Turnstile, and email templates stay available on free. Spam, honeypot, and rejected posts do not count. Use create_upgrade_link to hand a human a Stripe Checkout (or Customer Portal) URL. Pass product=expansion on a yearly team to add a pack. Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Do not use this to change the plan — call create_upgrade_link.

Parametersainameteam_idbranding

list_clients

List clients

Use to browse clients (companies). Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Do not use to list websites — call list_projects with client_id. Archived clients are hidden unless status=all or archived.

Parameterslimitcursorstatusteam_id

get_client

Get client

Use to inspect one client. Do not use to list that client's sites — call list_projects with client_id.

Parametersclient_idrequired

create_client

Create client

Use to add a client (company) by slug. Idempotent on slug unless strict is true. Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Prefer bootstrap_site when also creating a website and forms. Do not put Turnstile or webhooks on a client — those live on the project.

Parametersnamerequiredslugrequiredstrictteam_id

update_client

Update client

Use to rename a client. Do not use this to change domains, Turnstile, or webhooks — call update_project.

Parametersnameclient_idrequired

archive_client

Archive client

Use to archive a client. Do not use this as a hard delete. There is no unarchive tool in v1.

Parametersclient_idrequired

list_projects

List projects

Use to browse websites. Pass client_id to list one client's sites (team is inferred). Without client_id, Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Do not use to read one project's settings — call get_project. Archived projects are hidden unless status=all or archived.

Parameterslimitcursorstatusteam_idclient_id

get_project

Get project

Use to inspect one website's settings, domains, webhook URL, email templates, upload policy, plan, usage this month, limits, retention_days, and branding. Returns stored values plus resolved.email. Secrets are never returned. Plans are capacity, not a feature ladder. Free: one workspace, 100 clean submissions/month pooled on the team, 3 active (non-archived) projects, 30-day submission retention, and email.footer_mode / branding.mode stay furrow. Yearly ($199/year): extra workspaces, 10,000 submissions/month, unlimited projects, 730-day retention, branding.mode furrow | off | agency. Expansion packs are $99/year each and add 5,000 submissions/month on a yearly account. MCP, webhooks, snippets, inheritance, Turnstile, and email templates stay available on free. Spam, honeypot, and rejected posts do not count. Use create_upgrade_link to hand a human a Stripe Checkout (or Customer Portal) URL. Pass product=expansion on a yearly team to add a pack. Do not use to list forms — call list_forms.

Parametersproject_idrequired

list_forms

List forms

Use to list forms. Pass project_id for one website or client_id for one company (team is inferred). Otherwise Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Do not use to read resolved inheritance — call get_form.

Parameterslimitcursorstatusteam_idclient_idproject_id

get_form

Get form

Use to read a form plus resolved and inherited settings, including resolved.email and resolved.uploads. files_url is the private inbox folder for this form under the project inbox (do not put it in a public snippet). Turnstile always inherits from the project (inherited.turnstile is true). Form webhook_url_override is nullable; null means inherit the project webhook. Forms may override email.subject and email.intro only. Do not use to generate embed code — call get_snippet.

Parametersform_idrequired

list_submissions

List submissions

Use to inspect recent posts. Available on free and yearly. Pass project_id or form_id to infer the team; omit both and Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Free teams prune submissions after 30 days; yearly after 730 days. Do not use to read a single submission — call get_submission.

Parametersspamlimitsincecursorform_idteam_idproject_id

get_submission

Get submission

Use to read one stored submission by id, including file metadata and files_url (the form inbox). Do not use this for live submit tests — POST to /s/:publicKey instead. Do not expect signed bucket URLs — download from the inbox.

Parameterssubmission_idrequired

get_snippet

Get form snippet

Use after the form exists to get copy-paste html, astro, or next code that posts to /s/:publicKey. Do not invent a submit URL — this tool returns it. Snippets are single-value inputs; write checkbox groups and multi-selects yourself. Checkbox groups, select multiple, and other multi-value HTML fields must use a [] suffix on the name (name="services[]") or only the last checked value is stored. Put services[] on field_contract.name too. JSON/fetch should send a real array without brackets ({ "services": ["a", "b"] }) and must not use Object.fromEntries(formData) — use formData.getAll("services"). Single checkbox, select, or combobox: no brackets. File inputs use multipart POST (name="resume[]" for multiple). Enable uploads on the project first. Downloads are the project inbox at files_url, with the form slug as a folder — never put that URL in a public snippet. After dropping the snippet, add visitor-facing success UI: a thank-you page plus default_redirect_url for classic HTML POST, or an on-page message when using fetch/{ok:true}. Do not leave visitors looking at JSON. See furrow://docs/submit-success.

Parametersform_idrequiredframeworkrequired

create_project

Create project

Use to add one website under an existing client_id. Idempotent on slug unless strict is true. Free accounts are limited to 3 active (non-archived) projects; yearly is unlimited. If create_project returns plan_limit, call create_upgrade_link and hand the human the Stripe URL. Prefer bootstrap_site when the client does not exist yet. Optional email sets notification templates (subject, from_name, intro, footer_mode, include_meta). Free accounts cannot set footer_mode off. Set uploads_enabled on the project to accept files. Email templates support {{project.name}}, {{project.slug}}, {{form.name}}, {{form.slug}}, {{count}} (1-based clean submissions on this form, including the current one), and any submission field such as {{name}} or {{email}}. Use a fallback with {{name | "New submission"}}. Missing fields render empty and never error. Do not pass HTML; Furrow renders one owned layout. Plans are capacity, not a feature ladder. Free: one workspace, 100 clean submissions/month pooled on the team, 3 active (non-archived) projects, 30-day submission retention, and email.footer_mode / branding.mode stay furrow. Yearly ($199/year): extra workspaces, 10,000 submissions/month, unlimited projects, 730-day retention, branding.mode furrow | off | agency. Expansion packs are $99/year each and add 5,000 submissions/month on a yearly account. MCP, webhooks, snippets, inheritance, Turnstile, and email templates stay available on free. Spam, honeypot, and rejected posts do not count. Use create_upgrade_link to hand a human a Stripe Checkout (or Customer Portal) URL. Pass product=expansion on a yearly team to add a pack. File inputs use multipart POST (name="resume[]" for multiple). Enable uploads on the project first. Downloads are the project inbox at files_url, with the form slug as a folder — never put that URL in a public snippet. Do not put Turnstile keys on a form.

Parametersnamerequiredslugrequiredemailstrictclient_idrequiredfrom_namewebhook_urlnotify_emailshoneypot_fieldwebhook_secretallowed_domainsuploads_enabled+10 more

update_project

Update project

Use to patch website settings. Nested email sets notification templates: email.subject, email.from_name, email.intro, email.footer_mode (furrow | minimal | off), email.include_meta. Optional branding updates the team (mode furrow | off | agency on yearly only; ignored on free except furrow). Set uploads_enabled and upload_allowed_types here — forms inherit them. Email templates support {{project.name}}, {{project.slug}}, {{form.name}}, {{form.slug}}, {{count}} (1-based clean submissions on this form, including the current one), and any submission field such as {{name}} or {{email}}. Use a fallback with {{name | "New submission"}}. Missing fields render empty and never error. Do not pass HTML; Furrow renders one owned layout. Plans are capacity, not a feature ladder. Free: one workspace, 100 clean submissions/month pooled on the team, 3 active (non-archived) projects, 30-day submission retention, and email.footer_mode / branding.mode stay furrow. Yearly ($199/year): extra workspaces, 10,000 submissions/month, unlimited projects, 730-day retention, branding.mode furrow | off | agency. Expansion packs are $99/year each and add 5,000 submissions/month on a yearly account. MCP, webhooks, snippets, inheritance, Turnstile, and email templates stay available on free. Spam, honeypot, and rejected posts do not count. Use create_upgrade_link to hand a human a Stripe Checkout (or Customer Portal) URL. Pass product=expansion on a yearly team to add a pack. File inputs use multipart POST (name="resume[]" for multiple). Enable uploads on the project first. Downloads are the project inbox at files_url, with the form slug as a folder — never put that URL in a public snippet. Null Turnstile or webhook fields clear them. Do not use this to create forms. Updating project keys changes resolved settings on existing forms unless a form override is set.

Parametersnameemailbrandingfrom_nameproject_idrequiredwebhook_urlnotify_emailshoneypot_fieldwebhook_secretallowed_domainsuploads_enabledturnstile_secret+9 more

rotate_project_inbox

Rotate project inbox link

Use when a project's private inbox URL may have leaked. Issues a new inbox key; every previously shared inbox link stops working immediately. get_project returns the new files_url.

Parametersproject_idrequired

archive_project

Archive project

Use to archive a website. Archived projects reject public submit. Do not use this as a hard delete. There is no unarchive tool in v1.

Parametersproject_idrequired

create_form

Create form

Use to add a form under an existing project_id. Idempotent on slug unless strict is true. Overrides are nullable; omit them to inherit project notify emails, webhook, redirect, require_turnstile, and email templates. Pass email.subject / email.intro to override notification copy for this form only. Pass webhook_url_override to send this form to a different URL. Field contract labels (label) are used on notification emails. Checkbox groups, select multiple, and other multi-value HTML fields must use a [] suffix on the name (name="services[]") or only the last checked value is stored. Put services[] on field_contract.name too. JSON/fetch should send a real array without brackets ({ "services": ["a", "b"] }) and must not use Object.fromEntries(formData) — use formData.getAll("services"). Single checkbox, select, or combobox: no brackets. File inputs use multipart POST (name="resume[]" for multiple). Enable uploads on the project first. Downloads are the project inbox at files_url, with the form slug as a folder — never put that URL in a public snippet.

Parametersnamerequiredslugrequiredemailstrictproject_idrequiredfield_contractwebhook_url_overrideredirect_url_overridenotify_emails_overridewebhook_secret_overriderequire_turnstile_override

update_form

Update form

Use to patch form overrides. Pass null on an override to inherit again. Set email.subject or email.intro to override project notification copy for this form only; from_name, footer_mode, and include_meta stay on the project. Email templates support {{project.name}}, {{project.slug}}, {{form.name}}, {{form.slug}}, {{count}} (1-based clean submissions on this form, including the current one), and any submission field such as {{name}} or {{email}}. Use a fallback with {{name | "New submission"}}. Missing fields render empty and never error. Do not pass HTML; Furrow renders one owned layout. Set webhook_url_override to override the project webhook for this form. Do not use this to change Turnstile keys — those live on the project. Checkbox groups, select multiple, and other multi-value HTML fields must use a [] suffix on the name (name="services[]") or only the last checked value is stored. Put services[] on field_contract.name too. JSON/fetch should send a real array without brackets ({ "services": ["a", "b"] }) and must not use Object.fromEntries(formData) — use formData.getAll("services"). Single checkbox, select, or combobox: no brackets. File inputs use multipart POST (name="resume[]" for multiple). Enable uploads on the project first. Downloads are the project inbox at files_url, with the form slug as a folder — never put that URL in a public snippet.

Parametersnameemailform_idrequiredfield_contractwebhook_url_overrideredirect_url_overridenotify_emails_overridewebhook_secret_overriderequire_turnstile_override

archive_form

Archive form

Use to archive a form so public submit returns 404. Do not use this as a hard delete.

Parametersform_idrequired

upsert_project_webhook

Upsert project webhook

Use to set or replace the project webhook URL. Available on free and yearly. A signing secret is generated once if the project has none. Forms inherit this unless webhook_url_override is set. Do not use this for a one-off delivery — call test_webhook.

Parametersproject_idrequiredwebhook_urlrequiredwebhook_secret

test_webhook

Test webhook

Use to POST a signed webhook.test event to the project's webhook URL. Available on free and yearly. Do not use this to inspect past deliveries — that is REST GET /api/projects/:id/webhook-deliveries. Fails if no webhook URL and secret are set.

Parametersproject_idrequired

bootstrap_site

Bootstrap site

Use this to stand up a client, one website (project), and its forms in a single call. name/slug are the client; optional project_name/project_slug default to the same. Free accounts cannot create a fourth active project — call create_upgrade_link if bootstrap_site returns plan_limit. Operator tokens (all workspaces) must pass team_id from list_teams. Team-scoped tokens may omit team_id and cannot target another workspace. Idempotent on client, project, and form slugs. Site settings (domains, Turnstile, notify emails, webhook, email templates, uploads) live on the project. Email templates support {{project.name}}, {{project.slug}}, {{form.name}}, {{form.slug}}, {{count}} (1-based clean submissions on this form, including the current one), and any submission field such as {{name}} or {{email}}. Use a fallback with {{name | "New submission"}}. Missing fields render empty and never error. Do not pass HTML; Furrow renders one owned layout. Plans are capacity, not a feature ladder. Free: one workspace, 100 clean submissions/month pooled on the team, 3 active (non-archived) projects, 30-day submission retention, and email.footer_mode / branding.mode stay furrow. Yearly ($199/year): extra workspaces, 10,000 submissions/month, unlimited projects, 730-day retention, branding.mode furrow | off | agency. Expansion packs are $99/year each and add 5,000 submissions/month on a yearly account. MCP, webhooks, snippets, inheritance, Turnstile, and email templates stay available on free. Spam, honeypot, and rejected posts do not count. Use create_upgrade_link to hand a human a Stripe Checkout (or Customer Portal) URL. Pass product=expansion on a yearly team to add a pack. Checkbox groups, select multiple, and other multi-value HTML fields must use a [] suffix on the name (name="services[]") or only the last checked value is stored. Put services[] on field_contract.name too. JSON/fetch should send a real array without brackets ({ "services": ["a", "b"] }) and must not use Object.fromEn

Parametersnamerequiredslugrequiredemailformsteam_idfrom_namewebhook_urlproject_nameproject_slugnotify_emailshoneypot_fieldwebhook_secret+12 more

Version history

1
  1. v1.0.1LatestSep 16, 2026

Score

100% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts