MCP server
IntakeFlow ships a Model Context Protocol server at /api/mcp. Point any MCP client at it and an AI agent can inspect, send, and review client portals using your API key as its credential — the same keys, scopes, and plan limits as the REST API.
Connect a client
Claude Code / Claude Desktop
claude mcp add --transport http intakeflow https://your-domain.com/api/mcp \ --header "Authorization: Bearer ifl_live_YOUR_KEY"
Cursor (mcp.json)
{
"mcpServers": {
"intakeflow": {
"url": "https://your-domain.com/api/mcp",
"headers": { "Authorization": "Bearer ifl_live_YOUR_KEY" }
}
}
}Create a dedicated key for your agent. Read-only keys can inspect portals but can't send or review — a good default for assistants you're still trusting.
Transport
Stateless streamable-HTTP: every request is self-contained JSON-RPC 2.0 with the bearer header.initialize, notifications/initialized, ping, tools/list, and tools/call are implemented; no server-side session state, so it works behind load balancers and serverless.
Tools
| Tool | Scope | What it does |
|---|---|---|
| list_portals | read | Portals with status, completion %, and awaiting-review counts. Optional status filter. |
| get_portal | read | One portal in full: client, items, every response, rejection notes. No credential values. |
| send_portal | write | Send a portal to a client (creates the client if needed) and returns the signed link. |
| review_item | write | Approve a submitted item or reject it with a note (the client is emailed). |
| list_templates | read | Templates with item definitions — the source of template ids. |
| upsert_client | write | Create a client or update by email match. |
| portal_link | read | A fresh signed URL the client can use to open their portal. |
| send_reminder | write | Email the client about outstanding items, bypassing the daily cadence. |
Example conversation
With the tools connected, an agent can run a whole review pass on its own:
What the agent does under the hood
User: "Check Acme's portal and approve the items that look complete."
Agent: list_portals({}) → finds Acme, status awaiting_review
get_portal({ portal_id }) → reads each submitted answer
review_item({ response_id: "res_…", action: "approve" })
review_item({ response_id: "res_…", action: "reject",
note: "Screenshot shows the old logo — please re-upload" })Safety rails
- Tool calls inherit the key's scopes — read-only keys simply can't mutate.
- Rejecting without a note is refused; the client needs to know what to fix.
- Every action respects plan limits and tenancy — an agent can only see its own account.
- Credential answers are never exposed to the model, only
has_credentialflags.
Raw JSON-RPC example
POST https://your-domain.com/api/mcp
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "list_portals",
"arguments": { "status": "awaiting_review" }
} }Response
{ "jsonrpc": "2.0", "id": 1, "result": {
"content": [ { "type": "text", "text": "{ \"portals\": […]" } ],
"isError": false } }