This guide describes how to connect a local Python MCP server to the Codex VS Code extension by using a project-level .codex/config.toml file.
The example assumes:
- The MCP server is implemented in Python with FastMCP.
- The MCP server runs through
stdio. - The Python virtual environment already contains all required packages.
- The MCP server may use a
.envfile for environment variables such as dbt project paths and credentials.
Open the VS Code terminal and activate the Python environment where the MCP server already works.
Then run:
python -c "import sys; print(sys.executable)"Example result:
C:\Users\<user>\Development\project\.venv\Scripts\python.exe
Save this full path.
Codex should start the MCP server using this exact Python executable so that all required packages are available.
From the directory containing the MCP server, run:
Resolve-Path .\metricflow_mcp.pyExample:
C:\Users\<user>\Development\project\semantic\metricflow_mcp.py
Also get the directory containing the MCP server:
Resolve-Path .Example:
C:\Users\<user>\Development\project\semantic
This directory can be used as the MCP server working directory.
If the MCP server uses:
from dotenv import load_dotenv
load_dotenv()keep the .env file in the MCP server working directory.
Example:
semantic/
├── .env
├── metricflow_mcp.py
└── .venv/
Example .env:
DBT_PROJECT_DIR=C:\Users\<user>\Development\dbt\LCom_DW
DBT_PROFILES_DIR=C:\Users\<user>\.dbt
DBT_TARGET=dev
If the .env file contains credentials or secrets, add it to .gitignore.
Example:
.envAt the root of the repository opened in VS Code, create:
.codex/
Inside it, create:
config.toml
The repository structure should look similar to:
project/
│
├── .codex/
│ └── config.toml
│
├── AGENTS.md
│
├── semantic/
│ ├── metricflow_mcp.py
│ └── .env
│
└── ...
Add a configuration block for the MCP server.
Example:
[mcp_servers.lcom_metrics]
command = 'C:\FULL\PATH\TO\.venv\Scripts\python.exe'
args = ['C:\FULL\PATH\TO\semantic\metricflow_mcp.py']
cwd = 'C:\FULL\PATH\TO\semantic'
enabled = true
required = true
startup_timeout_sec = 60
tool_timeout_sec = 120Replace the example paths with the real paths from Steps 2 and 3.
Using single quotes in TOML is convenient on Windows because backslashes do not need to be escaped.
For example:
[mcp_servers.lcom_metrics]
command = 'C:\Users\<user>\Development\project\.venv\Scripts\python.exe'
args = ['C:\Users\<user>\Development\project\semantic\metricflow_mcp.py']
cwd = 'C:\Users\<user>\Development\project\semantic'
enabled = true
required = true
startup_timeout_sec = 60
tool_timeout_sec = 120mcp_servers.lcom_metrics— MCP server name visible to Codex.command— Python executable used to start the server.args— path to the MCP server Python file.cwd— working directory used when the MCP process starts.enabled— enables the MCP server.required— treats the MCP server as required for the Codex session.startup_timeout_sec— maximum startup time.tool_timeout_sec— maximum execution time for an MCP tool call.
After saving .codex/config.toml, restart the Codex extension.
You can also reload the VS Code window.
The MCP server should then be started automatically when Codex loads the project configuration.
If the Codex CLI is installed, run:
codex mcp listThe configured MCP server should appear in the list.
Example:
lcom_metrics enabled
You can also inspect the MCP servers from the Codex extension UI.
Start with a tool that does not require complex parameters.
For example, if the MCP server exposes:
get_metrics
ask Codex:
Use the lcom_metrics MCP server and tell me which metrics are available.
Codex should call the MCP tool instead of generating SQL or guessing metric names.
Then test another tool, for example:
Which dimensions are available for ARR?
Codex should call something similar to:
get_dimensions(metric="arr")
For a semantic metrics server, test a complete business question.
Example:
What was ARR for California in June 2026?
Use the lcom_metrics MCP tools, not SQL.
A typical tool sequence can be:
get_metrics
↓
get_dimensions
↓
get_state_codes
↓
run_metricflow_query
The MCP server is responsible for validating metric names, dimensions, controlled values, dates, ordering, and limits before executing the MetricFlow query.
Create an AGENTS.md file at the repository root.
Codex automatically reads repository instructions from this file.
Example:
# Codex Instructions
## Learning.com Metrics
For questions requiring Learning.com business metric values, use the
`lcom_metrics` MCP server instead of generating SQL.
Before querying:
1. Use `get_metrics` to identify the exact metric name.
2. Use `get_dimensions` to identify dimensions available for the requested metric.
3. Use controlled-value tools such as `get_state_codes` or `get_countries`
when filtering those dimensions.
4. Execute the metric query using `run_metricflow_query`.
Do not invent metric names, dimensions, or controlled dimension values.
If `run_metricflow_query` returns `success: false`, use the returned validation
error to correct the MCP query and retry.AGENTS.md is separate from Codex Skills.
Use:
AGENTS.mdfor repository-level instructions and MCP routing rules.- Skills for reusable business knowledge, ontology, metric definitions, and workflows.
- MCP tools for retrieving or calculating actual data.
User question
↓
Codex
↓
AGENTS.md
↓
Business Knowledge Skills
↓
MCP tools
↓
MetricFlow
↓
dbt Semantic Layer
↓
Data Warehouse
For example:
"What was ARR for CA in June 2026?"
↓
Codex understands the business question
↓
AGENTS.md tells Codex to use lcom_metrics
↓
Skill provides business meaning of ARR
↓
MCP validates metric/dimension/value names
↓
run_metricflow_query
↓
MetricFlow builds the semantic query
↓
Redshift returns the data
This keeps responsibilities separated:
- Codex interprets the user's request.
- Skills provide business context.
- MCP exposes controlled tools and validation.
- MetricFlow generates the semantic query.
- dbt Semantic Layer defines metrics and dimensions.
- Redshift provides the underlying data.
Check:
codex mcp listThen verify:
.codex/config.tomlexists at the repository root.commandpoints to the correct Python executable.argspoints to the correct MCP server file.enabled = true.- The Codex extension was restarted after the configuration change.
Run the server manually with the same Python executable configured in Codex:
"C:\FULL\PATH\TO\.venv\Scripts\python.exe" "C:\FULL\PATH\TO\metricflow_mcp.py"If it fails here, fix the Python/MCP environment before testing through Codex.
Typical causes include:
- Missing Python packages.
- Incorrect
DBT_PROJECT_DIR. - Incorrect
DBT_PROFILES_DIR. - Incorrect dbt target.
- Missing environment variables.
- Database authentication issues.
Verify that cwd points to the directory containing .env.
Example:
cwd = 'C:\Users\<user>\Development\project\semantic'Alternatively, explicitly provide required environment variables through the MCP configuration.
Make sure the Python server does not write normal output to stdout.
Avoid startup code such as:
print("Server started")or local test blocks such as:
if __name__ == "__main__":
print(run_metricflow_query(...))For the production MCP server, use only:
if __name__ == "__main__":
mcp.run(transport="stdio")Logging, if needed, should be configured so that it does not interfere with MCP stdio communication.
Before using the MCP server from Codex, confirm:
- MCP server runs with
mcp.run(transport="stdio") - Test
print()statements are removed from startup code - Correct Python virtual environment is used
- MCP Python file path is correct
-
.envis available -
.envis excluded from Git if it contains secrets -
.codex/config.tomlexists - MCP server is enabled in
config.toml - Codex extension has been restarted
-
codex mcp listshows the server - Simple MCP tool call works
- Full metric workflow works
-
AGENTS.mdcontains MCP usage instructions