Koskamo

Doorman MCP

Doorman reads every submission to a website's forms and lets real customers through while sales pitches, SEO spam and bots stay out. It stops spam, forwards only real submissions, and provides a plain-language reason for each decision, allowing agents to integrate spam screening directly into form handling workflows.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

Doorman MCP logo, by DoormanVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-07Operated by Doorman
MCP endpoint (Streamable HTTP)
https://withdoorman.com/mcp
Vendor documentation

What its tools do

12 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

12 of 12 have a description · 5 of 12 declare behavior hints · 6 of 11 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Passed Official MCP Registry namespace is tied to withdoorman.com ·
  • Passed Endpoint is on the registry namespace domain ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Screen contact form submissions for spam
  • Filter SEO spam and bots from lead forms
  • Automate fraud screening for demo requests

Source and maintenance

Vendor evidenceRegistry 0.1.0

Protocol and capabilities

Server
doorman 0.1.0
MCP protocol negotiated in check
2025-06-18
Tools
12 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": false
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Doorman screens a website's form submissions (contact, demo, checkout, comments) for sales pitches, bots and fraud, and forwards only the real ones. Act on a check's `action` (or the boolean `deliver`), never on `route`: route is Doorman's opinion, action is what to do (they differ in watch mode). To set it up for a new user: doorman_signup (ask for their email). If they already have an account and this connection has no key, ask them for one (https://withdoorman.com/app#/settings) and pass it as api_key; don't sign up again. Then, put the returned action URL in the project's form, set a destination, then doorman_test_submission to show it working. Docs: https://withdoorman.com/llms.txt

Tools

12 advertised

doorman_docs
Advertised by the server during the last successful anonymous check.
Advertised read-only

Read how Doorman works and how to integrate it (the same text as /llms.txt). Call this first if you haven't used Doorman before.

doorman_docs input schema
{
  "type": "object",
  "properties": {}
}
doorman_docs annotations
{
  "readOnlyHint": true
}
doorman_signup
Advertised by the server during the last successful anonymous check.

Create a Doorman account for the user with a first form and an API key. Ask the user for their email first. They'll get an email to set a dashboard password. Creates the account's first form too and returns its id and action URL, plus the api_key (store it as DOORMAN_KEY in the project's local secrets file, never commit it). Only for new users: if they already have an account, ask for a key instead. Until the user clicks the confirmation link in that email, nothing is emailed to them (100 checks; Slack and webhooks work).

doorman_signup input schema
{
  "type": "object",
  "required": [
    "email",
    "site_url",
    "site_context"
  ],
  "properties": {
    "mode": {
      "enum": [
        "watch",
        "enforce"
      ],
      "type": "string",
      "description": "watch delivers would-be drops, tagged; holds still follow forward_holds. Recommended for a new lead form: switch to enforce after a week or two of verdicts look right. Default enforce."
    },
    "email": {
      "type": "string",
      "description": "The user's email. Real submissions are forwarded here by default."
    },
    "site_url": {
      "type": "string",
      "description": "The website the form is on, e.g. acme.com"
    },
    "form_name": {
      "type": "string",
      "description": "Optional name, e.g. 'Contact form' or 'Demo request'"
    },
    "site_context": {
      "type": "string",
      "description": "One or two sentences: what the business sells and to whom. Doorman compares every submission against this. Read the project's README/landing copy to write it."
    }
  }
}
doorman_whoami
Advertised by the server during the last successful anonymous check.
Advertised read-only

Account, plan and this month's usage.

doorman_whoami input schema
{
  "type": "object",
  "properties": {
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    }
  }
}
doorman_whoami annotations
{
  "readOnlyHint": true
}
doorman_list_forms
Advertised by the server during the last successful anonymous check.
Advertised read-only

List the account's forms with their action URLs and settings.

doorman_list_forms input schema
{
  "type": "object",
  "properties": {
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    }
  }
}
doorman_list_forms annotations
{
  "readOnlyHint": true
}
doorman_create_form
Advertised by the server during the last successful anonymous check.

