BriefGate

MCP serverWeb & browsing

Lets your agent collect briefs, files and login details from clients into one place.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use BriefGate

About this server

Client intake: files, copy and logins from clients, from the browser or your AI agent.

Install BriefGate

The server’s own address, for the clients that take one directly. Or connect ahel once and every client you use reads it from one address, with the account kept on ahel rather than in each client’s config.

  • Claude Code

    claude mcp add --transport http --scope user briefgate 'https://mcp.briefgate.dev/mcp'

    Run it once in your project, then open /mcp to approve any sign-in the server asks for.

  • Claude Desktop

    https://mcp.briefgate.dev/mcp

    Add a custom connector in Settings, paste this address, and approve the sign-in.

  • Cursor

    cursor://anysphere.cursor-deeplink/mcp/install?name=briefgate&config=eyJ1cmwiOiJodHRwczovL21jcC5icmllZmdhdGUuZGV2L21jcCJ9

    Open the link and Cursor adds the server at that address.

  • ChatGPT

    https://mcp.briefgate.dev/mcp

    In Settings, enable Developer mode, create an MCP app, and paste this address. Your plan and workspace must allow custom apps.

  • Codex

    codex mcp add briefgate --url 'https://mcp.briefgate.dev/mcp'

    Run it once, then sign in with codex mcp login briefgate if the server asks for an account.

From the project's README

As published by sekera-radim/briefgate-mcp in README.md.

Client intake — from your browser, or from your AI coding agent.

Your agent can build the website. BriefGate gets the missing things from the client.

No agent? You don't need one. Everything below can be done by hand at app.briefgate.dev: build the request, send the link, watch answers arrive, download the results as one ZIP — no code, no API key, no MCP client. This package is for the other way of working, where an agent does it for you. See the dashboard quickstart.

Claude Code / Cursor / Codex → BriefGate → Client portal
  → Files · copy · credentials · structured data → Agent continues building

Watch as MP4 (25 s) · Full 47 s walkthrough

Website · MCP reference · llms.txt · Guides and checklists

The problem

Agents are fast. The bottleneck is the human on the other side of the project.

Somewhere in the middle of building, the agent needs something only the client has: a logo, homepage copy, brand colors, opening hours, hosting credentials, an API key, a piece of structured data like a price list. None of that exists in the chat, and none of it can be guessed.

The usual move is to stop and ask the developer to go chase the client by email. Instead, the agent creates a BriefGate intake. BriefGate emails the client, collects what comes back, chases automatically when it doesn't, and returns typed results the agent can use directly. The agent keeps building in the meantime.

Quickstart

Claude Code — hosted, no key to manage:

claude mcp add --transport http briefgate https://mcp.briefgate.dev/mcp

Then run /mcp in Claude Code, pick briefgate, and choose Authenticate.

Claude Code — local package:

claude mcp add briefgate -- npx -y @briefgate/mcp
npx -y @briefgate/mcp login

Prefer to skip sign-in entirely? Get a key at briefgate.dev (free tier, no card) and pass it as BRIEFGATE_API_KEY.

Cursor — add to .cursor/mcp.json:

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

Then run npx -y @briefgate/mcp login, or ask the agent to call the login tool.

Codex:

codex mcp add briefgate --env BRIEFGATE_API_KEY=bg_live_xxxxx -- npx -y @briefgate/mcp

Gemini CLI — installs as an extension from this repo's gemini-extension.json, pointed at the hosted endpoint:

gemini extensions install https://github.com/sekera-radim/briefgate-mcp

It authenticates the same way as the other hosted clients above — via OAuth, on first use. The extension also ships GEMINI.md, a context file that tells the model what BriefGate is and when to reach for it.

By default gemini extensions install fetches the repo's latest GitHub Release rather than the main branch; if that release predates the current gemini-extension.json and the command reports a missing configuration file, install from main directly instead: gemini extensions install --ref main https://github.com/sekera-radim/briefgate-mcp.

Claude Desktop — one-click install as a Desktop Extension (.mcpb), running the local @briefgate/mcp package instead of the hosted endpoint. Build details: see MCPB bundle below.

Cursor — as a plugin from this repo's .cursor-plugin/plugin.json, which bundles the same MCP config together with the collect-from-client skill below.

