MCP Tools Reference

BriefGate ships as an MCP server so coding agents can orchestrate client intake without leaving their context. All 13 tools map 1:1 to REST endpoints under https://api.briefgate.dev/v1/. Connect it without pasting a key — hosted OAuth or local device login — or with an API key for CI and scripts; see quickstart.md for all four options. login and logout are two additional local-only helpers available when you run the package via npx — see below.


When should an agent use BriefGate

Triggers. Reach for these tools when a task is blocked on something only a human outside the current conversation can provide: files (logo, product photos, documents), copy, brand assets, structured answers, or credentials/logins — and that person may take hours or days to respond, so something needs to chase them on a schedule instead of you polling by hand.

When not to. Skip it when the information is already available — in the repo, earlier in the conversation, or in an earlier BriefGate intake — or when the person you're talking to right now can just answer directly. BriefGate's portal and reminders are built for people who are not in this conversation.

Flow.

  1. Call define_intake with the typed items you need (see the item types table linked from each tool below).
  2. Poll get_intake_status. An item staying pending, or the intake staying sent or in_progress, is the normal state while BriefGate chases the client on the configured schedule — it is not an error or a sign the call failed. Use follow_up on the define_intake response, or a registered webhook, instead of tight polling.
  3. Once items are submitted, call get_intake_results to get typed values back. Its missing array names anything still outstanding — check it before assuming the intake is done.
  4. If a submitted value is wrong or incomplete, call request_revision with a note explaining what to fix, instead of asking the client again yourself outside BriefGate.
  5. secret items (passwords, API keys) come back through get_intake_results once: the plaintext value is present only on the first successful read (first_reveal: true) and absent on every call after. Store it immediately. Secrets are encrypted server-side on arrival (libsodium sealed box) — not end-to-end, not zero-knowledge — see security.md.

define_intake

Creates a new intake and immediately sends the client an email with their portal link.

Parameters

Parameter Type Required Description
project_name string Yes Human-readable project title shown in the portal and all emails.
client.email string Yes Client's email address.
client.name string Yes Client's display name. Every invite and reminder email opens by addressing the client by name.
client.language string No Portal and email language: cs, sk, pl, de, es, en. Omit it and the account's default language applies, falling back to English.
client.timezone string No IANA timezone (e.g. Europe/Prague) used for quiet-hours scheduling.
client.phone string No E.164 phone number (e.g. +420601123456).
client.also_notify array No Up to 4 extra { email, name } people who get the same portal link and reminders as the primary client (e.g. two directors of one company). Each gets their own email; nobody sees the rest.
email_copy object No Your own invite_subject, invite_intro, reminder_subject, reminder_intro, overriding the built-in translation for this intake. Placeholders: {sender}, {project}, {client}, {count}, {minutes}, {due} — an unknown one is rejected, not rendered literally.
items array Yes Ordered list of item definitions. See item-types.md.
items[].assignee string No client (default) or owner. An owner item is your own to-do — invisible to the client, never chased, and it never holds the intake open. See item-types.md.
branding object No Per-intake override of account branding: logo_url, accent_color (hex, e.g. #1B2A4A), sender_name, reply_to.
template string No Template slug to pre-populate items (e.g. "restaurant-website").
chase_schedule string No One of default, gentle, aggressive, custom, off (default: default). default=T+2d,T+5d,T+9d,weekly. gentle=T+3d,T+8d,biweekly. aggressive=T+1d,T+3d,T+5d,every-other-day. custom=every chase_interval chase_interval_unit. off=no auto reminders.
chase_interval integer No Reminder interval for chase_schedule: "custom". Omit it and custom reminds every 3 days. Rejected with any other schedule.
chase_interval_unit string No minutes, hours or days (default days). Minimum 5 minutes, maximum 90 days.
respect_quiet_hours boolean No Keep reminders inside the client's 08:00–19:00 window (default true).
max_reminders integer | string No Reminders before the intake stalls and hands back to you (1–1000, default 3, or "unlimited" to remove the cap).
chase_at_time string No Local time of day for the reminder, HH:MM. Requires chase_schedule: "custom" with a whole-day interval, and outranks quiet hours.
due_date string No ISO 8601 date. Shown in the portal and email subject.
auto_approve_hours integer No Hours after submission before an item is auto-approved without your review (default 72). Set to 0 to require explicit approval.
send boolean No Set to false to create a draft without emailing the client. Call POST /v1/intakes/:id/send to send later. Default: true.
retention object No { mode: "days"|"on_delivery", days?: number, anonymize?: boolean }. Default: purge 90 days after intake.completed. Use mode: "on_delivery" for intakes containing credentials — contents are removed ~24 h after you call get_intake_results.
folder_id string No Put this intake in an existing folder from list_folders instead of leaving it unfiled. Folders group intakes by client or project — reuse one for a returning client rather than creating a duplicate with create_folder.

Example — restaurant website project

json
{
  "project_name": "Bella Napoli — Website",
  "client": {
    "email": "owner@bellanapoli.com",
    "name": "Marco Esposito",
    "language": "en"
  },
  "items": [
    {
      "key": "logo",
      "label": "Restaurant logo",
      "help": "SVG or PNG with transparent background, minimum 512px.",
      "type": "image",
      "required": true,
      "constraints": {
        "formats": ["svg", "png"],
        "min_width": 512,
        "transparent_background": true
      }
    },
    {
      "key": "brand_colors",
      "label": "Brand colors",
      "help": "Pick the primary and secondary brand colors.",
      "type": "color_list",
      "required": true
    },
    {
      "key": "hero_copy",
      "label": "Hero tagline",
      "type": "longtext",
      "required": true,
      "constraints": { "max_chars": 400 }
    },
    {
      "key": "has_existing_site",
      "label": "Do you have an existing website?",
      "type": "boolean",
      "required": true
    },
    {
      "key": "existing_site_url",
      "label": "Existing website URL",
      "help": "Only required if you answered Yes above.",
      "type": "url",
      "required": false
    },
    {
      "key": "platform",
      "label": "Preferred platform",
      "type": "select",
      "required": true,
      "options": [
        { "value": "wordpress", "label": "WordPress" },
        { "value": "webflow",   "label": "Webflow" },
        { "value": "custom",    "label": "Custom / I'm not sure" }
      ]
    },
    {
      "key": "cms_password",
      "label": "Admin credentials",
      "help": "Existing CMS admin login (if migrating). Stored encrypted, one-time reveal.",
      "type": "secret",
      "required": false
    },
    {
      "key": "opening_hours",
      "label": "Opening hours",
      "type": "structured",
      "required": true,
      "schema": {
        "type": "object",
        "required": ["mon_fri", "sat", "sun"],
        "properties": {
          "mon_fri": { "type": "string" },
          "sat":     { "type": "string" },
          "sun":     { "type": "string" }
        }
      }
    }
  ],
  "chase_schedule": "default"
}

Response

json
{
  "intake_id": "in_8f3kQmR2",
  "portal_url": "https://p.briefgate.dev/8f3kqmr2",
  "status": "sent",
  "items": [
    { "key": "logo",       "status": "pending" },
    { "key": "brand_colors","status": "pending" }
  ],
  "follow_up": {
    "recommended": "schedule",
    "reason": "No active webhook endpoints are registered on this account.",
    "webhook": {
      "active_endpoints": 0,
      "events": ["item.submitted", "intake.completed"],
      "register_with": "manage_webhook"
    },
    "schedule": {
      "check_with": "get_intake_status",
      "every_hours": 24,
      "until": "2024-03-29T10:22:00Z"
    }
  }
}

follow_up tells you how to learn about progress on this intake without polling blindly. recommended is "webhook" when you already have an active webhook endpoint covering the relevant events, or "schedule" — as above — when you don't. On "schedule", poll get_intake_status every follow_up.schedule.every_hours hours until follow_up.schedule.until; on "webhook", register one with manage_webhook (or rely on the endpoints already listed under follow_up.webhook) instead of polling.


get_intake_status

Returns a lightweight snapshot of the intake's current state: which items are complete, which are pending, and the full chase history. Prefer this over get_intake_results when you only need to check progress.

progress.total counts what the intake is waiting on: an item the owner has waived, and an optional item the client has not touched, both leave the denominator. That keeps percent at 100 exactly when status turns completed.

Parameters

Parameter Type Required Description
intake_id string Yes The intake_id returned by define_intake.

Response

json
{
  "status": "in_progress",
  "due_date": "2024-04-01",
  "client_last_seen": "2024-03-16T14:05:33Z",
  "progress": {
    "submitted": 5,
    "total": 8,
    "outstanding": 3,
    "percent": 62
  },
  "items": [
    { "key": "logo",             "status": "approved",       "submitted_at": "2024-03-16T10:00:00Z", "label": "Restaurant logo" },
    { "key": "brand_colors",     "status": "approved",       "submitted_at": "2024-03-16T10:05:00Z", "label": "Brand colors" },
    { "key": "hero_copy",        "status": "needs_revision", "submitted_at": "2024-03-16T10:10:00Z", "label": "Hero tagline" },
    { "key": "has_existing_site","status": "approved",       "submitted_at": "2024-03-16T10:15:00Z", "label": "Do you have an existing website?" },
    { "key": "existing_site_url","status": "approved",       "submitted_at": "2024-03-16T10:15:00Z", "label": "Existing website URL" },
    { "key": "platform",         "status": "approved",       "submitted_at": "2024-03-16T10:20:00Z", "label": "Preferred platform" },
    { "key": "cms_password",     "status": "pending",        "submitted_at": null,                   "label": "Admin credentials" },
    { "key": "opening_hours",    "status": "pending",        "submitted_at": null,                   "label": "Opening hours" }
  ],
  "chases": [
    { "channel": "email", "sent_at": "2024-03-17T09:00:00Z", "status": "sent",      "attempt_no": 1 },
    { "channel": "email", "sent_at": "2024-03-20T09:00:00Z", "status": "sent",      "attempt_no": 2 },
    { "channel": "email", "sent_at": null,                   "status": "scheduled", "attempt_no": 3 }
  ]
}

Item statuses

Status Meaning
pending Not yet submitted by client.
submitted Uploaded or filled in; awaiting agent review or auto-approval.
needs_revision Agent requested a revision via request_revision.
approved Accepted (explicitly or via 72-hour auto-approval).
waived The owner waived the item — it will never be submitted and does not count toward progress.total.

get_intake_results

Returns the typed content of all approved (or all submitted) items. Use this once the intake is complete, or incrementally as items are approved using only_new: true.

Parameters

Parameter Type Required Description
intake_id string Yes The intake to retrieve results from.
only_new boolean No If true, returns only items approved since the last call. Useful for streaming incremental processing.
include_pending boolean No If true, also returns items that are submitted but not yet approved.

Response

json
{
  "intake_id": "in_8f3kQmR2",
  "status": "completed",
  "progress": { "submitted": 8, "total": 8, "outstanding": 0, "percent": 100 },
  "missing": [],
  "results": {
    "logo": {
      "url": "https://files.briefgate.dev/in_8f3kQmR2/logo.png?token=sig_abc&expires=1710615600",
      "filename": "bella-napoli-logo.png",
      "mime": "image/png",
      "width": 1024,
      "height": 512,
      "size": 48210,
      "checksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8"
    },
    "brand_colors": ["#1B2A4A", "#E8E2D9", "#C8382E"],
    "hero_copy": "Since 1987, handcrafted Neapolitan pizza in the heart of the city. Come hungry, leave happy.",
    "has_existing_site": true,
    "existing_site_url": "https://old.bellanapoli.com",
    "platform": "wordpress",
    "cms_password": {
      "value": "admin:s3cr3tP@ssw0rd",
      "one_time": true,
      "first_reveal": true,
      "expires_at": "2024-04-15T10:22:00Z"
    },
    "opening_hours": {
      "mon_fri": "12:00-22:00",
      "sat": "12:00-23:00",
      "sun": "13:00-21:00"
    }
  },
  "meta": {
    "logo": { "type": "image", "status": "approved", "submitted_at": "2024-03-16T10:00:00Z" },
    "cms_password": { "type": "secret", "status": "approved", "submitted_at": "2024-03-16T10:15:00Z" }
  }
}

missing lists the keys of required client items still pending or needs_revision — useful to check before assuming the intake is complete. meta carries one entry per item returned in results: its type, status, submitted_at, and (for a decision item) decided_by.

Notes on specific types:


request_revision

Marks an item as needs_revision and sends the client an email notification explaining what needs to be fixed. The item returns to pending on the client's side, and the cycle restarts.

Parameters

Parameter Type Required Description
intake_id string Yes The intake containing the item.
item_key string Yes The key of the item to revise (e.g. "logo").
note string Yes Human-readable explanation sent to the client. Be specific.

Example

json
{
  "intake_id": "in_8f3kQmR2",
  "item_key": "logo",
  "note": "The logo appears to be exported at 320px. Please re-export at a minimum of 512px on the shortest side, ideally as an SVG vector file."
}

Response

json
{
  "intake_id": "in_8f3kQmR2",
  "item_key": "logo",
  "status": "needs_revision",
  "client_notified": true
}

The client receives an email with your note. Their portal highlights the flagged item. When they resubmit, the item transitions back to submitted and the 72-hour auto-approval timer resets.


send_chase

Manually triggers a chase message outside the automatic schedule. Use this to send a personal nudge before a deadline.

Parameters

Parameter Type Required Description
intake_id string Yes The intake to chase.
channel string No "email". Defaults to "email".

Example

json
{
  "intake_id": "in_8f3kQmR2",
  "channel": "email"
}

Response

json
{
  "intake_id": "in_8f3kQmR2",
  "channel": "email",
  "sent_at": "2024-03-22T08:15:00Z"
}

When to use this tool


list_intakes

Returns a paginated list of intakes, optionally filtered by status or client email. Useful for building dashboards or checking which projects need attention.

Parameters

Parameter Type Required Description
status string No Filter by intake status: draft, sent, in_progress, completed, archived.
client_email string No Filter to intakes belonging to a specific client.
folder_id string No Filter by folder, using an id from list_folders. Pass the literal string "none" to see only intakes that are not in any folder.
q string No Free-text search: matches a substring of project name, client name, or client email.
limit integer No Number of results per page (default 20, max 100).
offset integer No Pagination offset (default 0).

Response

json
{
  "intakes": [
    {
      "intake_id": "in_8f3kQmR2",
      "project_name": "Bella Napoli — Website",
      "status": "in_progress",
      "client": {
        "email": "owner@bellanapoli.com",
        "name": "Marco Esposito"
      },
      "portal_url": "https://p.briefgate.dev/8f3kqmr2",
      "created_at": "2024-03-15T10:22:00Z",
      "progress": { "submitted": 3, "total": 7 }
    },
    {
      "intake_id": "in_4p2nWxY7",
      "project_name": "Green Leaf Cafe — Rebrand",
      "status": "completed",
      "client": {
        "email": "ops@greenleafcafe.com",
        "name": "Priya Nair"
      },
      "portal_url": "https://p.briefgate.dev/4p2nwxy7",
      "created_at": "2024-03-10T09:00:00Z",
      "progress": { "submitted": 5, "total": 5 }
    }
  ],
  "total": 47,
  "limit": 20,
  "offset": 0
}

Each intake in the array uses the same snake_case field shape as the single-intake object described elsewhere in these docs, plus a per-intake progress summary showing how many items have been submitted out of the total.


add_items

Appends new items to an existing intake that has already been sent. The client receives a notification that new items have been added. Use this when scope expands after the initial intake is live.

Parameters

Parameter Type Required Description
intake_id string Yes The intake to extend.
items array Yes Array of item definitions in the same format used in define_intake.

Example — adding a favicon request after the initial intake was sent

json
{
  "intake_id": "in_8f3kQmR2",
  "items": [
    {
      "key": "favicon",
      "label": "Favicon",
      "help": "A square icon at least 32x32px, ideally 512x512px. Used in browser tabs and bookmarks.",
      "type": "image",
      "required": true,
      "constraints": {
        "formats": ["png", "svg"],
        "min_width": 32,
        "min_height": 32
      }
    }
  ]
}

Response

json
{
  "intake_id": "in_8f3kQmR2",
  "items_added": [
    { "key": "favicon", "status": "pending" }
  ]
}

The client's portal immediately shows the new item.


update_item

Changes the definition of an existing item on an intake — for example, tightening a constraint, editing the label or help text, or making an item required after the fact. The item's key cannot be changed; if you need a different key, use add_items to add a new item and leave the old one in place or discard it.

Parameters

Parameter Type Required Description
intake_id string Yes The intake containing the item.
item_key string Yes The key of the item to update.
type string No New item type. See item-types.md.
label string No New label shown to the client.
help string No New help text.
required boolean No Whether the item is required.
constraints object No New constraints object, replacing the previous one.
options array No New {value, label} options array, for select/multiselect items.
pattern string No New regular expression, for text items.
discard_submitted_value boolean No See "Conflicts with an existing answer" below. Default false.

At least one field besides intake_id and item_key must be given. Neither schema nor owner_note can be set through this tool — the call is rejected if you pass either. assignee also cannot be changed by this tool — remove and re-add the item with add_items if it needs to move between client and owner.

Example — widening an image constraint after the client complained

json
{
  "intake_id": "in_8f3kQmR2",
  "item_key": "logo",
  "constraints": {
    "formats": ["svg", "png", "jpg"],
    "min_width": 256
  }
}

Response

json
{
  "item": {
    "key": "logo",
    "type": "image",
    "assignee": "client",
    "label": "Restaurant logo",
    "help": "SVG or PNG with transparent background, minimum 512px.",
    "required": true,
    "status": "pending",
    "value": null,
    "constraints": {
      "formats": ["svg", "png", "jpg"],
      "min_width": 256
    },
    "options": null,
    "pattern": null,
    "submitted_at": null,
    "approved_at": null,
    "revision_note": null,
    "revision_count": 0,
    "waiver": null,
    "client_note": null,
    "owner_note": null
  }
}

Conflicts with an existing answer

If the client has already submitted a value for the item, and your change would invalidate that value under the new definition (e.g. narrowing max_chars below the submitted text's length, or removing an option the client already selected), the call fails with 409 and error code item_answer_would_be_discarded instead of silently dropping the client's answer:

json
{
  "error": {
    "code": "item_answer_would_be_discarded",
    "message": "Changing constraints on \"logo\" would invalidate the client's submitted value."
  }
}

Pass discard_submitted_value: true to proceed anyway. In that case the item resets to pending and the response includes "discarded_submitted_value": true alongside item.


update_intake

Edits an intake that is already sent — the alternative used to be deleting it and calling define_intake again, which re-sends the invitation and hands the client a second link. Works on an intake in any status except archived; changing the chase cadence on a sent or in_progress intake re-plans the schedule from now, cancelling whatever reminder was still pending under the old settings. The client's e-mail address cannot be changed with this tool — it is what the portal link and magic token are bound to. Use manage_recipients to add, remove, or reinstate an address instead.

Parameters

Parameter Type Required Description
intake_id string Yes The intake to edit.
project_name string No
due_date string | null No YYYY-MM-DD. null clears it.
chase_schedule string No default, gentle, aggressive, custom, off.
chase_interval integer No Only meaningful with chase_schedule: "custom". Pair with chase_interval_unit.
chase_interval_unit string No minutes, hours, or days (default days).
chase_at_time string | null No HH:MM local time. Needs an interval measured in whole days. null clears it.
max_reminders integer | "unlimited" No Raising this past the number of reminders already sent un-stalls an intake that had run out and resumes chasing.
respect_quiet_hours boolean No
client.name string No
client.phone string | null No E.164, e.g. +420601123456. null clears it.
client.language string No cs, sk, pl, de, es, en.
client.timezone string No IANA timezone, e.g. Europe/Prague. Feeds respect_quiet_hours and chase_at_time — changing it also re-plans the schedule.
folder_id string | null No Move this intake to a different folder, using an id from list_folders. null removes it from any folder. It never touches the chase schedule.

No client.email — see above. At least one field besides intake_id is required. Omitting a field leaves it untouched; null is only accepted where the table above says so.

Example — switching a stalled intake to a faster, uncapped cadence

json
{
  "intake_id": "in_8f3kQmR2",
  "chase_schedule": "custom",
  "chase_interval": 6,
  "chase_interval_unit": "hours",
  "max_reminders": "unlimited"
}

Example — correcting the client's name and timezone

json
{
  "intake_id": "in_8f3kQmR2",
  "client": {
    "name": "Marco Esposito",
    "timezone": "Europe/Rome"
  }
}

Response is { "intake": { ... } }, the same object get_intake_status's sibling read tools return.

Errors

Code Meaning
intake_archived (409) The intake is archived and cannot be edited.
400 No field besides intake_id was given.
422 A field's value is invalid — e.g. chase_at_time against an interval that isn't a whole number of days.

manage_recipients

Adds, removes, or reinstates one of the people an intake is addressed to. An intake can have up to five recipients sharing one portal link — a primary client plus four others (two directors of the same company, for instance). Wraps POST/DELETE /v1/intakes/:id/recipients and the reinstate endpoint; see rest-api.md for the underlying REST contract.

Parameters

Parameter Type Required Description
intake_id string Yes
action string Yes add, remove, or reinstate.
email string Yes The address to add, remove, or reinstate.
name string No Only used with action: "add".

add — includes the address in the same portal link and future reminders as the primary client. Sends nothing by itself; use send_chase to reach the new person immediately.

remove — drops an additional address. The primary client cannot be removed this way — use update_intake to change other fields, or define_intake to start over.

reinstate — for a bounce that was wrong: the person did get the e-mail, or the mailbox has since been fixed. Clears the bounce flag on an address that a delivery failure had silenced. If nobody was left to chase before this call, automatic reminders resume.

Example

json
{
  "intake_id": "in_8f3kQmR2",
  "action": "reinstate",
  "email": "owner@bellanapoli.com"
}

Response

json
{
  "email": "owner@bellanapoli.com",
  "bounced_at": null,
  "still_chasing": true
}

(add and remove return the shapes documented for their underlying REST endpoints instead — also_notify for add, an empty body for remove.)

Errors

Code Meaning
recipient_exists (409) add: that address is already on the intake.
400 (recipient_limit) add: the intake already has five recipients.
recipient_is_primary (400) remove: that address is the primary client.
404 remove/reinstate: no such recipient on the intake.
recipient_not_bounced (409) reinstate: that address has never bounced.

manage_webhook

Creates, lists, or deletes webhook endpoints for your account. Webhooks let you react to intake events (an item submitted, an intake completed, a reminder bouncing, and so on) without polling. See webhooks.md for delivery, signature verification, and retry behavior.

Parameters

Parameter Type Required Description
action string Yes "create", "list", or "delete".
url string For create HTTPS endpoint that receives the webhook POSTs.
events array For create Subset of item.submitted, intake.completed, client.viewed, chase.bounced, intake.stalled, intake.overdue.
format string No "raw" (default, signed BriefGate envelope), "slack", or "discord".
webhook_id string For delete The endpoint to remove.

url and events are both required for action: "create".

Example — registering an endpoint

json
{
  "action": "create",
  "url": "https://yourapp.com/webhooks/briefgate",
  "events": ["item.submitted", "intake.completed", "intake.stalled"]
}

Response (create)

json
{
  "id": "whe_a1b2c3d4e5f6",
  "url": "https://yourapp.com/webhooks/briefgate",
  "events": ["item.submitted", "intake.completed", "intake.stalled"],
  "format": "raw",
  "active": true,
  "created_at": "2024-03-22T08:15:00Z",
  "secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

secret is shown exactly once, at creation — store it immediately, since you need it to verify signatures and it is never returned again (including by action: "list").

Response (list)

json
{
  "webhooks": [
    {
      "id": "whe_a1b2c3d4e5f6",
      "url": "https://yourapp.com/webhooks/briefgate",
      "events": ["item.submitted", "intake.completed", "intake.stalled"],
      "format": "raw",
      "active": true,
      "created_at": "2024-03-22T08:15:00Z"
    }
  ]
}

url is masked in the list response for slack/discord format endpoints, and shown in full for raw format.

Response (delete)

action: "delete" returns no body (204 No Content at the REST layer).


list_folders

Lists the folders in your account, used to group intakes by client or project. Call this before create_folder or before setting folder_id on define_intake, update_intake, or list_intakes — reuse an existing folder for a returning client instead of creating a duplicate.

Parameters

None.

Response

json
{
  "folders": [
    {
      "id": "fld_a1b2c3d4",
      "name": "Bella Napoli",
      "sort_order": 0,
      "intake_count": 3,
      "created_at": "2024-03-10T09:00:00Z"
    }
  ]
}

create_folder

Creates a new folder to group intakes, e.g. one per client. Call list_folders first and reuse a matching folder — only create one when none of the existing folders fits.

Parameters

Parameter Type Required Description
name string Yes Folder name, e.g. the client's or project's name. Must be unique in your account.

Response

json
{
  "id": "fld_a1b2c3d4",
  "name": "Bella Napoli",
  "sort_order": 0,
  "intake_count": 0,
  "created_at": "2024-03-22T08:15:00Z"
}

Errors

Code Meaning
folder_exists (409) A folder with this name already exists — use list_folders to find it instead.

login

Signs in without pasting an API key — the local-package equivalent of Option 1 in quickstart.md. Not available when connected through the hosted endpoint (mcp.briefgate.dev); there, connecting the client already triggers OAuth. Takes no arguments.

This is a two-phase tool because approval can take minutes, longer than a single tool call should block for:

  1. The first call starts a device-authorization flow and returns immediately with a short code and a URL. Tell the client's user to open the URL and approve the code; a browser is also opened automatically where possible.
  2. Call login again — any time, or once the user says they've approved it — to check progress. While it's still waiting, the response says so; once approved, that same call reports success and the key is saved to ~/.briefgate/credentials.json. No restart needed — the very next tool call is signed in.

Has no effect, and says so instead of running the flow, if an API key is already configured via --api-key or BRIEFGATE_API_KEY — those always take priority over a locally stored one.

Parameters: none.


logout

Removes the API key login stored locally for this BriefGate server, and best-effort revokes it on the server too (a DELETE /v1/keys/current call using that same key). Not available when connected through the hosted endpoint. Takes no arguments.

If the revoke call fails (no network, API unreachable), the local copy is still removed; the response says so and points at the BriefGate dashboard to revoke it there instead.

Parameters: none.


Idempotency

Network errors can cause define_intake to be called twice, which would send the client two emails and create two intakes. The MCP package automatically derives a stable idempotency key from the project_name, client.email, and a hash of the items array — retrying with identical arguments returns the original response without creating a second intake.

When calling the REST API directly, pass an Idempotency-Key header:

bash
curl -X POST https://api.briefgate.dev/v1/intakes \
  -H "Authorization: Bearer bg_live_xxxxx" \
  -H "Idempotency-Key: bella-napoli-2024-01" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

If the key was seen before, BriefGate returns the original response unchanged (HTTP 200, not 201). Keys expire after 24 hours.


Trying it without emailing a client

Pass "send": false to define_intake to create the intake as a draft without emailing the client — see the send parameter above. Nothing goes out until you call POST /v1/intakes/:id/send over REST; there is no MCP tool for sending a draft later. While it's still a draft, GET /v1/intakes/preview shows the exact subject line and sender name the client will get, using the account's current branding — it's session-only, so check it from the dashboard rather than from the agent.


Tool call example in Claude Code

When Claude Code invokes a BriefGate tool, the underlying MCP call looks like this:

json
{
  "type": "tool_use",
  "id": "toolu_01XyzAbc",
  "name": "mcp__briefgate__define_intake",
  "input": {
    "project_name": "Bella Napoli — Website",
    "client": {
      "email": "owner@bellanapoli.com",
      "name": "Marco Esposito",
      "language": "en"
    },
    "items": [
      {
        "key": "logo",
        "label": "Restaurant logo",
        "type": "image",
        "required": true,
        "constraints": {
          "formats": ["svg", "png"],
          "min_width": 512
        }
      }
    ],
    "chase_schedule": "default"
  }
}

The tool name is prefixed with mcp__ and the MCP server name (mcp__briefgate__). Claude Code handles the JSON serialization and transport automatically — you just describe what you need in natural language and the agent constructs the call.