Client Intake for Claude Code: Collect Assets Without Leaving Your Agent
The problem
Claude Code can build a complete website in an afternoon. Then it hits a wall: the client has not sent the logo, hero text, or their WordPress admin credentials. The agent waits. You wait. You send a follow-up email. Two weeks pass. The client sends a blurry JPG that is 200px wide.
This is the bottleneck: not the building, but the gathering. Developers lose more time chasing assets than writing code.
The solution
BriefGate MCP. Claude Code calls define_intake() with a list of what it needs. BriefGate emails the client a branded portal link. The client uploads files, fills in text, and submits credentials — all in a clean web interface designed for non-technical people. BriefGate chases them automatically on the schedule you set.
When everything is in, Claude Code calls get_intake_results() and picks up exactly where it left off — typed data, signed file URLs, structured objects, one-time credential tokens — ready to use without any parsing or transformation.
Setup
Three commands:
npm install -g @briefgate/mcp
claude mcp add briefgate -- briefgate-mcp --api-key bg_live_xxxxxGet your API key at https://app.briefgate.dev. The MCP server connects Claude Code to BriefGate's API. After setup, tools like define_intake, get_intake_results, get_intake_status, request_revision, and send_chase are available to Claude Code in every session.
Adding to CLAUDE.md
Put this snippet in your project's CLAUDE.md so the agent knows when and how to use BriefGate:
## Client asset collection
Use the briefgate MCP tools when you need assets from the client:
1. Call define_intake with items[] listing what you need
2. The client will be emailed a portal link automatically
3. Check status with get_intake_status or wait for the intake.completed webhook
4. Call get_intake_results to retrieve typed data and file URLs
5. For credentials (passwords, API keys), use type: "secret" — they are encrypted
Never ask the client directly for assets in conversation — use define_intake so
everything is tracked and chased automatically.A complete session example
Here is what a Claude Code session looks like with BriefGate in place:
Agent: "I have the site architecture ready. To continue building, I need the client's logo, hero copy, and Google Analytics ID. Let me create a BriefGate intake now."
Agent calls define_intake:
{
"project_name": "Bella Cucina Restaurant Website",
"client": {
"email": "[email protected]",
"name": "Marco",
"language": "en"
},
"items": [
{"key": "logo", "type": "image", "label": "Restaurant logo", "constraints": {"min_width": 512}},
{"key": "hero_copy", "type": "longtext", "label": "Homepage headline and intro text"},
{"key": "ga4_id", "type": "text", "label": "Google Analytics 4 Measurement ID", "required": false, "pattern": "^G-[A-Z0-9]+$"}
],
"chase_schedule": "default",
"branding": {"sender_name": "Radim"}
}Agent: "Intake created. Marco will receive an email at [email protected] with a portal link. I will continue building the static structure and placeholder components. I will check back when assets arrive."
[Agent continues building. Chase engine sends a reminder at T+2d. Marco submits the logo and copy at T+3d. The intake.completed webhook fires.]
Agent calls get_intake_results:
{
"status": "completed",
"items": [
{
"key": "logo",
"type": "image",
"status": "submitted",
"value": {
"url": "https://r2.briefgate.dev/signed/...",
"filename": "bellacucina-logo.svg",
"width": 1024,
"height": 512,
"mime_type": "image/svg+xml"
}
},
{
"key": "hero_copy",
"type": "longtext",
"status": "submitted",
"value": "Authentic Italian cuisine in the heart of Prague..."
},
{
"key": "ga4_id",
"type": "text",
"status": "skipped"
}
]
}Agent: "Logo received — SVG, 1024x512. Hero copy in. GA4 ID skipped (optional). Continuing with implementation: placing logo in header, populating hero section with copy, skipping analytics snippet."
Handling secrets
Credentials — WordPress admin, Stripe secret key, Google Analytics service account — need special handling. Use type: "secret".
{
"key": "wp_admin",
"type": "secret",
"label": "Current WordPress admin credentials",
"help": "Username and password for wp-admin. Encrypted before storage, shown to your developer once."
}The client's input is encrypted in their browser using libsodium sealed box before it reaches BriefGate's servers. The ciphertext is stored; the plaintext never is.
When the agent calls get_intake_results, the secret item returns:
{
"key": "wp_admin",
"type": "secret",
"status": "submitted",
"token": "sec_live_xxxxx",
"expires_at": "2026-08-15T10:00:00Z",
"revealed": false
}The agent then calls GET /v1/secrets/sec_live_xxxxx to decrypt and retrieve the plaintext. After that call, the token is consumed — the plaintext cannot be retrieved again through the API. The agent should store it in a secrets manager immediately.
Requesting revisions
When the agent reviews uploaded assets and finds quality issues, it can flag the item and ask the client to resubmit:
request_revision(
intake_id: "int_01J3K...",
item_key: "logo",
note: "The uploaded logo is 200px wide. We need at least 512px for retina screens. If you have an SVG version, that would be ideal — SVG scales to any size without quality loss."
)The client receives an email, sees the note on the flagged item in their portal, re-uploads, and submits. The item.submitted webhook fires again. The agent calls get_intake_results and finds the updated file.
This keeps the revision loop within BriefGate — no separate email thread, no risk of the original submission being overwritten without a record.