{
  "data": {
    "tool": {
      "category": "",
      "endpoint": "https://api.furrowforms.com/mcp",
      "jsonUrl": "https://www.anchorterminal.com/api/v1/tools/furrowforms-furrow-forms.json",
      "kind": "mcp",
      "listed": "indexed",
      "liveUrl": "https://www.anchorterminal.com/api/v1/live/furrowforms-furrow-forms.json",
      "markdownUrl": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms.md",
      "mcpTools": {
        "check": {
          "checker": "anchor-check/1.0",
          "totalTokens": 15637,
          "counts": {
            "error": 0,
            "note": 1,
            "warn": 5
          },
          "findings": [
            {
              "rule": "TC07",
              "severity": "warn",
              "tool": "bootstrap_site",
              "message": "the description is about 601 tokens",
              "fix": "Keep the description to what a model needs to choose and call the tool; move the manual to a resource or the docs."
            },
            {
              "rule": "TC22",
              "severity": "warn",
              "tool": "bootstrap_site",
              "message": "the definition is about 2,798 tokens",
              "fix": "Trim the description and parameter docs, or split the tool."
            },
            {
              "rule": "TC22",
              "severity": "warn",
              "tool": "create_project",
              "message": "the definition is about 1,678 tokens",
              "fix": "Trim the description and parameter docs, or split the tool."
            },
            {
              "rule": "TC22",
              "severity": "warn",
              "tool": "update_project",
              "message": "the definition is about 1,771 tokens",
              "fix": "Trim the description and parameter docs, or split the tool."
            },
            {
              "rule": "TC23",
              "severity": "warn",
              "message": "27 tools, about 15,645 tokens of definitions",
              "fix": "Split the server by job, or offer a smaller default toolset (a read-only set, or a search-then-call pattern)."
            },
            {
              "rule": "TC24",
              "severity": "note",
              "message": "27 of 27 tools have no outputSchema",
              "fix": "Declare outputSchema for tools that return structured data, and return structuredContent that matches it."
            }
          ]
        },
        "checkedAt": "2026-10-04T22:22:55Z",
        "count": 27,
        "schemaTokens": 15637,
        "status": "ok",
        "tools": [
          {
            "name": "list_teams",
            "title": "List teams",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {},
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "update_team",
            "title": "Update team",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "name": {
                  "description": "New team (workspace) display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "get_account",
            "title": "Get account",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "update_account",
            "title": "Update account",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "ai": {
                  "description": "AI spam filter. Off until this team saves its own TypeSafe key. One Jev call per heuristics-clean submission.",
                  "properties": {
                    "notify_suspected_spam": {
                      "description": "When true (the default), submissions the AI flags as spam still email notify addresses with a Potential spam label and send no webhook. Set false to silence those emails.",
                      "type": "boolean"
                    },
                    "typesafe_api_key": {
                      "anyOf": [
                        {
                          "maxLength": 500,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "TypeSafe API key for the AI spam filter. Send null or an empty string to remove it. The key is write-only and never returned."
                    }
                  },
                  "type": "object"
                },
                "branding": {
                  "description": "Account-wide branding for notification emails and hosted pages.",
                  "properties": {
                    "agency_name": {
                      "anyOf": [
                        {
                          "maxLength": 120,
                          "minLength": 1,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Agency name shown when mode is agency. Null clears it."
                    },
                    "agency_url": {
                      "anyOf": [
                        {
                          "format": "uri",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Optional http(s) link for the agency name when mode is agency. Null clears it."
                    },
                    "logo_url": {
                      "anyOf": [
                        {
                          "format": "uri",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Optional http(s) logo image URL when mode is agency. Null clears it."
                    },
                    "mode": {
                      "description": "furrow shows Furrow branding, off hides it, agency shows your own name/link/logo. Only yearly plans may change this.",
                      "enum": [
                        "furrow",
                        "off",
                        "agency"
                      ],
                      "type": "string"
                    }
                  },
                  "type": "object"
                },
                "name": {
                  "description": "New workspace display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "create_upgrade_link",
            "title": "Create upgrade link",
            "description": "Use when a free team is blocked on the 3-project, 100-submission, or one-workspace limit, or when a human should upgrade to yearly ($199/year) so you can keep adding projects, workspaces, and storing new submissions. Returns a Stripe Checkout URL to hand the human. If the team is already yearly, omit product to get a Stripe Customer Portal URL, or pass product=expansion for a $99/year pack that adds 5,000 submissions/month. Do not change plan in the database — Stripe webhooks do that. 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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "product": {
                  "description": "yearly starts the $199/year plan; expansion adds a $99/year 5,000-submission pack to a yearly team.",
                  "enum": [
                    "yearly",
                    "expansion"
                  ],
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "idempotentHint": false,
              "readOnlyHint": false
            }
          },
          {
            "name": "list_clients",
            "title": "List clients",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "cursor": {
                  "description": "Opaque cursor from the previous page's next_cursor.",
                  "minLength": 1,
                  "type": "string"
                },
                "limit": {
                  "description": "Page size, max 100.",
                  "exclusiveMinimum": 0,
                  "maximum": 100,
                  "type": "integer"
                },
                "status": {
                  "description": "Filter by archive state. Defaults to active.",
                  "enum": [
                    "active",
                    "archived",
                    "all"
                  ],
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "get_client",
            "title": "Get client",
            "description": "Use to inspect one client. Do not use to list that client's sites — call list_projects with client_id.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "client_id": {
                  "description": "Client id from list_clients or create_client.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "client_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "create_client",
            "title": "Create client",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "name": {
                  "description": "Client (company) display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "slug": {
                  "description": "Lowercase hyphenated identifier, unique per team. Used for idempotent re-runs.",
                  "maxLength": 80,
                  "minLength": 1,
                  "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
                  "type": "string"
                },
                "strict": {
                  "default": false,
                  "description": "When true, fail if the slug already exists instead of returning the existing record.",
                  "type": "boolean"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "name",
                "slug"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "update_client",
            "title": "Update client",
            "description": "Use to rename a client. Do not use this to change domains, Turnstile, or webhooks — call update_project.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "client_id": {
                  "description": "Client id from list_clients or create_client.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "name": {
                  "description": "New client display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                }
              },
              "required": [
                "client_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "archive_client",
            "title": "Archive client",
            "description": "Use to archive a client. Do not use this as a hard delete. There is no unarchive tool in v1.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "client_id": {
                  "description": "Client id from list_clients or create_client.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "client_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "list_projects",
            "title": "List projects",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "client_id": {
                  "description": "Only projects under this client.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "cursor": {
                  "description": "Opaque cursor from the previous page's next_cursor.",
                  "minLength": 1,
                  "type": "string"
                },
                "limit": {
                  "description": "Page size, max 100.",
                  "exclusiveMinimum": 0,
                  "maximum": 100,
                  "type": "integer"
                },
                "status": {
                  "description": "Filter by archive state. Defaults to active.",
                  "enum": [
                    "active",
                    "archived",
                    "all"
                  ],
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "get_project",
            "title": "Get project",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "project_id": {
                  "description": "Project (website) id from list_projects, create_project, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "project_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "list_forms",
            "title": "List forms",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "client_id": {
                  "description": "Only forms under this client's projects.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "cursor": {
                  "description": "Opaque cursor from the previous page's next_cursor.",
                  "minLength": 1,
                  "type": "string"
                },
                "limit": {
                  "description": "Page size, max 100.",
                  "exclusiveMinimum": 0,
                  "maximum": 100,
                  "type": "integer"
                },
                "project_id": {
                  "description": "Only forms in this project.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "status": {
                  "description": "Filter by archive state. Defaults to active.",
                  "enum": [
                    "active",
                    "archived",
                    "all"
                  ],
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "get_form",
            "title": "Get form",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "form_id": {
                  "description": "Form id from list_forms, create_form, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "form_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "list_submissions",
            "title": "List submissions",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "cursor": {
                  "description": "Opaque cursor from the previous page's next_cursor.",
                  "minLength": 1,
                  "type": "string"
                },
                "form_id": {
                  "description": "Only submissions to this form.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "limit": {
                  "description": "Page size, max 100.",
                  "exclusiveMinimum": 0,
                  "maximum": 100,
                  "type": "integer"
                },
                "project_id": {
                  "description": "Only submissions in this project.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "since": {
                  "description": "ISO 8601 timestamp; only submissions created after this instant.",
                  "minLength": 1,
                  "type": "string"
                },
                "spam": {
                  "default": "clean",
                  "description": "Which submissions to return. Defaults to clean.",
                  "enum": [
                    "clean",
                    "spam",
                    "unknown",
                    "all"
                  ],
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "get_submission",
            "title": "Get submission",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "submission_id": {
                  "description": "Submission id from list_submissions or a webhook payload.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "submission_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "get_snippet",
            "title": "Get form snippet",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "form_id": {
                  "description": "Form id from list_forms, create_form, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "framework": {
                  "description": "Snippet flavor: html (plain form), astro (component), or next (React client component).",
                  "enum": [
                    "html",
                    "astro",
                    "next"
                  ],
                  "type": "string"
                }
              },
              "required": [
                "form_id",
                "framework"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": true
            }
          },
          {
            "name": "create_project",
            "title": "Create project",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "allowed_domains": {
                  "description": "Hostnames allowed to post to this project's forms (example.com, www.example.com). Empty accepts any origin.",
                  "items": {
                    "maxLength": 253,
                    "minLength": 1,
                    "type": "string"
                  },
                  "type": "array"
                },
                "client_id": {
                  "description": "Client id from list_clients or create_client.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "default_redirect_url": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Where classic HTML posts redirect after success. Null returns JSON/inline success instead."
                },
                "email": {
                  "description": "Notification email template for the project: subject, from_name, intro, footer_mode, include_meta.",
                  "properties": {
                    "footer_mode": {
                      "description": "furrow shows the Furrow footer, minimal shows a one-line footer, off hides it (yearly plans only).",
                      "enum": [
                        "furrow",
                        "minimal",
                        "off"
                      ],
                      "type": "string"
                    },
                    "from_name": {
                      "description": "Display name on the From line of notification emails.",
                      "maxLength": 120,
                      "minLength": 1,
                      "type": "string"
                    },
                    "include_meta": {
                      "description": "Include submission metadata (IP, user agent, referrer, timestamp) below the fields.",
                      "type": "boolean"
                    },
                    "intro": {
                      "anyOf": [
                        {
                          "maxLength": 4000,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Plain-text paragraph above the submitted fields. Supports {{tokens}}. Null removes it."
                    },
                    "subject": {
                      "description": "Notification email subject. Supports {{tokens}} such as {{form.name}} or {{name}}.",
                      "maxLength": 300,
                      "minLength": 1,
                      "type": "string"
                    }
                  },
                  "type": "object"
                },
                "from_name": {
                  "anyOf": [
                    {
                      "maxLength": 120,
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Legacy From display name. Prefer email.from_name."
                },
                "honeypot_field": {
                  "description": "Name of the hidden honeypot input the snippet emits. Defaults to _gotcha.",
                  "maxLength": 80,
                  "minLength": 1,
                  "type": "string"
                },
                "name": {
                  "description": "Project (website) display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "notify_emails": {
                  "default": [],
                  "description": "Addresses that receive each clean submission (max 10). Inherited by every form.",
                  "items": {
                    "format": "email",
                    "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "type": "string"
                  },
                  "maxItems": 10,
                  "type": "array"
                },
                "rate_limit_per_ip": {
                  "description": "Max submissions per IP within rate_limit_window_s.",
                  "exclusiveMinimum": 0,
                  "maximum": 1000,
                  "type": "integer"
                },
                "rate_limit_window_s": {
                  "description": "Rate-limit window in seconds (max 86400).",
                  "exclusiveMinimum": 0,
                  "maximum": 86400,
                  "type": "integer"
                },
                "require_turnstile": {
                  "description": "Reject submissions that lack a valid Turnstile token.",
                  "type": "boolean"
                },
                "slug": {
                  "description": "Lowercase hyphenated identifier, unique per client. Used for idempotent re-runs.",
                  "maxLength": 80,
                  "minLength": 1,
                  "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
                  "type": "string"
                },
                "strict": {
                  "default": false,
                  "description": "When true, fail if the slug already exists instead of returning the existing record.",
                  "type": "boolean"
                },
                "turnstile_secret": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Cloudflare Turnstile secret used to verify tokens server-side. Null removes it."
                },
                "turnstile_site_key": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Cloudflare Turnstile site key for the frontend widget. Null removes it."
                },
                "upload_allowed_types": {
                  "description": "Allowed upload MIME types, e.g. application/pdf or image/*.",
                  "items": {
                    "maxLength": 80,
                    "minLength": 3,
                    "pattern": "^[a-z0-9.+-]+\\/[a-z0-9.+*-]+$",
                    "type": "string"
                  },
                  "maxItems": 20,
                  "minItems": 1,
                  "type": "array"
                },
                "upload_max_file_bytes": {
                  "description": "Max bytes per file (up to 25 MB).",
                  "exclusiveMinimum": 0,
                  "maximum": 26214400,
                  "type": "integer"
                },
                "upload_max_files": {
                  "description": "Max files per submission (up to 20).",
                  "exclusiveMinimum": 0,
                  "maximum": 20,
                  "type": "integer"
                },
                "upload_max_total_bytes": {
                  "description": "Max total upload bytes per submission (up to 50 MB).",
                  "exclusiveMinimum": 0,
                  "maximum": 52428800,
                  "type": "integer"
                },
                "uploads_enabled": {
                  "description": "Accept multipart file fields on this project's forms.",
                  "type": "boolean"
                },
                "webhook_secret": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "HMAC-SHA256 secret for the X-Furrow-Signature header. Omit to have one generated and returned."
                },
                "webhook_url": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Public https endpoint that receives a signed JSON POST per clean submission. Null disables it."
                }
              },
              "required": [
                "name",
                "slug",
                "client_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "update_project",
            "title": "Update project",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "allowed_domains": {
                  "description": "Replace the allowed hostnames. Empty array accepts any origin.",
                  "items": {
                    "maxLength": 253,
                    "minLength": 1,
                    "type": "string"
                  },
                  "type": "array"
                },
                "branding": {
                  "description": "Per-project branding override for notification emails and hosted pages.",
                  "properties": {
                    "agency_name": {
                      "anyOf": [
                        {
                          "maxLength": 120,
                          "minLength": 1,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Agency name shown when mode is agency. Null clears it."
                    },
                    "agency_url": {
                      "anyOf": [
                        {
                          "format": "uri",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Optional http(s) link for the agency name when mode is agency. Null clears it."
                    },
                    "logo_url": {
                      "anyOf": [
                        {
                          "format": "uri",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Optional http(s) logo image URL when mode is agency. Null clears it."
                    },
                    "mode": {
                      "description": "furrow shows Furrow branding, off hides it, agency shows your own name/link/logo. Only yearly plans may change this.",
                      "enum": [
                        "furrow",
                        "off",
                        "agency"
                      ],
                      "type": "string"
                    }
                  },
                  "type": "object"
                },
                "default_redirect_url": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Where classic HTML posts redirect after success. Null returns JSON/inline success instead."
                },
                "email": {
                  "description": "Notification email template for the project: subject, from_name, intro, footer_mode, include_meta.",
                  "properties": {
                    "footer_mode": {
                      "description": "furrow shows the Furrow footer, minimal shows a one-line footer, off hides it (yearly plans only).",
                      "enum": [
                        "furrow",
                        "minimal",
                        "off"
                      ],
                      "type": "string"
                    },
                    "from_name": {
                      "description": "Display name on the From line of notification emails.",
                      "maxLength": 120,
                      "minLength": 1,
                      "type": "string"
                    },
                    "include_meta": {
                      "description": "Include submission metadata (IP, user agent, referrer, timestamp) below the fields.",
                      "type": "boolean"
                    },
                    "intro": {
                      "anyOf": [
                        {
                          "maxLength": 4000,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Plain-text paragraph above the submitted fields. Supports {{tokens}}. Null removes it."
                    },
                    "subject": {
                      "description": "Notification email subject. Supports {{tokens}} such as {{form.name}} or {{name}}.",
                      "maxLength": 300,
                      "minLength": 1,
                      "type": "string"
                    }
                  },
                  "type": "object"
                },
                "from_name": {
                  "anyOf": [
                    {
                      "maxLength": 120,
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Legacy From display name. Prefer email.from_name."
                },
                "honeypot_field": {
                  "description": "Name of the hidden honeypot input the snippet emits. Defaults to _gotcha.",
                  "maxLength": 80,
                  "minLength": 1,
                  "type": "string"
                },
                "name": {
                  "description": "New project display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "notify_emails": {
                  "description": "Replace the notification recipients (max 10).",
                  "items": {
                    "format": "email",
                    "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "type": "string"
                  },
                  "maxItems": 10,
                  "type": "array"
                },
                "project_id": {
                  "description": "Project (website) id from list_projects, create_project, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "rate_limit_per_ip": {
                  "description": "Max submissions per IP within rate_limit_window_s.",
                  "exclusiveMinimum": 0,
                  "maximum": 1000,
                  "type": "integer"
                },
                "rate_limit_window_s": {
                  "description": "Rate-limit window in seconds (max 86400).",
                  "exclusiveMinimum": 0,
                  "maximum": 86400,
                  "type": "integer"
                },
                "require_turnstile": {
                  "description": "Reject submissions that lack a valid Turnstile token.",
                  "type": "boolean"
                },
                "turnstile_secret": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Cloudflare Turnstile secret used to verify tokens server-side. Null removes it."
                },
                "turnstile_site_key": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Cloudflare Turnstile site key for the frontend widget. Null removes it."
                },
                "upload_allowed_types": {
                  "description": "Allowed upload MIME types, e.g. application/pdf or image/*.",
                  "items": {
                    "maxLength": 80,
                    "minLength": 3,
                    "pattern": "^[a-z0-9.+-]+\\/[a-z0-9.+*-]+$",
                    "type": "string"
                  },
                  "maxItems": 20,
                  "minItems": 1,
                  "type": "array"
                },
                "upload_max_file_bytes": {
                  "description": "Max bytes per file (up to 25 MB).",
                  "exclusiveMinimum": 0,
                  "maximum": 26214400,
                  "type": "integer"
                },
                "upload_max_files": {
                  "description": "Max files per submission (up to 20).",
                  "exclusiveMinimum": 0,
                  "maximum": 20,
                  "type": "integer"
                },
                "upload_max_total_bytes": {
                  "description": "Max total upload bytes per submission (up to 50 MB).",
                  "exclusiveMinimum": 0,
                  "maximum": 52428800,
                  "type": "integer"
                },
                "uploads_enabled": {
                  "description": "Accept multipart file fields on this project's forms.",
                  "type": "boolean"
                },
                "webhook_secret": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "HMAC-SHA256 secret for the X-Furrow-Signature header. Omit to have one generated and returned."
                },
                "webhook_url": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Public https endpoint that receives a signed JSON POST per clean submission. Null disables it."
                }
              },
              "required": [
                "project_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "rotate_project_inbox",
            "title": "Rotate project inbox link",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "project_id": {
                  "description": "Project (website) id from list_projects, create_project, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "project_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "idempotentHint": false,
              "readOnlyHint": false
            }
          },
          {
            "name": "archive_project",
            "title": "Archive project",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "project_id": {
                  "description": "Project (website) id from list_projects, create_project, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "project_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "create_form",
            "title": "Create form",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "email": {
                  "description": "Per-form subject and intro overrides for the notification email.",
                  "properties": {
                    "intro": {
                      "anyOf": [
                        {
                          "maxLength": 4000,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Per-form intro override. Supports {{tokens}}. Null falls back to the project intro."
                    },
                    "subject": {
                      "anyOf": [
                        {
                          "maxLength": 300,
                          "minLength": 1,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Per-form subject override. Supports {{tokens}}. Null falls back to the project subject."
                    }
                  },
                  "type": "object"
                },
                "field_contract": {
                  "anyOf": [
                    {
                      "items": {
                        "properties": {
                          "label": {
                            "anyOf": [
                              {
                                "maxLength": 120,
                                "minLength": 1,
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Human label used in the snippet and notification email. Defaults to the field name."
                          },
                          "name": {
                            "description": "Posted field name. HTML checkbox groups / multi-select must end in [] (services[]) or only the last value is stored. JSON arrays omit the brackets.",
                            "maxLength": 80,
                            "minLength": 1,
                            "type": "string"
                          },
                          "report": {
                            "default": false,
                            "description": "Include this field in dashboard summaries and reports.",
                            "type": "boolean"
                          },
                          "type": {
                            "description": "text, email, textarea, file, etc. type=file emits a file input in get_snippet.",
                            "maxLength": 40,
                            "minLength": 1,
                            "type": "string"
                          }
                        },
                        "required": [
                          "name",
                          "type"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Declared fields (name, type, label, report). Drives get_snippet and the email layout. Null clears it."
                },
                "name": {
                  "description": "Form display name, e.g. Contact or Quote request.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "notify_emails_override": {
                  "anyOf": [
                    {
                      "items": {
                        "format": "email",
                        "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                        "type": "string"
                      },
                      "maxItems": 10,
                      "type": "array"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Recipients for this form only. Null inherits the project's notify_emails."
                },
                "project_id": {
                  "description": "Project (website) id from list_projects, create_project, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "redirect_url_override": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Success redirect for this form only. Null inherits default_redirect_url."
                },
                "require_turnstile_override": {
                  "anyOf": [
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Force Turnstile on or off for this form. Null inherits the project setting."
                },
                "slug": {
                  "description": "Lowercase hyphenated identifier, unique per project. Used for idempotent re-runs.",
                  "maxLength": 80,
                  "minLength": 1,
                  "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
                  "type": "string"
                },
                "strict": {
                  "default": false,
                  "description": "When true, fail if the slug already exists instead of returning the existing record.",
                  "type": "boolean"
                },
                "webhook_secret_override": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "HMAC secret for this form's webhook. Null inherits the project secret."
                },
                "webhook_url_override": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Webhook endpoint for this form only. Null inherits the project webhook."
                }
              },
              "required": [
                "name",
                "slug",
                "project_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "update_form",
            "title": "Update form",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "email": {
                  "description": "Per-form subject and intro overrides for the notification email.",
                  "properties": {
                    "intro": {
                      "anyOf": [
                        {
                          "maxLength": 4000,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Per-form intro override. Supports {{tokens}}. Null falls back to the project intro."
                    },
                    "subject": {
                      "anyOf": [
                        {
                          "maxLength": 300,
                          "minLength": 1,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Per-form subject override. Supports {{tokens}}. Null falls back to the project subject."
                    }
                  },
                  "type": "object"
                },
                "field_contract": {
                  "anyOf": [
                    {
                      "items": {
                        "properties": {
                          "label": {
                            "anyOf": [
                              {
                                "maxLength": 120,
                                "minLength": 1,
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Human label used in the snippet and notification email. Defaults to the field name."
                          },
                          "name": {
                            "description": "Posted field name. HTML checkbox groups / multi-select must end in [] (services[]) or only the last value is stored. JSON arrays omit the brackets.",
                            "maxLength": 80,
                            "minLength": 1,
                            "type": "string"
                          },
                          "report": {
                            "default": false,
                            "description": "Include this field in dashboard summaries and reports.",
                            "type": "boolean"
                          },
                          "type": {
                            "description": "text, email, textarea, file, etc. type=file emits a file input in get_snippet.",
                            "maxLength": 40,
                            "minLength": 1,
                            "type": "string"
                          }
                        },
                        "required": [
                          "name",
                          "type"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Declared fields (name, type, label, report). Drives get_snippet and the email layout. Null clears it."
                },
                "form_id": {
                  "description": "Form id from list_forms, create_form, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "name": {
                  "description": "New form display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "notify_emails_override": {
                  "anyOf": [
                    {
                      "items": {
                        "format": "email",
                        "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                        "type": "string"
                      },
                      "maxItems": 10,
                      "type": "array"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Recipients for this form only. Null inherits the project's notify_emails."
                },
                "redirect_url_override": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Success redirect for this form only. Null inherits default_redirect_url."
                },
                "require_turnstile_override": {
                  "anyOf": [
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Force Turnstile on or off for this form. Null inherits the project setting."
                },
                "webhook_secret_override": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "HMAC secret for this form's webhook. Null inherits the project secret."
                },
                "webhook_url_override": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Webhook endpoint for this form only. Null inherits the project webhook."
                }
              },
              "required": [
                "form_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "archive_form",
            "title": "Archive form",
            "description": "Use to archive a form so public submit returns 404. Do not use this as a hard delete.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "form_id": {
                  "description": "Form id from list_forms, create_form, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "form_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "upsert_project_webhook",
            "title": "Upsert project webhook",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "project_id": {
                  "description": "Project (website) id from list_projects, create_project, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "webhook_secret": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "HMAC-SHA256 secret for X-Furrow-Signature. Omit to have one generated and returned."
                },
                "webhook_url": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Public https endpoint that receives a signed JSON POST per clean submission. Null disables it."
                }
              },
              "required": [
                "webhook_url",
                "project_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "test_webhook",
            "title": "Test webhook",
            "description": "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.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "project_id": {
                  "description": "Project (website) id from list_projects, create_project, or bootstrap_site.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                }
              },
              "required": [
                "project_id"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": false,
              "readOnlyHint": false
            }
          },
          {
            "name": "bootstrap_site",
            "title": "Bootstrap site",
            "description": "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.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. Do not use when you only need to patch an existing form — call update_form.",
            "inputSchema": {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "properties": {
                "allowed_domains": {
                  "description": "Hostnames allowed to post to this project's forms (example.com, www.example.com). Empty accepts any origin.",
                  "items": {
                    "maxLength": 253,
                    "minLength": 1,
                    "type": "string"
                  },
                  "type": "array"
                },
                "default_redirect_url": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Where classic HTML posts redirect after success. Null returns JSON/inline success instead."
                },
                "email": {
                  "description": "Notification email template for the project: subject, from_name, intro, footer_mode, include_meta.",
                  "properties": {
                    "footer_mode": {
                      "description": "furrow shows the Furrow footer, minimal shows a one-line footer, off hides it (yearly plans only).",
                      "enum": [
                        "furrow",
                        "minimal",
                        "off"
                      ],
                      "type": "string"
                    },
                    "from_name": {
                      "description": "Display name on the From line of notification emails.",
                      "maxLength": 120,
                      "minLength": 1,
                      "type": "string"
                    },
                    "include_meta": {
                      "description": "Include submission metadata (IP, user agent, referrer, timestamp) below the fields.",
                      "type": "boolean"
                    },
                    "intro": {
                      "anyOf": [
                        {
                          "maxLength": 4000,
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Plain-text paragraph above the submitted fields. Supports {{tokens}}. Null removes it."
                    },
                    "subject": {
                      "description": "Notification email subject. Supports {{tokens}} such as {{form.name}} or {{name}}.",
                      "maxLength": 300,
                      "minLength": 1,
                      "type": "string"
                    }
                  },
                  "type": "object"
                },
                "forms": {
                  "default": [],
                  "description": "Forms to create or update on the site, matched by slug. Re-running is safe.",
                  "items": {
                    "properties": {
                      "email": {
                        "description": "Per-form subject and intro overrides for the notification email.",
                        "properties": {
                          "intro": {
                            "anyOf": [
                              {
                                "maxLength": 4000,
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Per-form intro override. Supports {{tokens}}. Null falls back to the project intro."
                          },
                          "subject": {
                            "anyOf": [
                              {
                                "maxLength": 300,
                                "minLength": 1,
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Per-form subject override. Supports {{tokens}}. Null falls back to the project subject."
                          }
                        },
                        "type": "object"
                      },
                      "field_contract": {
                        "anyOf": [
                          {
                            "items": {
                              "properties": {
                                "label": {
                                  "anyOf": [
                                    {
                                      "maxLength": 120,
                                      "minLength": 1,
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ],
                                  "description": "Human label used in the snippet and notification email. Defaults to the field name."
                                },
                                "name": {
                                  "description": "Posted field name. HTML checkbox groups / multi-select must end in [] (services[]) or only the last value is stored. JSON arrays omit the brackets.",
                                  "maxLength": 80,
                                  "minLength": 1,
                                  "type": "string"
                                },
                                "report": {
                                  "default": false,
                                  "description": "Include this field in dashboard summaries and reports.",
                                  "type": "boolean"
                                },
                                "type": {
                                  "description": "text, email, textarea, file, etc. type=file emits a file input in get_snippet.",
                                  "maxLength": 40,
                                  "minLength": 1,
                                  "type": "string"
                                }
                              },
                              "required": [
                                "name",
                                "type"
                              ],
                              "type": "object"
                            },
                            "type": "array"
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Declared fields (name, type, label, report). Drives get_snippet and the email layout. Null clears it."
                      },
                      "fields": {
                        "description": "Shorthand for field_contract: the fields this form posts.",
                        "items": {
                          "properties": {
                            "label": {
                              "anyOf": [
                                {
                                  "maxLength": 120,
                                  "minLength": 1,
                                  "type": "string"
                                },
                                {
                                  "type": "null"
                                }
                              ],
                              "description": "Human label used in the snippet and notification email. Defaults to the field name."
                            },
                            "name": {
                              "description": "Posted field name. HTML checkbox groups / multi-select must end in [] (services[]) or only the last value is stored. JSON arrays omit the brackets.",
                              "maxLength": 80,
                              "minLength": 1,
                              "type": "string"
                            },
                            "report": {
                              "default": false,
                              "description": "Include this field in dashboard summaries and reports.",
                              "type": "boolean"
                            },
                            "type": {
                              "description": "text, email, textarea, file, etc. type=file emits a file input in get_snippet.",
                              "maxLength": 40,
                              "minLength": 1,
                              "type": "string"
                            }
                          },
                          "required": [
                            "name",
                            "type"
                          ],
                          "type": "object"
                        },
                        "type": "array"
                      },
                      "name": {
                        "description": "Form display name, e.g. Contact or Quote request.",
                        "maxLength": 120,
                        "minLength": 1,
                        "type": "string"
                      },
                      "notify_emails_override": {
                        "anyOf": [
                          {
                            "items": {
                              "format": "email",
                              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                              "type": "string"
                            },
                            "maxItems": 10,
                            "type": "array"
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Recipients for this form only. Null inherits the project's notify_emails."
                      },
                      "redirect_url_override": {
                        "anyOf": [
                          {
                            "format": "uri",
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Success redirect for this form only. Null inherits default_redirect_url."
                      },
                      "require_turnstile_override": {
                        "anyOf": [
                          {
                            "type": "boolean"
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Force Turnstile on or off for this form. Null inherits the project setting."
                      },
                      "slug": {
                        "description": "Lowercase hyphenated identifier, unique per project. Used for idempotent re-runs.",
                        "maxLength": 80,
                        "minLength": 1,
                        "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
                        "type": "string"
                      },
                      "webhook_secret_override": {
                        "anyOf": [
                          {
                            "minLength": 1,
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "HMAC secret for this form's webhook. Null inherits the project secret."
                      },
                      "webhook_url_override": {
                        "anyOf": [
                          {
                            "format": "uri",
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Webhook endpoint for this form only. Null inherits the project webhook."
                      }
                    },
                    "required": [
                      "name",
                      "slug"
                    ],
                    "type": "object"
                  },
                  "type": "array"
                },
                "from_name": {
                  "anyOf": [
                    {
                      "maxLength": 120,
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Legacy From display name. Prefer email.from_name."
                },
                "honeypot_field": {
                  "description": "Name of the hidden honeypot input the snippet emits. Defaults to _gotcha.",
                  "maxLength": 80,
                  "minLength": 1,
                  "type": "string"
                },
                "name": {
                  "description": "Client (company) display name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "notify_emails": {
                  "default": [],
                  "description": "Addresses that receive each clean submission (max 10). Inherited by every form.",
                  "items": {
                    "format": "email",
                    "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "type": "string"
                  },
                  "maxItems": 10,
                  "type": "array"
                },
                "project_name": {
                  "description": "Website display name. Defaults to the client name.",
                  "maxLength": 120,
                  "minLength": 1,
                  "type": "string"
                },
                "project_slug": {
                  "description": "Website slug. Defaults to the client slug.",
                  "maxLength": 80,
                  "minLength": 1,
                  "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
                  "type": "string"
                },
                "rate_limit_per_ip": {
                  "description": "Max submissions per IP within rate_limit_window_s.",
                  "exclusiveMinimum": 0,
                  "maximum": 1000,
                  "type": "integer"
                },
                "rate_limit_window_s": {
                  "description": "Rate-limit window in seconds (max 86400).",
                  "exclusiveMinimum": 0,
                  "maximum": 86400,
                  "type": "integer"
                },
                "require_turnstile": {
                  "description": "Reject submissions that lack a valid Turnstile token.",
                  "type": "boolean"
                },
                "slug": {
                  "description": "Lowercase hyphenated identifier, unique per team. Used for idempotent re-runs.",
                  "maxLength": 80,
                  "minLength": 1,
                  "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
                  "type": "string"
                },
                "team_id": {
                  "description": "Team id from list_teams. Required for operator tokens and OAuth logins; team-scoped frw_ tokens may omit it.",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                  "type": "string"
                },
                "turnstile_secret": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Cloudflare Turnstile secret used to verify tokens server-side. Null removes it."
                },
                "turnstile_site_key": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Cloudflare Turnstile site key for the frontend widget. Null removes it."
                },
                "upload_allowed_types": {
                  "description": "Allowed upload MIME types, e.g. application/pdf or image/*.",
                  "items": {
                    "maxLength": 80,
                    "minLength": 3,
                    "pattern": "^[a-z0-9.+-]+\\/[a-z0-9.+*-]+$",
                    "type": "string"
                  },
                  "maxItems": 20,
                  "minItems": 1,
                  "type": "array"
                },
                "upload_max_file_bytes": {
                  "description": "Max bytes per file (up to 25 MB).",
                  "exclusiveMinimum": 0,
                  "maximum": 26214400,
                  "type": "integer"
                },
                "upload_max_files": {
                  "description": "Max files per submission (up to 20).",
                  "exclusiveMinimum": 0,
                  "maximum": 20,
                  "type": "integer"
                },
                "upload_max_total_bytes": {
                  "description": "Max total upload bytes per submission (up to 50 MB).",
                  "exclusiveMinimum": 0,
                  "maximum": 52428800,
                  "type": "integer"
                },
                "uploads_enabled": {
                  "description": "Accept multipart file fields on this project's forms.",
                  "type": "boolean"
                },
                "webhook_secret": {
                  "anyOf": [
                    {
                      "minLength": 1,
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "HMAC-SHA256 secret for the X-Furrow-Signature header. Omit to have one generated and returned."
                },
                "webhook_url": {
                  "anyOf": [
                    {
                      "format": "uri",
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Public https endpoint that receives a signed JSON POST per clean submission. Null disables it."
                }
              },
              "required": [
                "name",
                "slug"
              ],
              "type": "object"
            },
            "annotations": {
              "idempotentHint": true,
              "readOnlyHint": false
            }
          }
        ]
      },
      "name": "furrow-forms",
      "note": "Indexed from the official MCP registry: facts and our own checks, not reviewed, so no score, grade or rank.",
      "packages": [
        {
          "registryType": "npm",
          "identifier": "@furrowforms/mcp",
          "version": "1.0.1",
          "transport": "stdio"
        }
      ],
      "pageJsonUrl": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms.json",
      "popularity": {
        "githubStars": 1,
        "npmWeekly": 34
      },
      "registryName": "com.furrowforms/furrow-forms",
      "remotes": [
        {
          "type": "streamable-http",
          "url": "https://api.furrowforms.com/mcp"
        }
      ],
      "repository": "https://github.com/useburrow/furrow-forms",
      "reviewed": false,
      "slug": "furrowforms-furrow-forms",
      "source": "the official MCP registry",
      "sourceUrl": "https://registry.modelcontextprotocol.io/v0.1/servers?search=com.furrowforms/furrow-forms",
      "summary": "Form backend an agent runs end to end: provision forms, snippets, spam, signed webhooks.",
      "updatedAt": "2026-08-26T20:10:18Z",
      "url": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms",
      "vendor": "furrowforms.com",
      "vendorUrl": "https://furrowforms.com/ai",
      "version": "1.0.1",
      "websiteUrl": "https://furrowforms.com/ai",
      "where": "both",
      "why": [
        "vendor"
      ]
    }
  },
  "kind": "anchor.page",
  "links": {
    "api": "https://www.anchorterminal.com/api/v1/index.json",
    "html": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms",
    "json": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms.json",
    "llms": "https://www.anchorterminal.com/llms.txt",
    "markdown": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms.md",
    "slim": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms.min.md"
  },
  "markdown": "# furrow-forms\n\n\u003e Indexed, not reviewed: facts from the official MCP registry and our own checks. No score, grade or rank, and not in the rankings until the panel reviews it. How the index works: https://www.anchorterminal.com/indexed/\n\n- Kind: MCP server, by furrowforms.com (https://furrowforms.com/ai)\n- Listed because: It's published in the registry under furrowforms.com, a namespace the registry only gives to whoever proves they control that domain.\n- What the official MCP registry says: Form backend an agent runs end to end: provision forms, snippets, spam, signed webhooks.\n\n## Facts\n\n- MCP registry: `com.furrowforms/furrow-forms` 1.0.1\n- Endpoint: https://api.furrowforms.com/mcp (streamable HTTP)\n- Package: npm `@furrowforms/mcp` (stdio)\n- Source: https://github.com/useburrow/furrow-forms\n- Website: https://furrowforms.com/ai\n- npm downloads a week: 34\n- GitHub stars: 1\n- Registry entry updated: 2026-08-26\n\n## Tools\n\n- Tools it lists (27, about 15,637 tokens of context, `tools/list` without credentials over MCP 2026-07-28, checked 2026-10-04 22:22 UTC):\n  - `list_teams` (read-only): 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…\n  - `update_team` (writes): 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…\n  - `get_account` (read-only): Use to read the team's plan, usage this month, limits, expansion_packs, retention_days, branding, and AI spam filter (ai.typesafe_key_set,…\n  - `update_account` (writes): 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…\n  - `create_upgrade_link` (writes): Use when a free team is blocked on the 3-project, 100-submission, or one-workspace limit, or when a human should upgrade to yearly ($199/year) so you can keep…\n  - `list_clients` (read-only): 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…\n  - `get_client` (read-only): Use to inspect one client. Do not use to list that client's sites — call list_projects with client_id.\n  - `create_client` (writes): 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.…\n  - `update_client` (writes): Use to rename a client. Do not use this to change domains, Turnstile, or webhooks — call update_project.\n  - `archive_client` (writes): Use to archive a client. Do not use this as a hard delete. There is no unarchive tool in v1.\n  - `list_projects` (read-only): 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…\n  - `get_project` (read-only): Use to inspect one website's settings, domains, webhook URL, email templates, upload policy, plan, usage this month, limits, retention_days, and branding.…\n  - `list_forms` (read-only): 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…\n  - `get_form` (read-only): 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…\n  - `list_submissions` (read-only): 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…\n  - `get_submission` (read-only): 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…\n  - `get_snippet` (read-only): 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…\n  - `create_project` (writes): 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;…\n  - `update_project` (writes): Use to patch website settings. Nested email sets notification templates: email.subject, email.from_name, email.intro, email.footer_mode (furrow | minimal |…\n  - `rotate_project_inbox` (writes): 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…\n  - `archive_project` (writes): 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.\n  - `create_form` (writes): 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,…\n  - `update_form` (writes): 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…\n  - `archive_form` (writes): Use to archive a form so public submit returns 404. Do not use this as a hard delete.\n  - `upsert_project_webhook` (writes): 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…\n  - `test_webhook` (writes): 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…\n  - `bootstrap_site` (writes): 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…\n- How its tools read to an agent (0 errors, 5 warnings, 1 note, about 15,637 tokens; rules at https://www.anchorterminal.com/check.md; not part of the score):\n  - warn TC07 bootstrap_site: the description is about 601 tokens\n  - warn TC22 bootstrap_site: the definition is about 2,798 tokens\n  - warn TC22 create_project: the definition is about 1,678 tokens\n  - warn TC22 update_project: the definition is about 1,771 tokens\n  - warn TC23 server: 27 tools, about 15,645 tokens of definitions\n  - note TC24 server: 27 of 27 tools have no outputSchema\n\n- JSON: https://www.anchorterminal.com/api/v1/tools/furrowforms-furrow-forms.json\n- Being indexed says nothing about quality, and nobody can pay for it. Ask for a review: https://www.anchorterminal.com/builders/#claiming\n",
  "meta": {
    "attribution": "Anchor Terminal (https://www.anchorterminal.com)",
    "docs": "https://www.anchorterminal.com/docs/",
    "generatedAt": "2026-10-05",
    "license": "CC-BY-4.0",
    "method": "https://www.anchorterminal.com/benchmark/",
    "methodology": "0.3",
    "openapi": "https://www.anchorterminal.com/openapi.json",
    "preview": false,
    "run": "2026-10-01",
    "runLabel": "October 2026 research run"
  },
  "page": {
    "breadcrumbs": [
      {
        "name": "Home",
        "url": "https://www.anchorterminal.com/"
      },
      {
        "name": "Terminal",
        "url": "https://www.anchorterminal.com/tools/"
      },
      {
        "name": "Indexed",
        "url": "https://www.anchorterminal.com/indexed/"
      },
      {
        "name": "furrow-forms",
        "url": ""
      }
    ],
    "description": "furrow-forms, an MCP server by furrowforms.com, listed from the official MCP registry. Indexed, not reviewed: facts and our own checks, no score or ranking. Form backend an agent runs end to end: provision forms, snippets, spam, signed webhooks.",
    "facts": [
      "not reviewed",
      "not ranked",
      "facts only"
    ],
    "h1": "furrow-forms",
    "image": "https://www.anchorterminal.com/assets/og/indexed.png",
    "path": "/tools/furrowforms-furrow-forms",
    "published": "",
    "section": "indexed",
    "title": "furrow-forms: MCP server, indexed from the official MCP registry",
    "toc": null,
    "updated": "2026-10-05",
    "url": "https://www.anchorterminal.com/tools/furrowforms-furrow-forms"
  },
  "tokens": {
    "markdown": 1850,
    "slim": 1780
  },
  "version": 1
}
