Back to Discover

gopigeon-mcp

connector

arvaer

MCP Server for GoPigeon.dev

View on GitHub
0 starsSynced Aug 5, 2026

Install to Claude Code

/plugin marketplace add arvaer/gopigeon-mcp

README

@gopigeon/mcp

MCP server for Gopigeon — anonymous form endpoints + durable queues for AI coding agents. Thirteen stdio tools, zero signup.

Tools

Thirteen stdio tools across four surfaces.

Forms (5 tools)

  • create_endpoint — anonymous claim flow by default; owned mode when GOPIGEON_API_KEY is set (no claim email, no 30-day TTL — the form belongs to the authenticated user immediately). Pass kind: "telemetry" for a high-volume event endpoint (see Telemetry endpoints). Supports dry_run: true for forward-compat (see note below).
  • update_endpoint — requires GOPIGEON_API_KEY; patch shape — only the supplied fields are applied (name, redirect_url, allowed_origins, is_active). Omitted fields are preserved; re-applying the same patch is byte-identical (idempotent). Cannot change kind.
  • get_submissions — requires GOPIGEON_API_KEY; read submissions on endpoints you own. Pass since (ISO-8601 UTC) for incremental pulls (see Incremental reads).
  • list_endpoints — requires GOPIGEON_API_KEY; list endpoints you own. readOnlyHint: true, idempotentHint: true.
  • add_destination — requires GOPIGEON_API_KEY; attach an email / slack / discord / webhook destination to an owned endpoint. CC/BCC unsupported — use N email destinations instead.

Destinations (3 tools)

  • list_destinations — requires GOPIGEON_API_KEY; list destinations on an owned endpoint. Secrets (signing secrets, full webhook URLs) are redacted in the response. readOnlyHint: true, idempotentHint: true.
  • update_destination — requires GOPIGEON_API_KEY; patch a destination's type / config / is_active in place (no delete-and-recreate). Use {is_active: false} to pause fan-out without losing config. Omitted fields are preserved. idempotentHint: true.
  • remove_destination — requires GOPIGEON_API_KEY; idempotent — removing an already-removed destination returns success (no error).

Queues (5 tools, post-v1.0 surface)

  • create_queue — no auth; returns queue_api_key ONCE
  • publish_to_queue — requires GOPIGEON_QUEUE_API_KEY (supports dry_run: true for routing preview)
  • pull_queue — requires GOPIGEON_QUEUE_API_KEY
  • ack_queue — requires GOPIGEON_QUEUE_API_KEY
  • subscribe_form_to_queue — requires GOPIGEON_API_KEY (forms-side, not queue-side)

Utility (1 tool, works with both surfaces)

  • inspect_endpoint — no auth; no-side-effect probe; prefix-dispatches on f_* (form) / q_* (queue) IDs; v1.3 verifiability primitive paired with dry_run

Quota

Forms

Free tier: 50 submissions/month per form endpoint.

On exceed, the form submission endpoint returns HTTP 402 with auto_enqueued: true — the submission is durably persisted server-side and will replay automatically when the form owner upgrades to Pro. PRICE-04 shape preserved at the lower threshold (form-side cap was 500 submissions/month in v1.3; v1.4 drops to 50 to mirror the queue free-tier strictness).

Telemetry

Free tier: 5,000 events/month. Pro: 100,000 events/month.

Metered on a counter of its own — telemetry events never consume submissions_per_month, and form submissions never consume the telemetry allowance.

On exceed, POST /f/:id returns HTTP 402 with kind: "telemetry", queued: false, will_replay_on_upgrade: false. Unlike form endpoints there is no auto-enqueue: a telemetry endpoint has no destination to replay to, so holding the event would preserve nothing.

Queues

Free tier: 100 messages/month per user across all queues.

On exceed, publish_to_queue returns HTTP 402 with auto_enqueued: true — the envelope is durably persisted server-side and will replay automatically when you (or the queue owner) upgrade to Pro. No envelope is silent-dropped.

For owned (Bearer-claimed) queues, the counter is per-user across every queue they own. For anonymous (unclaimed) queues, a separate per-source-IP counter applies; the envelope still persists, but replay requires the queue to be claimed AND the owner to upgrade.

Read the full Free vs Pro section at /docs/queues#free-vs-pro.

Telemetry endpoints (v0.5.0+)

For high-volume product events — clicks, page views, funnel steps — rather than leads. Create with kind: "telemetry" (owned mode only; the kind is fixed at creation):

