# MCP server

> Let Claude Code, Cursor, VS Code and other AI agents manage forms, submissions and webhooks through Ikiform's MCP server.

Ikiform runs a remote [Model Context Protocol](https://modelcontextprotocol.io) server. Connect it to an AI agent and the agent can create, wire up and configure forms, read and triage submissions, and set up and debug webhooks in your workspace, using the same secret keys and scopes as the [REST API](https://ikiform.com/docs/api.md).

|   |   |
| --- | --- |
| URL | `https://ikiform.com/mcp` |
| Transport | Streamable HTTP, stateless, JSON-RPC over `POST` |
| Auth | `Authorization: Bearer ik_sk_...` |
| Rate limit | 100 requests a minute per key, shared with the REST API |

## Create a key

In the [dashboard](https://ikiform.com/dashboard/api-keys), create a **secret** key and give it only the scopes the agent needs. Every tool works on the workspace that owns the key. Keep the key out of your repository: use an environment variable or your client's secret prompt.

| Scope | Tools |
| --- | --- |
| `forms:read` | `list_forms`, `get_form`, and `connect_form` with a `form_id` |
| `forms:write` | `create_form`, `update_form`, `set_form_fields`, `delete_form` |
| `submissions:read` | `list_submissions`, `get_submission` |
| `submissions:write` | `mark_spam`, `mark_not_spam`, `delete_submission` |
| `webhooks:read` | `list_webhook_endpoints`, `list_deliveries` |
| `webhooks:write` | `create_webhook_endpoint` and `update_webhook_endpoint` (with `submissions:read`), `roll_webhook_secret`, `delete_webhook_endpoint`, `send_test_event`, `replay_failed_deliveries` |

> To connect forms in your code, `forms:read` and `forms:write` are enough. For read-only triage, use `submissions:read`. A tool called without its scope returns a `forbidden` error naming the missing scope.

## Connect your client

**Claude Code** (`Terminal`)

```bash
claude mcp add --transport http ikiform https://ikiform.com/mcp \
  --header "Authorization: Bearer ik_sk_..."
```

**Cursor** (`.cursor/mcp.json`)

```json
{
  "mcpServers": {
    "ikiform": {
      "url": "https://ikiform.com/mcp",
      "headers": {
        "Authorization": "Bearer ${env:IKIFORM_API_KEY}"
      }
    }
  }
}
```

**VS Code** (`.vscode/mcp.json`)

```json
{
  "inputs": [
    {
      "type": "promptString",
      "id": "ikiform-api-key",
      "description": "Ikiform secret API key (ik_sk_...)",
      "password": true
    }
  ],
  "servers": {
    "ikiform": {
      "type": "http",
      "url": "https://ikiform.com/mcp",
      "headers": {
        "Authorization": "Bearer ${input:ikiform-api-key}"
      }
    }
  }
}
```

**Other clients** (`mcp.json`)

```json
{
  "mcpServers": {
    "ikiform": {
      "type": "http",
      "url": "https://ikiform.com/mcp",
      "headers": { "Authorization": "Bearer ik_sk_..." }
    }
  }
}
```

In Cursor, set `IKIFORM_API_KEY` in your environment. VS Code asks for the key the first time and stores it securely. Any client that supports remote HTTP servers with custom headers works the same way.

Ikiform is listed in the [official MCP Registry](https://registry.modelcontextprotocol.io/v0/servers?search=ikiform) as `io.github.preetsuthar17/ikiform`. In Claude Code, the [Ikiform plugin](https://github.com/preetsuthar17/ikiform-plugin) adds the server and a skill for connecting forms: run `claude plugin marketplace add preetsuthar17/ikiform-plugin`, then `claude plugin install ikiform@ikiform`.

## Tools

Ids look like `frm_...` for forms, `sub_...` for submissions, `whk_...` for webhook endpoints and `dlv_...` for deliveries. Lists return 25 items by default and 100 at most; when `has_more` is true, pass `next_cursor` as `cursor`.

| Tool | What it does |
| --- | --- |
| `list_forms` | Forms newest first, with id, name, status, submission count and endpoint |
| `get_form` | A form's endpoint, fields, honeypot field, allowed domains, redirect URL, code snippets and setup instructions |
| `create_form` | Creates a form from a name, with optional allowed domains and redirect URL |
| `update_form` | Pauses or resumes a form, and changes its name, allowed domains, redirect URL, spam check, rate limits or email notifications |
| `set_form_fields` | Publishes a field schema that posts are validated against, or removes it |
| `delete_form` | Deletes a form. Its endpoint stops accepting posts |
| `list_submissions` | Submissions newest first, filtered by form, status (`received` or `spam`) or date |
| `get_submission` | One submission with its fields, metadata and spam score |
| `mark_spam`, `mark_not_spam` | Moves a submission to spam or back, sending the matching webhooks |
| `delete_submission` | Permanently deletes a submission. Cannot be undone |
| `list_webhook_endpoints` | Endpoints with their URL, status, events and failure state. Secrets are never returned |
| `create_webhook_endpoint` | Adds an endpoint and returns its signing secret once |
| `update_webhook_endpoint` | Changes an endpoint's URL, form, events or custom headers, or turns it off and on |
| `roll_webhook_secret` | Returns a new signing secret. The old one keeps working for 24 hours |
| `delete_webhook_endpoint` | Deletes an endpoint and its delivery history |
| `list_deliveries` | Recent deliveries for an endpoint, with status, attempts and the last error |
| `send_test_event` | Sends a signed `endpoint.test` event to an active endpoint |
| `replay_failed_deliveries` | Sends failed deliveries from the last `24h`, `3d` or `7d` again |

The server also offers a `connect_form` prompt: step-by-step instructions for connecting the form in your project, filled in with your form's endpoint and fields when you pass a `form_id`.

## What to ask

- “Connect the contact form in this project to Ikiform.”
- “Show me last week's spam on the waitlist form and restore anything that looks real.”
- “Why is my webhook failing? Fix the handler, send a test, then replay what failed today.”
- “Send new waitlist signups to my API route at /api/ikiform and put the secret in .env.”
- “Pause the old contact form and turn on the human check for the new one.”

Agents should confirm with you before deleting forms, submissions or endpoints, replaying deliveries, publishing a field schema or changing allowed domains, spam settings or rate limits. The Claude Code plugin's skill tells them to. Signing and Turnstile secrets belong in environment variables, never in code.

## Dashboard only

API keys, members, notification recipients and billing stay in the dashboard, so a leaked key can't create keys, invite people, email new addresses or spend money.
