How-To Guide

Codex MCP HubSpot Setup

The config.toml, the OAuth, and the workflows GTM Engineers wire up first on OpenAI's runtime.

Codex MCP HubSpot Setup
Codex MCP HubSpot Setup

Why Wire Codex to HubSpot

HubSpot is where the deal data lives for most B2B SaaS GTM teams. OpenAI Codex becomes a viable GTM agent runtime the moment it can read and write to that CRM directly. Account research that updates the company record. Pre-call briefs pulled from the deal timeline. Lead scoring on inbound. Enrichment loops that score and route.

HubSpot publishes an official MCP server at https://mcp.hubspot.com/anthropic. The same server works for Claude Code, Codex, and any other MCP client. The wiring path on Codex is slightly different: configuration lives in config.toml, OAuth tokens are referenced by environment variable, and the runtime uses codex exec for headless runs.

For the equivalent on Claude Code's runtime, see Claude Code MCP HubSpot. This guide covers the Codex-specific setup.

Step 1: Configure the MCP Server

Codex MCP servers live in ~/.codex/config.toml. The block for HubSpot:

[mcp_servers.hubspot]
url = "https://mcp.hubspot.com/anthropic"
bearer_token_env_var = "HUBSPOT_OAUTH_TOKEN"

The CLI helper does the same thing interactively:

codex mcp add hubspot --url https://mcp.hubspot.com/anthropic

For team projects, commit a project-scoped config.toml so teammates pick up the same wiring. Personal OAuth tokens stay in each engineer's local environment, referenced by the env var name. The server config travels with the repo. The credentials don't.

The first time the connection is used in a session, Codex triggers the OAuth flow. You log into HubSpot, approve the scopes, and the token gets stored in your environment. For headless jobs, store the token in a secret manager (1Password CLI, AWS Secrets Manager, Doppler) and load it into the env at run time.

Step 2: Pick the Right Scopes

The HubSpot OAuth scopes work the same regardless of which MCP client is calling them. Grant only what the workflow needs.

Read-only research workflow. crm.objects.companies.read, crm.objects.contacts.read, crm.objects.deals.read. Sufficient for account research, pre-call briefs, and pipeline audits.

Enrichment workflow that writes scores and properties. Add crm.objects.companies.write and crm.objects.contacts.write. Plus crm.schemas.contacts.read if the agent needs to discover available custom properties before writing.

Meeting prep and logging. Add crm.objects.meetings.read, crm.objects.meetings.write, and crm.objects.notes.write.

Deal hygiene workflows. Add crm.objects.deals.write.

The principle is the same as any API integration: smallest scope that does the job. Don't grant write access to a workflow that only reads. Don't grant deal-write to a workflow that only touches contacts.

Step 3: Use Codex-Specific Controls

Codex exposes a few per-server controls in config.toml that are worth using for production workflows.

startup_timeout_sec. How long Codex waits for the MCP server to come up. Default works for most cases. Bump higher if you have unreliable network conditions.

tool_timeout_sec. How long an individual MCP tool call can run before Codex aborts. For HubSpot, the default is fine for single-record operations. For batch operations on 100+ records, bump this to 60 or 120 seconds.

enabled_tools and disabled_tools. Allow and deny lists at the server level. Use disabled_tools to block destructive operations (delete contact, delete deal) even if the OAuth scope technically permits them. This is the deterministic guardrail equivalent to a Claude Code hook.

Example block with controls:

[mcp_servers.hubspot]
url = "https://mcp.hubspot.com/anthropic"
bearer_token_env_var = "HUBSPOT_OAUTH_TOKEN"
startup_timeout_sec = 10
tool_timeout_sec = 60
disabled_tools = ["delete_contact", "delete_deal", "delete_company"]

Step 4: Write the Workflow Prompt

The prompt structure for a Codex workflow:

Role. One paragraph. "You are an account research agent. You read HubSpot company records, gather firmographic and signal data, and write a summary back to a custom property."

Inputs. What the workflow reads. "A list of company IDs from the active_research_queue table."

Steps. Numbered and explicit. "For each company ID: read the company record. If last_research_date is older than 30 days, run research. Write the summary to ai_research_summary. Update last_research_date to today. Skip if research is fresh."

Output format. The summary structure, length, and tone.

Stopping conditions. "Stop after 100 companies. Stop on any error affecting more than 5% of the batch."

Save the prompt as a file. Don't paste it into the runtime command. For automation, put the project context in AGENTS.md at the repo root, the open standard that Codex reads natively. The Codex sales agent guide covers the full workflow build.