Any Agent Skills-compatible tool (OpenAI Codex, GitHub Copilot / VS Code, Cursor, Gemini CLI, and other clients on that standard) — install the collect-from-client skill with the skills CLI:

npx skills add https://github.com/sekera-radim/briefgate-mcp/tree/main/skills/collect-from-client

The bare owner/repo shorthand the CLI's own docs show does not work against this layout as of skills@1.5.26 — it either 404s against its registry or, given the plain repo URL, clones the whole repo and reports "No SKILL.md found" because ours lives a directory deeper than the root. The full /tree/main/skills/<name> URL above is what actually installs it; verified by running it in an empty scratch directory before documenting it. This copies SKILL.md into that tool's local skills directory; the skill still assumes the briefgate MCP server (see the client-specific instructions above) is configured separately.

Full setup details, manual config, and API-key precedence: see Reference below.

For agents reading project instructions (AGENTS.md, Copilot, Cursor rules)

If your agent reads a project instructions file instead of (or in addition to) MCP tool descriptions or Agent Skills, add this block to your AGENTS.md, .github/copilot-instructions.md, or .cursor/rules:

## BriefGate

BriefGate (MCP server `briefgate`, or `npx @briefgate/mcp`) collects files,
text, choices, or credentials from a human who is not in this conversation
(a client, colleague, or customer) — it emails them a no-account portal link
and chases them automatically until everything is submitted.

Use it when a task is blocked on input only that outside person can supply,
especially if they may take days and need reminders. Do not use it when the
information is already available, or when the person who should answer is
the user you're talking to.

Flow: `define_intake` (with items) -> tell the user it was sent ->
`get_intake_status` later ("not ready" is normal, not an error) ->
`get_intake_results` once completed. `request_revision` for a bad item.
Secret items are revealed in plaintext exactly once.

Example: building a client's website

An agent is building a website for a restaurant. It has the layout and the booking flow, but it still needs the logo, a hero photo, the opening hours, a short description of the restaurant, the social media links, and admin access to the client's WordPress install. It calls define_intake:

{
  "project_name": "Website for Trattoria Bella",
  "client": { "email": "owner@trattoriabella.example", "name": "Marco", "language": "en" },
  "items": [
    { "key": "logo", "type": "image", "label": "Restaurant logo",
      "constraints": { "formats": ["svg", "png"], "min_width": 512 } },
    { "key": "hero_image", "type": "image", "label": "Hero photo for the homepage" },
    { "key": "opening_hours", "type": "structured", "label": "Opening hours",
      "schema": { "type": "object", "properties": { "mon_fri": { "type": "string" }, "sat": { "type": "string" }, "sun": { "type": "string" } } } },
    { "key": "about_copy", "type": "longtext", "label": "Short description of the restaurant" },
    { "key": "social_links", "type": "structured", "label": "Social media links" },
    { "key": "wp_admin", "type": "secret", "label": "WordPress admin credentials" }
  ]
}

From there, BriefGate (1) creates a branded portal, (2) emails the client, (3) validates each asset as it comes in, (4) chases the client automatically until everything is submitted, and (5) notifies the agent when it's done.

The agent keeps building the layout, the booking flow, and everything else that doesn't depend on this — then calls get_intake_results(intake_id) and gets back typed data and signed URLs for the files, plus a one-time reveal of the WordPress credentials. It stores the secret and continues.

Why not a form?

Generic formBriefGate
Human creates the formAgent declares what it needs
Human reads resultsAgent consumes typed results
Generic answersTyped items
Manual follow-upAutomatic chasing
Spreadsheet mindsetAPI / MCP workflow
Credentials are awkwardSecret item + controlled reveal
Human workflowAgent workflow

BriefGate is not trying to replace every form builder. It is designed for the point where an AI agent needs information from a human.

Free tier, no card required. BriefGate is a hosted service — this repository is the open-source MCP client, MIT licensed. Sign up at briefgate.dev.

Reference

Everything below is unchanged technical detail: manual setup, environment variables, HTTP/OAuth mode, the full tool reference, webhooks, pricing, and legal.

Claude Code: manual setup and API keys