// create_endpoint
{ "name": "Site events", "kind": "telemetry" }

Submit to /f/:id exactly as with a form endpoint. What differs:

Form endpointTelemetry endpoint
Countersubmissions_per_monthseparate telemetry allowance
Free / Pro50 / 10,000 per month5,000 / 100,000 per month
Retention30 / 90 days7 / 30 days, actively swept
Destinationsrequired to be usefulrefused (400)
Spam scoring_gotcha honeypot evaluatednot scored; always is_spam: 0
Over quota402 + auto-enqueue + replay on upgrade402, queued: false

The separation is the point: a click stream can never consume the quota that gates your lead delivery. add_destination against a telemetry endpoint returns 400 — the guard applies after creation as well as at creation.

Idempotency

POST /f/:id accepts an optional Idempotency-Key header (max 255 printable ASCII characters, no spaces). A repeat carrying a key already seen on that endpoint stores nothing and returns the original submission_id with idempotent_replay: true, consuming no quota.

This matters for fire-and-forget browser sends with keepalive: true, where the browser may retry on its own and inflate counts invisibly. Generate a fresh UUID per logical event; reuse it verbatim on retries of that event. Omit the header to opt out. A malformed key returns 400 rather than being ignored.

Incremental reads (v0.5.0+)

get_submissions accepts since — an ISO-8601 UTC timestamp — returning only rows changed after that instant, oldest-first, plus next_since in the response. Store that watermark and pass it back on the next call.

// first call
{ "form_id": "f_abc123def456xyz0", "since": "2026-08-01T00:00:00Z" }
// response carries next_since — hand it back next time

The cursor runs over updated_at, not created_at, so it catches edits to older rows as well as new submissions. Without it every pull re-walks the full history and gets slower forever — the cost that makes telemetry volume painful to ingest.

Rows carry data (raw JSON string, kept for backwards compatibility) and data_parsed (the same payload already decoded — prefer it), plus created_at_iso / updated_at_iso alongside the database-native timestamps.

Verifiability (v0.3.0+)

Before consuming the one-shot claim event, agents can verify endpoint wiring without side effects. Two mechanisms — one is a flag on the existing tools, the other is a new probe tool.

Dry-run mode — dry_run flag on existing tools

Pass dry_run: true to create_endpoint or publish_to_queue. The tool appends ?dry_run=1 to the outgoing request; the backend runs the full guard cascade (CORS, rate-limit, honeypot, quota read for forms; Bearer auth, body-size guard, read-only quota preview for queues) and returns a routing preview only — sends nothing, no claim email, no funnel event, no quota counter, no AMQP publish.

// MCP tool call (Claude Code):
{
  "tool": "publish_to_queue",
  "args": {
    "queue_id": "q_abc123",
    "payload": { "hello": "world" },
    "dry_run": true
  }
}
// → structuredContent: { dry_run: true, would_route_to: [...], would_have_counted: {...} }

The dry_run field is z.boolean().optional().default(false) — agents using older @gopigeon/mcp@^0.2.0 that omit the field continue to work; the URL has no ?dry_run=1 suffix (a regular real-submission call).

Dry-run is a routing preview — sends nothing. Not a sandbox tier.

Claim-status probe — inspect_endpoint tool

inspect_endpoint is a no-side-effect probe that prefix-dispatches on the endpoint ID:

  • f_* IDs route to GET /f/{id}/status
  • q_* IDs route to GET /q/{id}/status
  • Other prefixes return a structured error WITHOUT making an HTTP call

Returns {exists, claimed, active} on 200, or {exists: false} on 404 (treated as a valid "not found" answer, not an error). The tool advertises readOnlyHint: true, idempotentHint: true so agent runtimes can safely cache or reorder calls. Shares the 60/min/IP rate-limit bucket with ?dry_run=1 requests.

// MCP tool call:
{
  "tool": "inspect_endpoint",
  "args": { "endpoint_id": "f_abc123def456xyz0" }
}
// → structuredContent: { exists: true, claimed: false, active: true }

Use this BEFORE consuming the claim event with a real submission — it tells you whether the form exists and whether the one-shot claim slot is still available.

Response shapes

ToolReal call returnsDry-run / probe returns
create_endpoint{form_id, endpoint_url, claim_note}{dry_run: true, would_route_to, ...}
publish_to_queue{seq, id}{dry_run: true, would_have_counted: {quota_used, quota_remaining}}
inspect_endpoint(no real-call variant — always probe){exists, claimed, active} or {exists: false}

Install as a Claude Code plugin

The quickest way to get both the connector and the gopigeon skill — which teaches agents how to use it — is the plugin:

/plugin marketplace add arvaer/gopigeon-mcp
/plugin install gopigeon@gopigeon-mcp

That wires up the MCP server and installs the skill in one step. Set GOPIGEON_API_KEY / GOPIGEON_QUEUE_API_KEY in your environment first if you need the authenticated tools (see Environment).

Prefer to wire the MCP server up by hand? The manual installs are below.

Install (Claude Code)

# Anonymous mode — create_endpoint + create_queue only
claude mcp add --transport stdio gopigeon -- npx -y @gopigeon/mcp@^0.4.0

# With form API key for get_submissions + list_endpoints
claude mcp add --transport stdio --env GOPIGEON_API_KEY=YOUR_KEY gopigeon -- npx -y @gopigeon/mcp@^0.4.0

# With queue API key for publish/pull/ack
claude mcp add --transport stdio --env GOPIGEON_QUEUE_API_KEY=YOUR_QK gopigeon -- npx -y @gopigeon/mcp@^0.4.0

Install (Cursor / generic JSON config)

{
  "mcpServers": {
    "gopigeon": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@gopigeon/mcp@^0.4.0"],
      "env": {
        "GOPIGEON_API_KEY": "${GOPIGEON_API_KEY}",
        "GOPIGEON_QUEUE_API_KEY": "${GOPIGEON_QUEUE_API_KEY}"
      }
    }
  }
}

Both env vars are optional — omit either to disable that surface. The server boots without keys and exposes only the no-auth tools (create_endpoint, create_queue).

Environment

  • GOPIGEON_API_BASE — API base URL (v0.3.0+, preferred). Defaults to https://api.gopigeon.dev (the queue API host). Override for self-hosted or local (http://localhost:8090). Do NOT use https://gopigeon.dev (marketing host, CSRF-gated).
  • GOPIGEON_BASE_URL — Legacy alias for GOPIGEON_API_BASE (backward-compat, one release). Use GOPIGEON_API_BASE for new configurations.
  • GOPIGEON_API_KEY — Forms-side. Required for get_submissions, list_endpoints, and subscribe_form_to_queue. Generate via POST /api/keys from the dashboard.
  • GOPIGEON_QUEUE_API_KEY — Queue-side. Required for publish_to_queue, pull_queue, ack_queue. Returned ONCE by create_queue; never re-issued.

The two API keys live on different trust boundaries — a forms key cannot publish to queues, and a queue key cannot read form submissions. subscribe_form_to_queue is the one cross-surface tool, and it authenticates on the forms side (it mutates forms.queue_id).

Get an API Key

# Log in first, then:
curl -X POST https://gopigeon.dev/api/keys \
  -H "Authorization: Bearer <your_session_token>" \
  -H "Content-Type: application/json" \
  -d '{"name":"claude-code"}'
# → { "api_key": "<64 hex chars>", ... }
# Store immediately — it will not be shown again.

Get a Queue API Key

Either via this MCP server's create_queue tool (preferred for agents) or directly via the REST API:

curl -X POST https://api.gopigeon.dev/q/create \
  -H "Content-Type: application/json" \
  -d '{"consumers":["me"]}'
# → { "queue_id": "q_...", "queue_api_key": "qk_<64 hex>", ... }
# Store the queue_api_key immediately — it is NOT shown again.

See /docs/queues for the full publish/pull/ack worked example.

Develop

git clone https://github.com/arvaer/gopigeon-mcp.git
cd gopigeon-mcp
npm install
npm run build     # compiles src/ → dist/
npm test          # vitest suite
npm run dev       # tsx src/index.ts — runs against live server

This repository is also a Claude Code plugin marketplace — the plugin lives in plugins/gopigeon/ and the catalog is .claude-plugin/marketplace.json. Pull requests welcome.

License

MIT

Rendered live from arvaer/gopigeon-mcp's GitHub README — not stored, always reflects the source repo.

1 Plugin

NameDescriptionCategorySource
gopigeonAnonymous form endpoints and durable queues for AI agents — the gopigeon MCP connector plus a skill that teaches agents how to use it.productivity./plugins/gopigeon

0 Comments

Login required
Log in to post a comment or update on this repo.

No comments yet — be the first to share an update.