Skip to content

Commit 4f49d49

Browse files
committed
Isolate launch readiness MCP config
1 parent e4997c4 commit 4f49d49

5 files changed

Lines changed: 340 additions & 38 deletions

File tree

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ test-release-asset-names: ## Validate GitHub Release asset naming configuration.
229229
test-release-notes: ## Validate LLM-generated GitHub Release notes plumbing.
230230
tests/release_notes.sh
231231

232+
.PHONY: test-launch-readiness-mcp-config
233+
test-launch-readiness-mcp-config: ## Validate launch-readiness Codex MCP isolation.
234+
tests/launch_readiness_mcp_config.sh
235+
232236
.PHONY: fmt
233237
fmt: ## Format Rust code.
234238
$(CARGO) fmt --all

experiment/locality-mcp-comparison/README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The output parent page is:
2222
hosted MCP path against Codex on the Locality path.
2323
- `run-launch-readiness-benchmark.sh` - core benchmark runner.
2424
- `run-repeated.sh` - runs the benchmark multiple times.
25-
- `setup-codex-azure.sh` - writes Codex Azure config.
25+
- `setup-codex-azure.sh` - writes Codex Azure config without MCP servers.
2626
- `prompts/Locality/*.md` - Locality-only scenario prompts.
2727
- `prompts/MCP/*.md` - Notion-MCP-only scenario prompts, paired by filename with `prompts/Locality/*.md`.
2828
- `prompts/locality-agent-prompt.md` - legacy Locality-only agent prompt used only when `prompts/Locality/` has no scenarios.
@@ -78,13 +78,12 @@ ssh -o StrictHostKeyChecking=accept-new "$SSH_TARGET" '
7878
'
7979
```
8080

81-
Verify Notion MCP and Locality:
81+
Verify Locality:
8282

8383
```bash
8484
ssh -o StrictHostKeyChecking=accept-new "$SSH_TARGET" '
8585
export PATH="$HOME/.cargo/bin:$PATH"
8686
cd /home/amika/workspace/locality
87-
codex mcp list
8887
target/debug/loc connections --json
8988
target/debug/loc locate "https://app.notion.com/p/codeflash/Locality-Launch-Amika-Environment-3a33ac0ebb888001ac26d52f57f1deba"
9089
'
@@ -132,7 +131,8 @@ Codex auth/config or `~/.config/locality-experiment/env`.
132131
## Launch Runner MCP Auth
133132

134133
When `run-launch-readiness-benchmark.sh` is run with `--compare-mcp`, it
135-
configures Codex MCP auth before running the MCP scenarios:
134+
validates MCP credentials during setup and configures Codex MCP auth only before
135+
running the MCP scenarios:
136136