Paste an API key (for CI, scripts, or if you'd rather manage the key yourself). Get one at briefgate.dev (free tier available, no card required):

claude mcp add briefgate \
  -e BRIEFGATE_API_KEY=bg_live_... \
  -- npx -y @briefgate/mcp

Or add manually to ~/.claude/settings.json:

{
  "mcpServers": {
    "briefgate": {
      "command": "npx",
      "args": ["-y", "@briefgate/mcp"],
      "env": {
        "BRIEFGATE_API_KEY": "bg_live_..."
      }
    }
  }
}

BRIEFGATE_API_KEY (or --api-key on the command line), if set, always takes precedence over a key login stored locally — running login while one is configured just says so instead of doing anything.

Verify it loaded — run /mcp in Claude Code and look for briefgate with 15 tools.

The same local-package and API-key setup works for any MCP client that runs the package locally (Cursor, Codex, others) — register it with no key at all and run login, or paste BRIEFGATE_API_KEY into that client's own MCP config the same way.

Sign in without an API key

Two ways to get a key onto this machine without pasting one — both run the same device-authorization flow (RFC 8628) against the same credential file, so pick whichever fits how you're using the package.

From a terminal — the login / logout subcommands:

npx -y @briefgate/mcp login     # prints a code + URL, waits for approval, saves the key
npx -y @briefgate/mcp logout    # removes the local key, best-effort revokes it remotely

login blocks until you approve it (or it times out at 10 minutes), then prints Signed in as <account_name> and exits 0 — or prints why it didn't work (denied, expired, an error) and exits 1. logout always removes the local copy; it also sends DELETE /v1/keys/current using that same key to revoke it server-side, and if that call fails (no network, API unreachable) it says so and points at the BriefGate dashboard instead of leaving you unsure whether the key is still live.

From an agent — the login / logout tools (see Tools):

Same flow, for a client that can't block a terminal on your click. login is two-phase because a tool call can't sit open for minutes:

  1. The first call starts the flow and returns immediately with the code and URL. A browser is opened automatically where possible.
  2. Call login again — any time, or once you've approved it — to check progress. While it's still waiting, it says so; once approved, that same call reports success and the key is saved. No restart needed: the very next tool call is signed in.

logout as a tool does exactly what the subcommand does, including the best-effort remote revoke.

Either way, the key lands in ~/.briefgate/credentials.json (directory mode 0700, file mode 0600; override the path with BRIEFGATE_CREDENTIALS_FILE), keyed by which BriefGate server it's for so a staging BRIEFGATE_BASE_URL and production never collide. An explicit key always wins over a stored one — --api-key, then BRIEFGATE_API_KEY, then whatever login last saved — and login says so instead of running the flow when one of those is already set. Neither the subcommands nor the tools apply to the shared hosted endpoint (mcp.briefgate.dev) — see Hosted endpoint + OAuth, where connecting a client triggers real OAuth instead.

Environment variables

VariableRequiredDefaultDescription
BRIEFGATE_API_KEYNo—API key (bg_live_... or bg_test_...). Takes precedence over a credential stored by login. If nothing is configured, tool calls fail with a message pointing at login.
BRIEFGATE_BASE_URLNohttps://api.briefgate.devOverride for staging or local development.
BRIEFGATE_CREDENTIALS_FILENo~/.briefgate/credentials.jsonWhere login/logout store the key. Mainly for tests and unusual setups.
BRIEFGATE_NO_BROWSERNounsetSet to 1 to stop login from opening a browser (headless servers, CI); the URL is printed either way.
BRIEFGATE_MCP_HTTPNo—Set to 1 to start Streamable HTTP instead of stdio.
BRIEFGATE_MCP_PORTNo3000Port for HTTP mode.
BRIEFGATE_MCP_PUBLIC_HOSTNo—Publishes the server as a shared, multi-customer OAuth endpoint. See Hosted endpoint + OAuth.
BRIEFGATE_MCP_AUTH_SERVERNoBRIEFGATE_BASE_URLThe OAuth authorization server advertised to clients in published mode. Defaults to BRIEFGATE_BASE_URL for local dev, where they're usually the same address; a real deployment behind a container network sets this explicitly (see below).

--api-key bg_live_... is also accepted on the command line, ahead of BRIEFGATE_API_KEY in priority. login and logout are also accepted as the first command-line argument (npx @briefgate/mcp login), instead of --http/no flag.

HTTP (Streamable HTTP) mode

For remote or multi-session deployments, start the server in HTTP mode:

BRIEFGATE_API_KEY=bg_live_... npx @briefgate/mcp --http --port 3000

The server binds to 127.0.0.1 only and includes DNS-rebinding protection. Behind a reverse proxy, terminate TLS there and forward to the local port — do not expose the port directly.

Hosted endpoint + OAuth

Set BRIEFGATE_MCP_PUBLIC_HOST to the hostname the server is published under and it becomes a shared, multi-customer endpoint: each caller sends its own key as Authorization: Bearer bg_live_... (an OAuth access token, for this API, is that same key — see below), and the server speaks to the BriefGate API as that caller. The public instance is https://mcp.briefgate.dev/mcp.

BRIEFGATE_MCP_PUBLIC_HOST=mcp.example.com npx @briefgate/mcp --http --port 3000

Several things change, on purpose:

  • the listener binds 0.0.0.0 and the Host guard accepts that name, because a server behind a reverse proxy is reached by its public name;
  • the BRIEFGATE_API_KEY fallback and the local login credential are both switched off. Leaving either on would let an anonymous caller spend the operator's key, or read whatever the machine's own login last stored;
  • login/logout, tools and subcommands alike, are unavailable — connecting a client triggers real OAuth instead, described below;
  • the server becomes an OAuth 2.1 resource server, per the MCP authorization spec, so an OAuth-aware client can add it with nothing but the URL. This package never runs the authorization flow itself — it only advertises where to find it and enforces that a request carries a token:
    • it serves GET /.well-known/oauth-protected-resource (RFC 9728), and the same content again under /.well-known/oauth-protected-resource/mcp (the resource-scoped path the MCP spec also has clients try), both with open CORS and naming the BriefGate API as the authorization server — see BRIEFGATE_MCP_AUTH_SERVER above;
    • every MCP request now needs a Bearer token — including initialize and tools/list, which used to work without one so a registry could introspect the tool list. One with no token gets HTTP 401 and a WWW-Authenticate: Bearer resource_metadata="https://<host>/.well-known/oauth-protected-resource" header, which is the signal an OAuth client uses to start signing in;
    • if a tool call's key turns out to be expired or revoked (the API answers 401), the response is rewritten into a real HTTP 401 with the same header plus error="invalid_token", rather than an ordinary tool error — so the client knows to refresh rather than just reporting the call failed.

What a connecting client actually does, against the authorization server named in that metadata: standard OAuth 2.1 discovery (GET /.well-known/oauth-authorization-server), dynamic client registration (POST /v1/oauth/register), then an authorization-code exchange with PKCE (S256) at POST /v1/oauth/token — no client secret, since MCP clients are public clients — and POST /v1/oauth/revoke to end a session. None of that is this package's concern; it only has to be a correct resource server pointing at it. The access token that comes out the other end is a bg_live_... key like any other, with a one-hour expiry the API enforces.

None of this applies without BRIEFGATE_MCP_PUBLIC_HOST: a local --http run keeps behaving exactly as before, including an absent key reaching initialize/tools/list and a plain Authorization: Bearer ... header working with no OAuth involved.

Tools

define_intake

Create a new client intake — a branded portal where the client submits the assets you need. BriefGate sends the invite email and chases the client automatically until everything is collected.

project_name: "Website for John Finance"
client: { email: "john@example.com", name: "John", language: "cs" }
// also_notify: [{ email: "jane@example.com", name: "Jane" }]
//   Others at the client who get the same link and the same reminders — either of
//   them can supply the material. Each gets their own email; nobody sees the rest.
due_date: "2026-08-15"
branding: { accent_color: "#1B2A4A", sender_name: "Radim" }
chase_schedule: "default"   // default | gentle | aggressive | custom | off
// chase_interval: 5, chase_interval_unit: "minutes"   // only with "custom"; omit for every 3 days
// respect_quiet_hours: false, max_reminders: 12       // for a deliberately rapid cadence
items:
  - { key: "logo",       type: "image",    label: "Company logo",
      constraints: { formats: ["svg","png"], min_width: 512 } }
  - { key: "hero_copy",  type: "longtext", label: "Homepage headline",
      constraints: { max_chars: 400 } }
  - { key: "brand_colors", type: "color_list", label: "Brand colors", required: false }
  - { key: "ga4_id",    type: "text",     label: "Google Analytics ID",
      pattern: "^G-[A-Z0-9]+$", required: false }
  - { key: "wp_admin",  type: "secret",   label: "WordPress admin credentials" }
  - { key: "photos",    type: "file_list", label: "Photos (5–10 images)",
      constraints: { formats: ["jpg","png","heic"], min_count: 5, max_count: 15 } }
  - { key: "opening_hours", type: "structured", label: "Opening hours",
      schema: { type: "object", properties: { mon_fri: { type: "string" }, sat: { type: "string" } } } }
  - { key: "has_existing_site", type: "boolean", label: "Does the client have an existing website?" }
  - { key: "website_url", type: "url", label: "Current website URL", required: false }
  - { key: "service_tier", type: "select", label: "Service package",
      options: [{ value: "basic", label: "Basic" }, { value: "pro", label: "Pro" }] }
// folder_id: "fld_1"
//   Put the intake straight into an existing folder from list_folders instead
//   of leaving it unfiled.
// client_brief: "Here's the offer we agreed on, plus a few notes on scope..."
//   Free text shown to the client above the requested items — information from
//   you to them, not another thing you're asking them for. Up to 5000 characters.
//   Documents go through POST /v1/intakes/:id/brief/files (dashboard or REST,
//   not through MCP).

Item key rules: must be snake_case (e.g. logo, hero_copy, ga4_id). Keys become property names in get_intake_results — no uppercase, no spaces, no hyphens.

Returns { intake_id, portal_url, status }. Save intake_id for all follow-up calls.

get_intake_status

Check which items are submitted, pending, or need revision. Includes the history of automated chase emails and when the client last opened the portal.

intake_id: "in_8f3k"

Returns per-item status and a full chase history.

get_intake_results

Retrieve typed submitted values. Files are signed URLs (valid 24 hours). Secrets are one-time — decrypted and returned on the first call only; store them before moving on.

intake_id: "in_8f3k"
only_new: true          // only items new since last call
include_pending: false  // omit unsubmitted items

Returns { results: { logo: "https://signed...", hero_copy: "text...", wp_admin: "s3cr3t" }, meta: { ... } }.

request_revision

Ask the client to resubmit an item with a note explaining what is wrong.

intake_id: "in_8f3k"
item_key: "logo"
note: "Logo is blurry — we need at least 512 px wide in SVG or PNG with a transparent background"

Returns { status: "revision_requested", item_key }.

send_chase

Send a manual reminder outside the automatic schedule. Use when a deadline is approaching or email attempts have failed.

intake_id: "in_8f3k"

Returns { sent: true }.

list_intakes

List all intakes across projects, optionally filtered by status, client email, folder, or a text search.

status: "in_progress"   // draft | sent | in_progress | completed | archived
client_email: "john@example.com"
folder_id: "fld_1"      // or "none" for intakes not in any folder
q: "Finance"             // substring match on project name, client name, or client email
limit: 20
offset: 0

Returns { intakes: [...], total }.

add_items

Add new items to an already-sent intake — for example a favicon you forgot, or additional credentials needed mid-project.

intake_id: "in_8f3k"
items:
  - { key: "favicon", type: "image", label: "Favicon (32×32 PNG or ICO)" }

Returns the updated intake.

update_item

Change an item's definition after the intake was sent — the type, label, help text or constraints. Use this when you asked for the wrong thing, e.g. you requested an image but the client has a PDF.

intake_id: "in_8f3k"
item_key: "logo"
type: "file"                        // was "image"
constraints: { formats: ["pdf","ai","svg"] }
discard_submitted_value: false      // true is required if the change invalidates what the client already sent

Returns the updated item. If the client already submitted a value that the new definition would reject, the call fails with item_answer_would_be_discarded until you pass discard_submitted_value: true.

update_intake

Change settings on an already-sent intake — project name, due date, reminder cadence, quiet hours, the client brief, or the client's name, phone, language, and timezone. Use this instead of deleting and recreating the intake, which would re-send the invite.

Shortened here. Read the whole README on GitHub.

Signals

Last commit
Sep 2026
Weekly_downloads
167 weekly_downloads
Advanced
Delivery
briefgate MCP server → your ahel connector (mcp.ahel.ai) → your AI.
Item type
mcp-server
Key
io-github-sekera-radim-briefgate
Source
github.com/sekera-radim/briefgate-mcp
Hosted endpoint
https://mcp.briefgate.dev/mcp