Create another form endpoint (one per distinct form on the site: contact, demo request, checkout, comments).

doorman_create_form input schema
{
  "type": "object",
  "required": [
    "name"
  ],
  "properties": {
    "kind": {
      "enum": [
        "lead",
        "signup",
        "checkout",
        "comment"
      ],
      "type": "string",
      "description": "lead = contact/demo/quote/sales form (default)"
    },
    "name": {
      "type": "string",
      "description": "Form name"
    },
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "email_to": {
      "type": "string",
      "description": "Comma-separated emails to forward real submissions to"
    },
    "slack_url": {
      "type": "string",
      "description": "Slack incoming webhook URL"
    },
    "webhook_url": {
      "type": "string",
      "description": "HTTPS URL that receives a signed JSON POST per real submission"
    },
    "redirect_url": {
      "type": "string",
      "description": "Where to send the visitor after submitting (default: a Doorman thank-you page)"
    },
    "site_context": {
      "type": "string",
      "description": "What the business sells and to whom"
    }
  }
}
doorman_update_form
Advertised by the server during the last successful anonymous check.

Change a form's settings: context, destinations, thresholds, watch mode, allow/block lists.

doorman_update_form input schema
{
  "type": "object",
  "required": [
    "form_id"
  ],
  "properties": {
    "kind": {
      "enum": [
        "lead",
        "signup",
        "checkout",
        "comment"
      ],
      "type": "string"
    },
    "mode": {
      "enum": [
        "enforce",
        "watch"
      ],
      "type": "string",
      "description": "watch = deliver would-be drops, tagged (a safe way to start)"
    },
    "name": {
      "type": "string",
      "description": "Form name"
    },
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "form_id": {
      "type": "string",
      "description": "f_..."
    },
    "email_to": {
      "type": "string",
      "description": "Comma-separated emails"
    },
    "slack_url": {
      "type": "string",
      "description": "Slack incoming webhook URL"
    },
    "allow_list": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Emails or domains always delivered without judging"
    },
    "block_list": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Emails or domains always dropped"
    },
    "deliver_at": {
      "type": "number",
      "description": "Deliver when P(real) >= this (default 0.8)"
    },
    "drop_below": {
      "type": "number",
      "description": "Drop when P(real) < this (default 0.2)"
    },
    "webhook_url": {
      "type": "string",
      "description": "HTTPS webhook URL"
    },
    "redirect_url": {
      "type": "string",
      "description": "Redirect after submit"
    },
    "site_context": {
      "type": "string",
      "description": "What the business sells and to whom"
    },
    "forward_holds": {
      "type": "boolean",
      "description": "Forward held submissions, flagged (default true)"
    }
  }
}
doorman_get_install_snippet
Advertised by the server during the last successful anonymous check.
Advertised read-only

Get ready-to-paste integration code for a form on a given platform. Use 'html' for static sites, 'react' for SPA client components, and 'fetch' (plain fetch with timeout and fallback: Workers, Node, Next, Deno), 'nextjs', 'express', 'python', 'ruby' or 'elixir' when the form already posts to the project's own backend.

doorman_get_install_snippet input schema
{
  "type": "object",
  "required": [
    "form_id",
    "platform"
  ],
  "properties": {
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "form_id": {
      "type": "string",
      "description": "f_..."
    },
    "platform": {
      "enum": [
        "html",
        "ajax",
        "react",
        "fetch",
        "nextjs",
        "express",
        "curl",
        "python",
        "ruby",
        "elixir",
        "webflow",
        "framer",
        "wordpress"
      ],
      "type": "string"
    }
  }
}
doorman_get_install_snippet annotations
{
  "readOnlyHint": true
}
doorman_test_submission
Advertised by the server during the last successful anonymous check.

