Codex · MCP Server
Codex MCP Server: messaging and email in your product
Three lines of config.toml connect the Unipile MCP server. Codex then builds LinkedIn, WhatsApp and email features into your product, from the CLI, the IDE extension or the desktop app. Nothing to install or run locally.
7-day free trial, no credit card.
Codex · crm-app
Unipile MCP connected
Add LinkedIn people search to my CRM.
Read endpointPOST /v2/{account_id}/linkedin/searchschema loaded
Added the search route and the results list. Each row keeps the provider ID for the profile.
Describe the next feature…
Use case
Add LinkedIn, WhatsApp and email to your product from Codex
Add LinkedIn, WhatsApp, email or calendar to your product. Through the Unipile MCP server, Codex reads the API reference, writes the code in your stack and tests every request.
Connect the Unipile MCP server to CodexUnipile MCP connected
Select the channels you want to connect
developer.unipile.com/mcpConnect all channels9 channels
↑↓navigate spaceselect ↵connectone URL, one header
config.toml, CLI and IDE
Add the Unipile MCP server to Codex
The server is remote: one URL over streamable HTTP and one header, nothing to run locally. One entry in config.toml serves Codex CLI, the IDE extension and the ChatGPT desktop app.
Before you start: Codex CLI or the IDE extension, signed in, a Development application in the Unipile dashboard with a scoped Account API key, and one test account linked through Hosted Auth.
codex mcp add, then the headerregisters the URL in ~/.codex/config.toml
Global configuration~/.codex/config.toml
Project configuration.codex/config.toml (trusted project)
Key from an environment variableenv_http_headers
?
Why two steps on the CLI?codex mcp add has no custom header flag, so the X-API-KEY header goes in config.toml, by hand or with env_http_headers.
# 1. Register the hosted Unipile MCP server (global config)
codex mcp add unipile --url "https://developer.unipile.com/mcp?branch=v2.0"
# Added global MCP server 'unipile'.
# 2. Add the X-API-KEY header to the entry in ~/.codex/config.toml
[mcp_servers.unipile]
url = "https://developer.unipile.com/mcp?branch=v2.0"
http_headers = { "X-API-KEY" = "your-scoped-api-key" }
# 3. Verify
codex mcp get unipile
[mcp_servers.unipile]
url = "https://developer.unipile.com/mcp?branch=v2.0"
http_headers = { "X-API-KEY" = "your-scoped-api-key" }
[mcp_servers.unipile]
url = "https://developer.unipile.com/mcp?branch=v2.0"
http_headers = { "X-API-KEY" = "your-scoped-api-key" }
# Read only inside a trusted project. Keep the key out of git: prefer env_http_headers.
[mcp_servers.unipile]
url = "https://developer.unipile.com/mcp?branch=v2.0"
env_http_headers = { "X-API-KEY" = "UNIPILE_API_KEY" }
# export UNIPILE_API_KEY=your-scoped-api-key before launching codex
Save the file and restart Codex. Verified on codex-cli 0.154.0.
Keep your API key out of config.toml. In a shared file, use
env_http_headers so each developer exports their own UNIPILE_API_KEY, or http_headers_helper to read it from a vault. Keep default_tools_approval_mode on prompt while you build if you want to confirm each write.Verify the connection
- 1In the CLI,
codex mcp listshows unipile as enabled, andcodex mcp get unipileits headers. - 2Inside a session,
/mcplists the server; Auth Unsupported is expected, since it uses a header, not OAuth. - 3In a chat, ask
Using the Unipile MCP, list the endpoints for LinkedIn people search and their required parametersand expect real routes back.
Prompts, not glue code
Give your agent the prompt
Three integration jobs, each with the prompt to paste in Codex, the endpoints the agent runs on
https://api.unipile.com with your X-API-KEY, and what lands in your project.Add LinkedIn people search to my CRM, then let the user open the selected profile and start a conversation from it.
Search endpoints"linkedin search people profile"3 matches
Run requestPOST /v2/{account_id}/linkedin/search10 results
Added
GET /api/linkedin/search (keywords, pagination cursor) and GET /api/linkedin/profiles/:identifier. The results list keeps the provider ID returned by the search, the profile route reuses it, and the "Message" button passes it to the chat creation. Ran both on the Development app.One identifier from the search result to the conversation
The hard part is keeping the same identifier from the search row to the profile, then to the message. Codex reads the three contracts and sees which field carries it, so nothing is guessed.
Endpoints the agent uses
Build a LinkedIn integration
POST/v2/{account_id}/linkedin/searchGET/v2/{account_id}/users/{identifier}POST/v2/{account_id}/chats
Generate a typed Node.js and Python client for the Unipile chats and emails routes we use, from the API schemas, with retries on 429.
Read endpointGET /v2/{account_id}/emailsschema loaded
Run requestGET /v2/{account_id}/chats200 OK
Wrote
unipile-client.ts and unipile_client.py from the request and response schemas: typed list and send methods for chats and emails, cursor pagination helper, exponential backoff on 429 with the Retry-After header. Both clients ran the list calls on the Development app.Typed clients from the real schemas, not from memory
Codex reads the request body and response schema of each route, generates the types and runs one call per method on your Development application. The official Node.js and Python SDKs remain the reference.
Endpoints the agent uses
See the official SDKs
GET/v2/{account_id}/chatsPOST/v2/{account_id}/chats/{chat_id}/messages/sendGET/v2/{account_id}/emailsPOST/v2/{account_id}/emails/send
Support multiple connected accounts for each user of my SaaS: they can link several LinkedIn and email accounts and pick which one sends.
Read endpointGET /v2/accountsschema loaded
Run requestGET /v2/accounts3 accounts
Added an
accounts table keyed by user and account_id, a picker in the composer, and POST /api/messages that sends on the selected account. Reconnect states from the accounts route are surfaced as a badge. Verified with three accounts on the Development app.One user, several accounts, one Scope per workspace
Each account your users connect through Hosted Auth gets its own
account_id. The agent maps your users to those IDs, shows reconnect and checkpoint states, and routes every send to the account the user picked.Endpoints the agent uses
Implement Hosted Auth with an agent
GET/v2/accountsGET/v2/accounts/{account_id}POST/v2/auth/linkPOST/v2/{account_id}/chats
A Development application first
Give Codex a scoped key from a Development application, kept apart from Production.
Test accounts, real requests
The agent runs requests on test accounts, on behalf of the authenticated user who linked them, within each provider's limits.
Validate each flow
Check the connect flow, one read and one write per feature, and a webhook delivery.
Then switch to Production
Nothing touches your users' accounts until you switch the key. See security and compliance.
Troubleshooting
Common errors and what they mean
What you see when a Codex MCP entry is not right, and the fix for each.
The server does not show up after editing config.toml
Restart Codex, then check CODEX_HOME and run codex mcp list in the shell you launch Codex from.
The project configuration is ignored
Mark the project as trusted with trust_level = "trusted" under [projects."/path/to/repo"], or move the entry to ~/.codex/config.toml.
Invalid TOML
Name the table [mcp_servers.unipile] exactly and make http_headers a table, with "X-API-KEY" in quotes.
401 Unauthorized on requests
Export the variable named in env_http_headers in the shell that launched Codex, and use a scoped Account API key.
Settings say the server is unavailable
Nothing to change: that check looks for resources, and the Unipile server exposes actions, as /mcp confirms.
Timed out
Check the URL (?branch=v2.0 included), the network and any proxy before raising startup_timeout_sec.
6000+
Companies Innovating with Unipile
Trusted by industry leaders
1 API
Streamline operations for all major communication channels
2 Days
Achieve live integration quickly with minimal setup
30%
Reduction in maintenance efforts and resources
Built-In Security and Compliance
Enterprise-grade protection for your data and workflows Learn more about our security
SOC 2 Type II
Certified
Independently audited security controls ensuring data protection and operational integrity.
GDPR
Compliant
Full compliance with European data protection regulations for user privacy.
99.9%
Platform Uptime over the last 24 months
24/7
Global Support with high-performance API
Codex MCP server FAQ
The questions people actually type: config.toml instead of mcp.json, where it lives, codex mcp add, keeping the key out of the file, the three surfaces, what to check when nothing shows up, timeouts and keys.
No. Codex stores its MCP configuration in
~/.codex/config.toml, in TOML, one table per server named [mcp_servers.<name>]. There is no mcp.json in Codex, and the file is not created at install time: you create it, or codex mcp add creates it for you. A trusted project can also carry a .codex/config.toml at its root.~/.codex/config.toml for the user configuration, .codex/config.toml at the repository root for the project configuration. The CODEX_HOME environment variable moves the whole configuration directory: when a server shows in one terminal and not in another, check it first. Codex CLI, the IDE extension and the desktop app read the same file.Partly.
codex mcp add unipile --url "https://developer.unipile.com/mcp?branch=v2.0" writes the table for a streamable HTTP server, and --bearer-token-env-var covers servers that take a Bearer token. The Unipile server authenticates with an X-API-KEY header, which the command cannot set, so you add http_headers or env_http_headers to the entry it created. Verified on codex-cli 0.154.0.Use
env_http_headers = { "X-API-KEY" = "UNIPILE_API_KEY" }: it maps the header name to the name of an environment variable instead of a value, so the file can be committed without a secret and each developer exports their own scoped Account API key. http_headers is for static values, and http_headers_helper lets a local command produce the headers as JSON.Yes. The three surfaces of one Codex host read the same configuration, so a server added once is available everywhere. In the desktop app and in the extension you can also add it from Settings, MCP servers, Add server, choosing Streamable HTTP. Restart the client after saving the file.
Four causes, in order: the client was not restarted; the file sits under a different
CODEX_HOME than your current shell; the table is in a project .codex/config.toml and the project is not marked trust_level = "trusted", in which case Codex skips the project layer entirely; or the TOML is invalid. Run codex mcp list, then /mcp inside a session.startup_timeout_sec overrides the default 10 second startup timeout and tool_timeout_sec the default 60 second per-tool timeout, both under the server table. The Unipile server is remote over HTTP with no local process to start, so a startup timeout almost always points at the URL, the network or a corporate proxy, not at the server.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.