Cursor · MCP Server
Cursor MCP Server: build messaging and email features in your IDE
One remote MCP server, one URL, one header. Add it to Cursor and your agent reads the Unipile API specification, writes the LinkedIn, WhatsApp, email or calendar integration into your project, and tests it on a Development application. Nothing to install or run locally. Part of the Unipile MCP server.
Global ~/.cursor/mcp.json
Project .cursor/mcp.json
Remote HTTP, X-API-KEY header
Cursor CLI supported
The install link opens Cursor with the server pre-filled; replace the placeholder with your scoped API key. 7-day free trial, no credit card.
Cursor · crm-app
Unipile MCP connected
Add LinkedIn account connection to my CRM. Users link their own account from the Settings page.
Read endpointPOST /v2/auth/linkschema loaded
Added POST /api/accounts/connect (creates the hosted auth link server-side) and the Settings button that opens it. The callback stores the account ID on the user.
Now sync each user's LinkedIn inbox into the contact timeline.
Run requestGET /v2/{account_id}/chats200 OK
Describe the next feature…
The job
What you are trying to do
Add a LinkedIn, WhatsApp, email or calendar connection to your product. That means reading an API reference, picking the right endpoints, wiring Hosted Auth and its callbacks, then keeping the right IDs from search to message. With the Unipile MCP server in Cursor, the agent does that reading for you and writes the code in your stack.
Connect the Unipile MCP server to CursorUnipile MCP connected
Select the channels you want to connect
developer.unipile.com/mcpConnect all channels9 channels
Instagram/v2/{account_id}/chats↑↓navigate spaceselect ↵connectone URL, one header
Without it
Tabs, guesswork, glue code
Cursor guesses endpoint names and payloads from training data, and gets the IDs wrong.
You paste schemas from the reference into the chat, one endpoint at a time.
The first real call happens in production, after the code review.
With the Unipile MCP server
The result in your application
A connect route and a Settings button: each user links their own account through Hosted Auth.
A webhook receiver and an inbox that shows messages and emails as they arrive.
Every request already run once on your Development application before you review the diff.
mcp.json, global or project
Add the Unipile MCP server to Cursor
The server is remote: one URL over streamable HTTP and one header. No npx, no local process, no Node version to manage. Pick where the entry lives, paste the block from the official documentation, save, and Cursor loads the server.
Cursor up to date, with MCP available in Customize (sidebar) or the Cursor CLI.
A Development application in the Unipile dashboard, with a Scope and a scoped Account API key.
At least one test account connected to that Scope through Hosted Auth, so the agent can run real requests.
Global configuration~/.cursor/mcp.json
Project configuration.cursor/mcp.json (repository root)
Key from an environment variable${env:UNIPILE_API_KEY}
?
Global or project?Global when you build several Unipile integrations from one machine. Project when each repository needs its own scoped key, which is the right call when Development and Production live in different repositories. Cursor reads project first, then global.
{
"mcpServers": {
"unipile": {
"url": "https://developer.unipile.com/mcp?branch=v2.0",
"headers": {
"X-API-KEY": "your-scoped-api-key"
}
}
}
}
{
"mcpServers": {
"unipile": {
"url": "https://developer.unipile.com/mcp?branch=v2.0",
"headers": {
"X-API-KEY": "your-scoped-api-key"
}
}
}
}
{
"mcpServers": {
"unipile": {
"url": "https://developer.unipile.com/mcp?branch=v2.0",
"headers": {
"X-API-KEY": "${env:UNIPILE_API_KEY}"
}
}
}
}
Save the file. Cursor loads the server and lists it in Customize. Cursor resolves ${env:NAME} in url and headers, so the key never has to sit in the file.
Optional: install in one click
Paste your scoped Account API key to get an install link that opens Cursor with the server pre-filled. Everything runs in your browser; the key is never sent to unipile.com.
Leave it empty and the link installs the server with a placeholder you replace in Cursor.
Add Unipile to Cursor
Verify
Verify the connection
Three checks, in the editor, in the CLI, then in a chat. None of them touches a connected account.
1In CustomizeOpen Customize in the sidebar: the unipile server is listed, enabled, and shows its status. The toggle disables it without removing the entry.
2In the Cursor CLIThe CLI shares the editor's configuration, project first, then global.agent mcp list# or /mcp list inside an interactive session
3In a chat, without touching an accountAsk something that only reads the API specification. If the agent answers with real routes and parameters, the server is wired.Using the Unipile MCP, list the endpoints for LinkedIn people search and their required parameters.
Prompts, not glue code
Give your agent the prompt
Three integration jobs, each with the exact prompt to paste in Cursor, the Unipile endpoints the agent reads and runs, and what lands in your project. Paths are complete, on the API base URL
https://api.unipile.com, with your scoped key in the X-API-KEY header.Add LinkedIn messaging to my ATS: sync each recruiter's inbox and let them reply from the candidate page.
Search endpoints"chats messages send"3 matches
Run requestGET /v2/{account_id}/chats12 chats
Created
linkedin/inbox-sync.ts (chats and messages upserted on the candidate, cursor pagination) and POST /candidates/:id/reply, which calls the send route with the chat's own account ID. Ran the sync on the Development app: 12 chats, 87 messages.Paste the prompt, review the diff
Cursor reads the chat and message contracts through the server, writes the sync job and the reply endpoint in your stack, and runs the first requests on your Development application. WhatsApp, Instagram and Telegram use the same chat routes, so the second channel is a smaller prompt than the first.
Endpoints the agent uses
GET/v2/{account_id}/chatsGET/v2/{account_id}/chats/{chat_id}/messagesPOST/v2/{account_id}/chats/{chat_id}/messages/send
Common mistake: Mixing IDs. A message is always sent on the account that owns the chat; keep
Build a LinkedIn integration
account_id and chat_id together from the list call to the send call.Implement Unipile Hosted Auth in this React and Fastify app so users connect their own LinkedIn account from Settings.
Read endpointPOST /v2/auth/linkschema loaded
Run requestPOST /v2/auth/link201 · link
Added
POST /api/accounts/connect in Fastify: it creates the auth link server-side and returns the hosted URL. The React Settings page opens it and, on return, stores the new account_id on the workspace. Verified on the Development app with a test LinkedIn account.Your users connect their own accounts, your app gets an account ID
Hosted Auth is the page Unipile serves to your users so they link LinkedIn, WhatsApp, Gmail, Outlook or a calendar themselves. The agent wires the link creation on your backend, the redirect on your frontend and the storage of the account ID, which every later request needs.
Endpoints the agent uses
POST/v2/auth/linkPOST/v2/auth/intentGET/v2/accounts/{account_id}
Common mistake: Creating the auth link from the browser. The link is created on your server with your key; the frontend only receives the hosted URL.
Implement Hosted Auth with an agent
Subscribe to new-message webhooks and build a unified LinkedIn, WhatsApp and email inbox, one thread list with the channel as a badge.
Read endpointPOST /v2/webhooks/endpoints/schema loaded
Run requestGET /v2/{account_id}/emails200 OK
Registered a webhook endpoint for message events on the Development app, added
POST /webhooks/unipile that returns 200 immediately and queues the event, a Thread model that maps chats and email threads to one shape, and the thread list with channel badges. Sent a test message: the list updated in under a second.Real time without polling, one list for messaging and email
Chats and emails come from two families of routes with one schema each. The agent reads both contracts, designs the common model, writes the sync and the webhook receiver, then checks the delivery log through the webhook conversations route.
Endpoints the agent uses
POST/v2/webhooks/endpoints/GET/v2/{account_id}/chatsGET/v2/{account_id}/emailsGET/v2/webhooks/conversations/
Common mistake: Doing the work inside the webhook handler. Acknowledge with a 2xx right away and process the event asynchronously, or deliveries time out and retry.
Build a unified inbox with an agent
Development to production
Test on a Development application first
The Unipile dashboard separates a Development application from a Production one. Give Cursor a scoped key from the Development application, with one or two test accounts connected through Hosted Auth. The agent runs real requests on those accounts, on behalf of the authenticated user who linked them, within each provider's limits, and nothing touches your users' accounts until you ship.
Validate the connect flow end to end: auth link created server-side, account ID stored on the user.
Validate one read and one write per feature: list chats, send a message on the test account.
Validate a webhook delivery and a reconnect or checkpoint state before switching the key to Production.
crm-app · DevelopmentUsed by Cursor
Scopedev-tests · 2 accounts
Key
scoped Account API keyAccountsLinkedIn test account, Gmail test mailbox
Webhooks1 endpoint · message events
crm-app · ProductionUntouched
Scopeone per workspace
Key
scoped keys, in your backend onlyAccountsyour users' own accounts, via Hosted Auth
Troubleshooting
Common errors and what they mean
The messages Cursor shows when an MCP entry is not right, and the fix for each. Most of them come down to the file, the JSON or the key.
No tools or prompts
Cursor loaded the entry but got nothing back from the server.
FixCheck the file you edited (global ~/.cursor/mcp.json or project .cursor/mcp.json at the repository root), validate the JSON (a trailing comma is the usual culprit), then reload the server from Customize or restart Cursor.
No server info found
The entry is there but Cursor cannot describe the server.
FixThe url must be exactly https://developer.unipile.com/mcp?branch=v2.0, as a remote entry with url and headers, not command. Remove any type: "stdio" left from another server.
Connection failed
The URL answers but not as an MCP server.
FixA typo in the host or in ?branch=v2.0, or a corporate proxy blocking the request. Open the URL in a browser: it must answer, not 404.
401 Unauthorized on requests
The server is connected, but running a request fails.
FixThe key is missing from headers, the header name is not X-API-KEY, or you used a Service or global Account key instead of a scoped Account API key from your Development application.
The project configuration is ignored
Cursor keeps using the global entry, or none.
Fix.cursor/mcp.json must sit at the root of the folder you opened in Cursor, not in a subfolder. Cursor reads project first, then global, then parent directories.
Where to read the logs
Every case above leaves a trace.
FixOpen the Output panel (Cmd+Shift+U on macOS, Ctrl+Shift+U on Windows and Linux) and select MCP Logs in the dropdown: initialization, requests and errors are listed there.
Cursor MCP server FAQ
The questions people actually type: where mcp.json lives, global or project, remote servers and headers, what to check when nothing shows up, keys, one-click install and the CLI.
Two places.
~/.cursor/mcp.json in your home folder is the global configuration, available in every project. .cursor/mcp.json at the root of the folder you opened in Cursor is the project configuration. Cursor reads the project file first, then the global one, then parent directories. Both take the same mcpServers block.Globally when you build several Unipile integrations from one machine and one Development application. Per project when each repository needs its own scoped key, which is the right choice when Development and Production integrations live in different repositories. In both cases the key is a scoped Account API key, never a Service or global key.
Yes. A remote entry in
mcp.json takes a url and a headers object, and Cursor resolves ${env:NAME} inside both. The Unipile server is exactly that: streamable HTTP at https://developer.unipile.com/mcp?branch=v2.0 with the X-API-KEY header. No npx, no local process, no Node version to manage.In this order: the file you edited (global or project, at the repository root), the validity of the JSON, a reload of the server from Customize or a restart of Cursor, then the MCP Logs in the Output panel (Cmd+Shift+U, select MCP Logs). If the server connects but requests fail with 401, the key is missing from the header or is not a scoped Account API key.
The server answers without a key when the agent only reads the API specification. To run real requests, create a Scope in your Development application, assign the test accounts, and generate a scoped Account API key for that Scope. Never give an MCP client a Service key or a global Account key.
Yes. The install link on this page encodes the server configuration; it opens Cursor with the unipile entry pre-filled, and you replace the placeholder with your scoped key. The optional generator above builds the same link with your key already in it, entirely in your browser.
Yes. The CLI shares the editor's configuration, project first, then global.
agent mcp list shows the configured servers and their status, and /mcp list does the same inside an interactive session. The agent then uses the Unipile server when a request calls for it.