Judge a sample message against a form's settings. Free, not forwarded, not counted. Use it to show the user Doorman working after setup (try one genuine enquiry and one sales pitch).

doorman_test_submission input schema
{
  "type": "object",
  "required": [
    "form_id",
    "message"
  ],
  "properties": {
    "email": {
      "type": "string",
      "description": "Optional sender email"
    },
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "form_id": {
      "type": "string",
      "description": "f_..."
    },
    "message": {
      "type": "string",
      "description": "The message text"
    }
  }
}
doorman_send_test_delivery
Advertised by the server during the last successful anonymous check.

Send a sample delivery to the form's email/Slack/webhook destinations and report whether each one worked.

doorman_send_test_delivery input schema
{
  "type": "object",
  "required": [
    "form_id"
  ],
  "properties": {
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "form_id": {
      "type": "string",
      "description": "f_..."
    }
  }
}
doorman_list_submissions
Advertised by the server during the last successful anonymous check.
Advertised read-only

Recent submissions with their verdicts. Use review=true for held ones waiting for a human.

doorman_list_submissions input schema
{
  "type": "object",
  "properties": {
    "limit": {
      "type": "number"
    },
    "route": {
      "enum": [
        "deliver",
        "hold",
        "drop"
      ],
      "type": "string"
    },
    "review": {
      "type": "boolean"
    },
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "form_id": {
      "type": "string",
      "description": "Optional f_..."
    }
  }
}
doorman_list_submissions annotations
{
  "readOnlyHint": true
}
doorman_label_submission
Advertised by the server during the last successful anonymous check.

Mark a submission real (delivers it if it was held or dropped) or spam.

doorman_label_submission input schema
{
  "type": "object",
  "required": [
    "submission_id",
    "label"
  ],
  "properties": {
    "label": {
      "enum": [
        "real",
        "spam"
      ],
      "type": "string"
    },
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "submission_id": {
      "type": "string",
      "description": "sub_..."
    }
  }
}
doorman_contact_support
Advertised by the server during the last successful anonymous check.

Stuck, or something isn't working? Send the problem straight to Doorman's founder, with the error you hit. Your account context (plan, forms, recent errors, never keys) is attached, and the reply goes to the account email. Use it instead of guessing at a fix.

doorman_contact_support input schema
{
  "type": "object",
  "required": [
    "message"
  ],
  "properties": {
    "error": {
      "type": "string",
      "description": "The exact error text, if any"
    },
    "api_key": {
      "type": "string",
      "description": "Doorman API key (dm_live_...). Only needed if the MCP connection has no Authorization header."
    },
    "message": {
      "type": "string",
      "description": "What you were trying to do and what happened"
    },
    "category": {
      "enum": [
        "setup",
        "bug",
        "billing",
        "question",
        "other"
      ],
      "type": "string"
    }
  }
}

Prompts

Not advertised

No prompt definitions available.

Resources

Not advertised

No resource definitions available.

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (5 of 5 answered).

  1. 2026-11-07: 1 of 1 checks answered
  2. 2026-11-09: 2 of 2 checks answered
  3. 2026-11-10: 2 of 2 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
351 ms
95th percentile latency
351 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 351 ms · metadata changed · 12 tool(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http doorman-mcp-withdoorman https://withdoorman.com/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add doorman-mcp-withdoorman --url https://withdoorman.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable doorman-mcp-withdoorman in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "doorman-mcp-withdoorman": {
      "url": "https://withdoorman.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "doorman-mcp-withdoorman": {
      "type": "streamableHttp",
      "url": "https://withdoorman.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start doorman-mcp-withdoorman and inspect its tools.
VS Code configuration
{
  "servers": {
    "doorman-mcp-withdoorman": {
      "type": "http",
      "url": "https://withdoorman.com/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http doorman-mcp-withdoorman https://withdoorman.com/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://withdoorman.com/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "doorman-mcp-withdoorman": {
      "serverUrl": "https://withdoorman.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like Doorman MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run Doorman MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing