Client Intake for Cursor Agents: Collect Assets Without Leaving the Editor
BriefGate MCP lets a Cursor agent collect a client's logo, copy, and credentials through a tracked portal instead of stalling mid-build.
The problem
Cursor's agent can scaffold and build most of a client website in one session, then stall on the same thing every time: the logo, the homepage copy, or the client's hosting login are missing, and nobody in the chat can produce them. You can ask the agent to pause and remind you to email the client, but the reminder just sits in a chat transcript nobody reopens. Two weeks later the project has stalled because the client never sent the photos, with no record of when you asked or whether you asked twice.
The bottleneck is not the coding. It is the gap between "I need this from the client" and having it in a usable, typed form inside the same session where you are building.
The solution
BriefGate MCP closes that gap. Cursor's agent calls define_intake() with a list of typed items — a logo, hero copy, an opening-hours schedule, a WordPress login. BriefGate emails the client a branded portal link, validates what they submit in real time, and chases them automatically on a schedule you choose. When the client is done, the agent calls get_intake_results() and gets typed data and signed file URLs back — no parsing, no re-asking, no guessing whether "the logo" means the 200px JPEG from three emails ago.
Setting up BriefGate MCP in Cursor
Cursor reads MCP server configuration from mcp.json — either .cursor/mcp.json in a project (shared with a team when checked into the repo) or ~/.cursor/mcp.json globally. Both use the same mcpServers object. You can add BriefGate two ways.
Option A — hosted endpoint with OAuth (fewest moving parts)
Add the hosted Streamable HTTP endpoint with no key at all:
{
"mcpServers": {
"briefgate": {
"url": "https://mcp.briefgate.dev/mcp"
}
}
}Open Cursor's Settings → Tools & Integrations, find the briefgate entry, and click Needs login. Cursor opens your browser to the BriefGate dashboard to sign in and approve access, then stores the resulting credentials — nothing else to paste into the config file.
Option B — local package with an API key (for CI, or if you'd rather not do a browser redirect)
{
"mcpServers": {
"briefgate": {
"command": "npx",
"args": ["-y", "@briefgate/mcp"],
"env": {
"BRIEFGATE_API_KEY": "bg_live_xxxxx"
}
}
}
}Get the key from https://app.briefgate.dev/app, then restart Cursor after editing mcp.json. Both options expose the same 13 tools: define_intake, add_items, update_item, update_intake, list_intakes, get_intake_status, get_intake_results, request_revision, send_chase, manage_recipients, manage_webhook, list_folders, and create_folder.
Telling the agent when to use it
Cursor rules work the same way CLAUDE.md does for Claude Code — add a project rule (.cursor/rules/briefgate.mdc, or a plain note in your existing rules file) so the agent reaches for BriefGate instead of asking in chat:
When you need an asset, credential, or piece of copy from the client:
1. Call define_intake with items[] describing exactly what is needed
2. The client is emailed a portal link automatically — do not email them yourself
3. Continue with other work; check get_intake_status or wait for the
intake.completed webhook rather than blocking on a reply
4. Call get_intake_results to retrieve typed data and file URLs
5. Use type: "secret" for any password, API key, or login — never ask for
credentials directly in chat or a commit messageA worked example
Agent: "The site structure is in place. Before I can finish the booking page I need the current menu, access to Google Business Profile, and the API key for the reservation widget. Creating a BriefGate intake."
The agent calls define_intake:
{
"project_name": "Karlin Noodle Bar — Website Refresh",
"client": {
"email": "[email protected]",
"name": "Petra",
"language": "en"
},
"items": [
{"key": "menu_pdf", "type": "file", "label": "Current menu (PDF)", "required": true, "constraints": {"formats": ["pdf"]}},
{"key": "gbp_access", "type": "secret", "label": "Google Business Profile login", "required": true},
{"key": "reservation_widget_key", "type": "secret", "label": "Reservation widget API key", "required": true}
],
"chase_schedule": "default"
}BriefGate returns an intake_id and a portal_url, and emails Petra right away. See item types for the full list of constraints each type accepts, and the MCP tools reference for every field define_intake takes.
Agent: "Intake sent. Petra will get an email at [email protected]. I'll continue building the booking page layout with placeholder content and pick this up once these three items are in."
While the client fills the portal
The agent does not have to wait idle. It keeps working on whatever does not depend on the missing items — layout, navigation, placeholder sections. BriefGate's chase engine sends reminder emails on the schedule you set (default is T+2d, T+5d, T+9d, then weekly), so nobody has to remember to follow up. A registered manage_webhook endpoint reports intake.completed the moment the client finishes; otherwise get_intake_status checks progress cheaply.
Resuming across Cursor sessions
Cursor work is usually split across many short sessions, not one long-running conversation — close the editor, come back tomorrow, maybe on another machine. The next session has no memory of an intake created earlier unless something outside the chat records it, so note the intake_id in a comment near the code that depends on it:
// BriefGate intake in_8f3kQmR2 — menu PDF, GBP login, reservation widget keyBefore assuming nothing has arrived — or worse, calling define_intake again and sending Petra a second portal link — a new session checks status first with get_intake_status(intake_id: "in_8f3kQmR2"). If the intake_id itself got lost, list_intakes(client_email: "[email protected]") finds the same intake by the client's address instead.
Resuming with the results
Once the portal shows everything submitted, the agent calls get_intake_results:
{
"status": "completed",
"results": {
"menu_pdf": {
"url": "https://files.briefgate.dev/in_8f3kQmR2/menu_pdf.pdf?token=...",
"filename": "karlin-noodle-bar-menu.pdf",
"mime": "application/pdf"
},
"gbp_access": {"value": "[email protected]:MyPassword123", "first_reveal": true},
"reservation_widget_key": {"value": "rw_live_9f2kQmR2xY", "first_reveal": true}
}
}Agent: "Menu, Google Business Profile login, and the reservation widget key are in. Storing both credentials in the project's secrets manager, then wiring the widget into the booking page and linking the menu PDF from the homepage."
Handling credentials
For gbp_access and reservation_widget_key above, type: "secret" is what makes them safe to move this way instead of text. The value travels to BriefGate over HTTPS and is sealed there — on BriefGate's server, not in the client's browser or by the agent — with a libsodium sealed box before it is ever written to the database. The agent does not decrypt anything itself: BriefGate's server returns the plaintext exactly once, on first reveal, through get_intake_results. See Secrets for the one-time-reveal mechanics, and how to ask for client logins securely if the agent only has a rough sense of what a project needs.
Requesting a fix
If the returned menu file turns out to be a blurry phone photo of the printed menu, not an actual export, the agent does not need a new email thread:
request_revision(
intake_id: "in_8f3kQmR2",
item_key: "menu_pdf",
note: "The menu came through as a photo of the printed page and it's too blurry to typeset. Could you export a proper PDF from whatever tool you used to make it, or a flat, straight-on scan?"
)The client sees the note on the flagged item in their portal, re-uploads, and the agent's next get_intake_results call picks up the corrected file — all inside the same tracked intake, with no separate email to lose track of.