137137
```bash
138138
export LINEAR_API_KEY=<linear-api-key>
@@ -149,9 +149,11 @@ export SLACK_CHANNEL_IDS=<comma-delimited-channel-ids>
149149
any Slack MCP variable is set, both `SLACK_BOT_TOKEN` and `SLACK_TEAM_ID` are
150150
required.
151151

152-
The runner stores token-backed helper scripts and secret files under
153-
`~/.local/bin` and `~/.config/locality-launch-readiness/mcp` by default, then
154-
updates Codex MCP entries for `linear-server`, `notion`, and optionally `slack`.
152+
The runner uses separate per-run Codex homes under `OUT_DIR/codex` by default.
153+
The Locality strategy uses a config with all `mcp_servers.*` tables stripped.
154+
The MCP strategy stores token-backed helper scripts and secret files under
155+
`OUT_DIR/mcp` by default, then updates only the MCP strategy Codex home with
156+
entries for `linear-server`, `notion`, and optionally `slack`.
155157

156158
## Add Scenarios
157159

@@ -249,6 +251,7 @@ Important artifacts:
249251
- `metrics.tsv` - phase wall-clock metrics with a `scenario` column.
250252
- `summary.json` - machine-readable run summary.
251253
- `scenarios.tsv` - scenario manifest with prompt paths, output directories, and mounted report pages when `--write-mounted-page` or `--push` is used.
254+
- `codex-strategy-setup.out` and `codex-strategy-setup.err` - per-strategy Codex config setup logs.
252255
- `mcp-auth-setup.out` and `mcp-auth-setup.err` - Codex MCP setup logs when `--compare-mcp` is enabled.
253256
- `scenarios/<scenario>/report-body.md` - Locality report for that scenario.
254257
- `scenarios/<scenario>/notion-mcp-report-body.md` - MCP report for that scenario.

experiment/locality-mcp-comparison/run-launch-readiness-benchmark.sh

Lines changed: 127 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ REPORT_DATE="${REPORT_DATE:-$(TZ="$REPORT_TZ" date +%F)}"
8181
RUN_ID="${RUN_ID:-$(date -u +%Y%m%dT%H%M%SZ)}"
8282
REPORT_TITLE="${REPORT_TITLE:-Launch Readiness Benchmark $RUN_ID}"
8383
OUT_DIR="${OUT_DIR:-$REPO_DIR/experiment/runs/$RUN_ID}"
84+
RUN_ROOT_OUT_DIR="$OUT_DIR"
8485
CODEX_MODEL="${CODEX_MODEL:-gpt-5.6-luna}"
8586
CODEX_REASONING_EFFORT="${CODEX_REASONING_EFFORT:-low}"
8687
CODEX_EXEC_TIMEOUT_SECONDS="${CODEX_EXEC_TIMEOUT_SECONDS:-900}"
@@ -93,8 +94,15 @@ LOCALITY_EXPERIMENT_TRACE_FORCE_DIRECT="${LOCALITY_EXPERIMENT_TRACE_FORCE_DIRECT
9394
PROMPT_ROOT="${PROMPT_ROOT:-$SCRIPT_DIR/prompts}"
9495
LOCALITY_PROMPT_DIR="${LOCALITY_PROMPT_DIR:-$PROMPT_ROOT/Locality}"
9596
MCP_PROMPT_DIR="${MCP_PROMPT_DIR:-$PROMPT_ROOT/MCP}"
96-
MCP_SECRET_DIR="${MCP_SECRET_DIR:-$HOME/.config/locality-launch-readiness/mcp}"
97-
MCP_BIN_DIR="${MCP_BIN_DIR:-$HOME/.local/bin}"
97+
BASE_CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
98+
CODEX_STRATEGY_ROOT="${CODEX_STRATEGY_ROOT:-$RUN_ROOT_OUT_DIR/codex}"
99+
LOCALITY_CODEX_HOME="$CODEX_STRATEGY_ROOT/locality"
100+
MCP_CODEX_HOME="$CODEX_STRATEGY_ROOT/notion-mcp"
101+
MCP_SECRET_DIR="${MCP_SECRET_DIR:-$RUN_ROOT_OUT_DIR/mcp/secrets}"
102+
MCP_BIN_DIR="${MCP_BIN_DIR:-$RUN_ROOT_OUT_DIR/mcp/bin}"
103+
MCP_AUTH_SETUP_OUT="$RUN_ROOT_OUT_DIR/mcp-auth-setup.out"
104+
MCP_AUTH_SETUP_ERR="$RUN_ROOT_OUT_DIR/mcp-auth-setup.err"
105+
MCP_AUTH_CONFIGURED=0
98106
METRICS_TSV="$OUT_DIR/metrics.tsv"
99107
SUMMARY_JSON="$OUT_DIR/summary.json"
100108
CONTEXT_PATHS_FILE="$OUT_DIR/locality-context-paths.txt"
@@ -167,11 +175,52 @@ render_locality_traces() {
167175
done
168176
}
169177

170-
configure_codex_mcp_auth() {
171-
MCP_AUTH_DETAIL="linear=skipped; notion=skipped; slack=skipped"
178+
strip_codex_mcp_tables() {
179+
local source="$1"
180+
local destination="$2"
181+
python3 - "$source" "$destination" <<'PY'
182+
import re
183+
import sys
184+
from pathlib import Path
172185
173-
command -v codex >/dev/null || return
186+
source = Path(sys.argv[1])
187+
destination = Path(sys.argv[2])
188+
text = source.read_text(encoding="utf-8") if source.exists() else ""
189+
190+
skip = False
191+
lines = []
192+
for line in text.splitlines(keepends=True):
193+
stripped = line.strip()
194+
header = stripped.split("#", 1)[0].strip()
195+
if header.startswith("[") and header.endswith("]"):
196+
table = header.strip("[]").strip()
197+
skip = table == "mcp_servers" or table.startswith("mcp_servers.")
198+
if skip:
199+
continue
200+
if re.match(r"^mcp_servers\s*=", stripped):
201+
continue
202+
lines.append(line)
203+
204+
destination.parent.mkdir(parents=True, exist_ok=True)
205+
body = "".join(lines).rstrip()
206+
destination.write_text((body + "\n") if body else "", encoding="utf-8")
207+
PY
208+
}
174209

210+
prepare_codex_home_without_mcp() {
211+
local codex_home="$1"
212+
mkdir -p "$codex_home"
213+
chmod 700 "$codex_home"
214+
215+
if [ -d "$BASE_CODEX_HOME" ] && [ "$BASE_CODEX_HOME" != "$codex_home" ]; then
216+
find "$BASE_CODEX_HOME" -maxdepth 1 -type f ! -name config.toml -exec cp -p {} "$codex_home/" \; 2>/dev/null || true
217+
fi
218+
219+
strip_codex_mcp_tables "$BASE_CODEX_HOME/config.toml" "$codex_home/config.toml"
220+
chmod 600 "$codex_home/config.toml"
221+
}
222+
223+
validate_codex_mcp_auth_inputs() {
175224
if [ -z "$LINEAR_API_KEY" ]; then
176225
echo "LINEAR_API_KEY is required when --compare-mcp is enabled" >&2
177226
return 2
@@ -185,9 +234,32 @@ configure_codex_mcp_auth() {
185234
echo "SLACK_BOT_TOKEN and SLACK_TEAM_ID are both required to configure Slack MCP" >&2
186235
return 2
187236
fi
237+
}
238+
239+
prepare_codex_strategy_homes() {
240+
prepare_codex_home_without_mcp "$LOCALITY_CODEX_HOME"
241+
if [ "$COMPARE_MCP" -eq 1 ]; then
242+
validate_codex_mcp_auth_inputs || return
243+
prepare_codex_home_without_mcp "$MCP_CODEX_HOME"
244+
fi
245+
}
188246

189-
mkdir -p "$MCP_SECRET_DIR" "$MCP_BIN_DIR" "$HOME/.codex" || return
190-
chmod 700 "$MCP_SECRET_DIR" "$HOME/.codex" || return
247+
codex_home_for_strategy() {
248+
case "$1" in
249+
locality) printf '%s\n' "$LOCALITY_CODEX_HOME" ;;
250+
notion-mcp) printf '%s\n' "$MCP_CODEX_HOME" ;;
251+
*) printf '%s\n' "$BASE_CODEX_HOME" ;;
252+
esac
253+
}
254+
255+
configure_codex_mcp_auth() {
256+
MCP_AUTH_DETAIL="linear=skipped; notion=skipped; slack=skipped"
257+
258+
command -v codex >/dev/null || return
259+
validate_codex_mcp_auth_inputs || return
260+
261+
mkdir -p "$MCP_SECRET_DIR" "$MCP_BIN_DIR" "$MCP_CODEX_HOME" || return
262+
chmod 700 "$MCP_SECRET_DIR" "$MCP_BIN_DIR" "$MCP_CODEX_HOME" || return
191263

192264
local notion_helper="$MCP_BIN_DIR/locality-launch-notion-mcp"
193265
(
@@ -216,12 +288,12 @@ SH
216288
) || return
217289

218290
export LINEAR_API_KEY
219-
codex mcp remove linear-server >/dev/null 2>&1 || true
220-
codex mcp remove notion >/dev/null 2>&1 || true
221-
codex mcp remove slack >/dev/null 2>&1 || true
222-
codex mcp remove slack-server >/dev/null 2>&1 || true
223-
codex mcp add linear-server --url https://mcp.linear.app/mcp --bearer-token-env-var LINEAR_API_KEY || return
224-
codex mcp add notion -- "$notion_helper" || return
291+
CODEX_HOME="$MCP_CODEX_HOME" codex mcp remove linear-server >/dev/null 2>&1 || true
292+
CODEX_HOME="$MCP_CODEX_HOME" codex mcp remove notion >/dev/null 2>&1 || true
293+
CODEX_HOME="$MCP_CODEX_HOME" codex mcp remove slack >/dev/null 2>&1 || true
294+
CODEX_HOME="$MCP_CODEX_HOME" codex mcp remove slack-server >/dev/null 2>&1 || true
295+
CODEX_HOME="$MCP_CODEX_HOME" codex mcp add linear-server --url https://mcp.linear.app/mcp --bearer-token-env-var LINEAR_API_KEY || return
296+
CODEX_HOME="$MCP_CODEX_HOME" codex mcp add notion -- "$notion_helper" || return
225297

226298
local slack_status="skipped"
227299
if [ -n "$SLACK_BOT_TOKEN" ]; then
@@ -250,13 +322,14 @@ exec npx -y @modelcontextprotocol/server-slack
250322
SH
251323
chmod 700 "$slack_helper"
252324
) || return
253-
codex mcp add slack -- "$slack_helper" || return
325+
CODEX_HOME="$MCP_CODEX_HOME" codex mcp add slack -- "$slack_helper" || return
254326
slack_status="configured"
255327
else
256328
rm -f "$MCP_SECRET_DIR/slack-bot-token" "$MCP_SECRET_DIR/slack-team-id" "$MCP_SECRET_DIR/slack-channel-ids"
257329
fi
258330

259-
MCP_AUTH_DETAIL="linear=configured; notion=configured; slack=$slack_status"
331+
MCP_AUTH_DETAIL="linear=configured; notion=configured; slack=$slack_status; codex_home=$MCP_CODEX_HOME"
332+
MCP_AUTH_CONFIGURED=1
260333
echo "Configured Codex MCP auth: $MCP_AUTH_DETAIL"
261334
}
262335

@@ -277,6 +350,8 @@ run_codex_agent() {
277350
local agent_loc_trace="$OUT_DIR/$strategy-agent-locality-trace.jsonl"
278351
local prompt
279352
local run_cmd
353+
local codex_home
354+
codex_home="$(codex_home_for_strategy "$strategy")"
280355
prompt="$(cat "$prompt_file")"
281356
cp "$prompt_file" "$prompt_snapshot"
282357

@@ -304,6 +379,7 @@ run_codex_agent() {
304379
fi
305380
{
306381
printf 'timeout_seconds=%s\n' "$CODEX_EXEC_TIMEOUT_SECONDS"
382+
printf 'codex_home=%s\n' "$codex_home"
307383
printf 'codex_command='
308384
printf '%q ' "${cmd[@]}"
309385
printf '\nwrapped_command='
@@ -313,7 +389,7 @@ run_codex_agent() {
313389

314390
set +e
315391
set -o pipefail
316-
LOCALITY_TRACE_FILE="$agent_loc_trace" LOCALITY_TRACE_RUN_ID="$RUN_ID" \
392+
CODEX_HOME="$codex_home" LOCALITY_TRACE_FILE="$agent_loc_trace" LOCALITY_TRACE_RUN_ID="$RUN_ID" \
317393
"${run_cmd[@]}" < /dev/null 2> "$err_file" | python3 "$SCRIPT_DIR/scripts/timestamp-jsonl.py" > "$events_file"
318394
local pipe_status=("${PIPESTATUS[@]}")
319395
local rc="${pipe_status[0]}"
@@ -493,21 +569,21 @@ git -C "$REPO_DIR" rev-parse --git-dir >/dev/null
493569
phase_end "locality" "validate_environment" "ok" "repo=$REPO_DIR; model=$CODEX_MODEL; effort=$CODEX_REASONING_EFFORT; scenarios=${#SCENARIO_FILES[@]}; prompts=$LOCALITY_PROMPT_DIR; write_mounted_page=$WRITE_MOUNTED_PAGE"
494570

495571
phase_start
496-
if [ "$COMPARE_MCP" -eq 1 ]; then
497-
set +e
498-
configure_codex_mcp_auth > "$OUT_DIR/mcp-auth-setup.out" 2> "$OUT_DIR/mcp-auth-setup.err"
499-
MCP_AUTH_RC=$?
500-
set -e
501-
if [ "$MCP_AUTH_RC" -eq 0 ]; then
502-
phase_end "notion_mcp" "mcp_auth_setup" "ok" "$MCP_AUTH_DETAIL; out=$OUT_DIR/mcp-auth-setup.out"
572+
set +e
573+
prepare_codex_strategy_homes > "$OUT_DIR/codex-strategy-setup.out" 2> "$OUT_DIR/codex-strategy-setup.err"
574+
CODEX_STRATEGY_SETUP_RC=$?
575+
set -e
576+
if [ "$CODEX_STRATEGY_SETUP_RC" -eq 0 ]; then
577+
if [ "$COMPARE_MCP" -eq 1 ]; then
578+
phase_end "locality" "codex_strategy_config" "ok" "locality_home=$LOCALITY_CODEX_HOME; mcp_home=$MCP_CODEX_HOME; mcp_auth=validated"
503579
else
504-
phase_end "notion_mcp" "mcp_auth_setup" "failed" "exit=$MCP_AUTH_RC; out=$OUT_DIR/mcp-auth-setup.out; err=$OUT_DIR/mcp-auth-setup.err"
505-
cat "$OUT_DIR/mcp-auth-setup.out" >&2 || true
506-
cat "$OUT_DIR/mcp-auth-setup.err" >&2 || true
507-
exit "$MCP_AUTH_RC"
580+
phase_end "locality" "codex_strategy_config" "ok" "locality_home=$LOCALITY_CODEX_HOME; mcp_auth=not requested"
508581
fi
509582
else
510-
phase_end "notion_mcp" "mcp_auth_setup" "skipped" "pass --compare-mcp to configure Codex MCP auth"
583+
phase_end "locality" "codex_strategy_config" "failed" "exit=$CODEX_STRATEGY_SETUP_RC; out=$OUT_DIR/codex-strategy-setup.out; err=$OUT_DIR/codex-strategy-setup.err"
584+
cat "$OUT_DIR/codex-strategy-setup.out" >&2 || true
585+
cat "$OUT_DIR/codex-strategy-setup.err" >&2 || true
586+
exit "$CODEX_STRATEGY_SETUP_RC"
511587
fi
512588

513589
phase_start
@@ -709,6 +785,29 @@ PY
709785
fi
710786

711787
if [ "$COMPARE_MCP" -eq 1 ]; then
788+
phase_start
789+
if [ "$MCP_AUTH_CONFIGURED" -eq 0 ]; then
790+
set +e
791+
configure_codex_mcp_auth > "$MCP_AUTH_SETUP_OUT" 2> "$MCP_AUTH_SETUP_ERR"
792+
MCP_AUTH_RC=$?
793+
set -e
794+
if [ "$MCP_AUTH_RC" -eq 0 ]; then
795+
phase_end "notion_mcp" "mcp_auth_setup" "ok" "$MCP_AUTH_DETAIL; out=$MCP_AUTH_SETUP_OUT"
796+
else
797+
phase_end "notion_mcp" "mcp_auth_setup" "failed" "exit=$MCP_AUTH_RC; out=$MCP_AUTH_SETUP_OUT; err=$MCP_AUTH_SETUP_ERR"
798+
cat "$MCP_AUTH_SETUP_OUT" >&2 || true
799+
cat "$MCP_AUTH_SETUP_ERR" >&2 || true
800+
OUT_DIR="$RUN_OUT_DIR"
801+
CONTEXT_PATHS_FILE="$RUN_CONTEXT_PATHS_FILE"
802+
CONTEXT_INVENTORY="$RUN_CONTEXT_INVENTORY"
803+
CONTEXT_SEARCH_RESULTS="$RUN_CONTEXT_SEARCH_RESULTS"
804+
export OUT_DIR CONTEXT_PATHS_FILE CONTEXT_INVENTORY CONTEXT_SEARCH_RESULTS
805+
exit "$MCP_AUTH_RC"
806+
fi
807+
else
808+
phase_end "notion_mcp" "mcp_auth_setup" "skipped" "already configured; codex_home=$MCP_CODEX_HOME"
809+
fi
810+
712811
phase_start
713812
set +e
714813
run_codex_agent "notion-mcp" "$MCP_PROMPT_FILE" "$OUT_DIR/notion-mcp-report-body.md" "$OUT_DIR/notion-mcp-agent-final.md"

experiment/locality-mcp-comparison/setup-codex-azure.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ name = "Azure OpenAI"
1818
base_url = "$AZURE_OPENAI_BASE_URL"
1919
env_key = "AZURE_OPENAI_API_KEY"
2020
wire_api = "responses"
21-
22-
[mcp_servers.notion]
23-
url = "https://mcp.notion.com/mcp"
2421
TOML
2522

2623
chmod 700 "$CODEX_HOME"

0 commit comments

Comments
 (0)