Formfurrow

io.github.CloudCorpRecords由 GitHub 账号 CloudCorpRecords 发布v0.1.0更新于 Nov 7, 2026

Run a form backend end to end: teams, clients, projects, forms, submissions, snippets, webhooks.

已验证STDIO仅桌面效率与工作流商业与电商

概览

AI 生成的概览

连接托管 FurrowForms 表单后端的本地桥接服务,让助手管理团队、客户、项目、表单、提交记录、嵌入代码和 Webhook。

可以做什么
  • 列出并更新团队与账户设置,包括品牌和垃圾信息过滤选项
  • 浏览、创建、重命名和归档客户(公司)
  • 管理网站(项目):创建、修改设置、轮换私有收件箱、归档
  • 创建和更新表单,读取解析后的设置,并按指定框架获取嵌入代码
  • 列出并读取已存储的提交记录,包括文件元数据和收件箱位置
  • 注册或替换项目 Webhook 并发送签名测试事件;一次调用即可搭建客户、站点和表单
适用场景
适用于表单托管在 FurrowForms 上、希望助手在不打开后台的情况下搭建客户、站点和表单、查看新提交或配置 Webhook 的场景。它只是一个本地转发桥,只有已有 FurrowForms 账户和 API 密钥时才有意义。
运行要求
通过 npx(需 Node.js)或 Docker 镜像在本地以 stdio MCP 服务器运行,并需要网络访问以转发到托管的上游端点。可选环境变量:FURROWFORMS_MCP_URL 用于覆盖端点,FURROWFORMS_API_KEY 会以 Bearer Authorization 头发送;未设置密钥时不发送认证头。
安装前请注意
多数工具会写入或修改数据:创建和更新客户、项目、表单,归档(v1 无取消归档),轮换项目收件箱(此前分享的收件箱链接立即失效),以及设置 Webhook。update_account 可写入只写的 TypeSafe API 密钥。API 密钥会发送到上游服务,且端点可通过 FURROWFORMS_MCP_URL 重定向。升级套餐工具已被刻意移除,因此不暴露任何支付工具。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Formfurrow,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

formfurrow

formfurrow is a small local bridge to the hosted FurrowForms MCP server, a form backend you can run end to end: organise work into teams, clients and projects, build forms under those projects, read the submissions that come in, pull an embed snippet for a form in your framework of choice, and wire a project's webhook so new submissions are pushed to your own endpoint as they land.

The bridge keeps no form data of its own. It serves the upstream server's tool list locally, exactly as captured from the live endpoint, and forwards each tool call upstream, returning the result untouched. The captured surface here is a labelled subset: the upstream's plan-upgrade funnel tool (create_upgrade_link) was omitted on purpose, so there is no payment or plan-upgrade tool in this package. Everything that remains is workspace management on the caller's own form backend.

Tools

Account and teams:

  • list_teams — list the caller's teams. No required arguments.
  • update_team — update a team. Required: name.
  • get_account — read the caller's account. No required arguments.
  • update_account — update the account. No required arguments.

Clients:

  • list_clients — list clients. No required arguments.
  • get_client — read one client. Required: client_id.
  • create_client — create a client. Required: name, slug.
  • update_client — update a client. Required: client_id.
  • archive_client — archive a client. Required: client_id.

Projects:

  • list_projects — list projects. No required arguments.
  • get_project — read one project. Required: project_id.
  • create_project — create a project. Required: name, slug, client_id.
  • update_project — update a project. Required: project_id.
  • rotate_project_inbox — rotate a project's inbox. Required: project_id.
  • archive_project — archive a project. Required: project_id.

Forms and submissions:

  • list_forms — list forms. No required arguments.
  • get_form — read one form. Required: form_id.
  • create_form — create a form. Required: name, slug, project_id.
  • update_form — update a form. Required: form_id.
  • archive_form — archive a form. Required: form_id.
  • list_submissions — list submissions. No required arguments.
  • get_submission — read one submission. Required: submission_id.
  • get_snippet — get a form's embed snippet. Required: form_id, framework.

Webhooks and setup:

  • upsert_project_webhook — register or replace a project's webhook. Required: webhook_url, project_id.
  • test_webhook — send a test webhook for a project. Required: project_id.
  • bootstrap_site — bootstrap a site. Required: name, slug.