Step 5: Schedule with codex exec

The codex exec command is non-interactive. It runs the task and exits, perfect for cron jobs.

codex exec "process the active research queue from HubSpot, writing summaries back to each company"

Schedule this on a cron job that runs at your desired cadence. Pipe stdout to a log file. Pipe stderr to a Slack alert. Track API usage and tokens consumed per run.

For workflows that benefit from cloud execution rather than local cron, Codex offers the cloud agent surface delegated from ChatGPT. Useful for long-running jobs (1000+ companies) where you don't want to tie up local compute.

Production Failures to Watch

Three things break repeatedly.

Token expiry. HubSpot OAuth tokens have a finite lifetime. The refresh token grant handles renewal automatically if offline_access is in your scope set, but it must be wired correctly in config.toml. Test the refresh flow before scheduling. A token that expires mid-run breaks the cron silently.

Rate-limit cascades. A batch run that processes 500 companies with multiple property reads per company trips HubSpot's 100-requests-per-10-seconds limit. The HubSpot MCP server handles batch reads through HubSpot's batch endpoints which avoids most of this. For writes that don't have a batch endpoint, add exponential backoff and a hard ceiling.

Schema drift. A teammate renames a custom property in HubSpot. The agent's prompt still references the old name. Writes silently fail or land in the wrong field. Read the property schema at the top of every run. Log a clear error if the expected property doesn't exist.

For the Claude Code equivalent, see Claude Code MCP HubSpot. For Salesforce on Codex, the same patterns apply but with the Salesforce Connected App in place of HubSpot's OAuth flow. For broader Codex GTM patterns, see the Codex sales agent guide.

Authoritative References

For Codex CLI commands and config.toml fields, see OpenAI's Codex CLI documentation. For the Codex MCP setup specifically, see the Codex MCP guide. For HubSpot OAuth scopes and rate limits, see the HubSpot OAuth documentation.

Frequently Asked Questions

How do I add the HubSpot MCP server to OpenAI Codex?

Codex stores MCP server configuration in a config.toml file (usually at ~/.codex/config.toml). Add an [mcp_servers.hubspot] block with url = 'https://mcp.hubspot.com/anthropic' and the appropriate bearer_token_env_var pointing at an environment variable that holds your OAuth token. Alternatively, codex mcp add hubspot from the CLI walks you through the same setup interactively. The OAuth flow happens once and the token gets stored in your config.

What HubSpot OAuth scopes does Codex need for sales workflows?

For read-only research: crm.objects.companies.read, crm.objects.contacts.read, crm.objects.deals.read. For workflows that write properties: add the .write versions. For meeting log automation: crm.objects.meetings.write and crm.objects.notes.write. Grant only what the workflow needs. A Codex agent with overly broad scope plus a vague prompt can update fields you didn't intend, just like any other agent runtime.

Can I run a headless Codex job that writes to HubSpot via MCP?

Yes. codex exec is the non-interactive mode that runs the task and exits. Schedule it as a cron job on a small always-on machine. The job loads the MCP config, opens the HubSpot connection using the stored OAuth token, runs your prompt, and exits. The token refresh happens automatically if you've enabled offline access. Pipe the log to a file for audit. Pipe failures to Slack.

How does Codex handle HubSpot's API rate limits?

Codex itself doesn't add rate-limit handling beyond what the MCP server provides. The HubSpot MCP server handles batch operations through HubSpot's batch endpoints (read up to 100 records per call) which keeps you under the per-10-second limit for most workflows. For runs that approach the limit, add exponential backoff to the prompt with a retry ceiling. The safer pattern is to cap batch size in the prompt itself rather than relying on retry logic.

What's the difference between using Codex versus Claude Code for HubSpot MCP integration?

The MCP server is the same. The differences are in the runtime around it. Codex configures servers in config.toml (declarative), exposes per-server tool_timeout_sec and enabled_tools/disabled_tools controls, and runs headless via codex exec. Claude Code configures in .mcp.json, supports hooks for deterministic guardrails, and runs headless via claude -p. Both produce comparable results on standard HubSpot workflows. Pick the runtime that fits your team's existing stack.

Source: State of GTM Engineering Report 2026 (n=228). Salary data combines survey responses from 228 GTM Engineers across 32 countries with analysis of 3,342 job postings.

Get the Weekly Pulse

Salary shifts, tool intel, and job market data for GTM Engineers. Weekly playbooks for wiring Codex into the GTM stack.