Each tool's full input schema, including its optional fields, is served verbatim in the MCP tools/list response.

Configuration

  • FURROWFORMS_MCP_URL (optional) — override the upstream endpoint. Defaults to https://api.furrowforms.com/mcp. (The override hook is this rebuild's own labelled reconstruction.)
  • FURROWFORMS_API_KEY (optional) — when set, every upstream request carries an Authorization: Bearer <key> header. When it is not set, no key header is sent. (The Authorization header name is pinned by the registry record; the Bearer scheme and this forwarding are labelled reconstructions, and the original surface was captured keyless.)

Forwarding mechanics

On the first tool call the client opens a streamable HTTP session with the upstream: a JSON-RPC initialize request (protocolVersion 2025-03-26, clientInfo name formfurrow), then a notifications/initialized notification, then the tools/call request carrying the caller's arguments unchanged. When the upstream answers initialize with an Mcp-Session-Id header, that value rides on every later request of the session, which is reused for the life of the process. Replies may arrive as plain JSON or as server-sent events; both are read.

Successful upstream results pass through verbatim, including any isError flag the upstream sets. Failures — a JSON-RPC error, a non-2xx status, an unreadable response, or a request that cannot be completed — come back as an isError result whose text starts with formfurrow error: (this rendering is this rebuild's own labelled reconstruction).

CLI

Each tool is also a subcommand taking one JSON argument string:

bash
npx @reneturcios/formfurrow list_teamsnpx @reneturcios/formfurrow create_client '{"name":"Acme","slug":"acme"}'npx @reneturcios/formfurrow get_snippet '{"form_id":"frm_1","framework":"react"}'npx @reneturcios/formfurrow --version

Exit codes: 0 on success, 1 on an isError result, 2 on a usage error.

MCP server

bash
npx -y @reneturcios/formfurrow mcp

MCP client config:

json
{  "mcpServers": {    "formfurrow": {      "command": "npx",      "args": ["-y", "@reneturcios/formfurrow", "mcp"]    }  }}

Docker

bash
docker run -i ghcr.io/cloudcorprecords/formfurrowdocker run --rm ghcr.io/cloudcorprecords/formfurrow --version

The container's default command is mcp, so the first form is a stdio MCP server; any other arguments reach the CLI normally.

Development

bash
npm installnpm run buildnpm testnpm run dev

The test suite runs entirely against a stubbed JSON-RPC upstream — no live network calls.

License

MIT — see LICENSE.

来源:README.md,提交 d2b4b80

工具

26

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.

无需输入参数。

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.

输入参数name必填team_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.

输入参数team_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.

输入参数ainameteam_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.

输入参数limitcursorstatusteam_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.

输入参数client_id必填

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.

输入参数name必填slug必填strictteam_id

update_client

Update client

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

输入参数nameclient_id必填

archive_client

Archive client

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

输入参数client_id必填

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.

输入参数limitcursorstatusteam_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.

输入参数project_id必填

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.

输入参数limitcursorstatusteam_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.

输入参数form_id必填

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.

输入参数spamlimitsincecursorform_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.

输入参数submission_id必填

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.

输入参数form_id必填framework必填

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.

输入参数name必填slug必填emailstrictclient_id必填from_namewebhook_urlnotify_emailshoneypot_fieldwebhook_secretallowed_domainsuploads_enabled另有 10 个

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.

输入参数nameemailbrandingfrom_nameproject_id必填webhook_urlnotify_emailshoneypot_fieldwebhook_secretallowed_domainsuploads_enabledturnstile_secret另有 9 个

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.

输入参数project_id必填

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.

输入参数project_id必填

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.

输入参数name必填slug必填emailstrictproject_id必填field_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.

输入参数nameemailform_id必填field_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.

输入参数form_id必填

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.

输入参数project_id必填webhook_url必填webhook_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.

输入参数project_id必填

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

输入参数name必填slug必填emailformsteam_idfrom_namewebhook_urlproject_nameproject_slugnotify_emailshoneypot_fieldwebhook_secret另有 12 个

版本历史

1
  1. v0.1.0最新Nov 4, 2026

评分

已满足适用检查项的 90%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分
  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分