From bb88393f413ebe51ad892246f8234fe7e5230318 Mon Sep 17 00:00:00 2001
From: thedoublejay
Date: Fri, 29 May 2026 14:37:55 +0700
Subject: [PATCH] feat: fix setup-mcp config targets, add codex client, prep
4.2.0
setup-mcp previously wrote the gather-step server block to
`.claude/settings.json`, which Claude Code does not read for MCP server
definitions, so the registered server never appeared in the client.
- `--scope local` now writes the project-scoped `.mcp.json`; `--scope global`
writes the user-scoped `~/.claude.json`.
- New `--client codex` merges a `[mcp_servers.gather-step]` block into
`~/.codex/config.toml` using toml_edit, preserving existing servers, other
keys, and comments. Default client stays `claude`.
- `status` MCP detection now reads `.mcp.json` / `~/.claude.json` to match the
new write locations; integration and wizard tests updated accordingly.
- Corrected the MCP clients guide (user scope is `~/.claude.json`, not
`~/.claude/settings.json`; refreshed the Fast Path section).
- Refreshed Cargo deps to latest SemVer-compatible versions (serde_json,
tokio, rmcp, similar, quick_cache, memchr + transitive); exact pins left
untouched. Bumped website astro 6.3.5 -> 6.4.2.
- Bumped workspace, internal crate, and website versions and landing-page
stamps to 4.2.0; marked 4.2.0 released in the changelog.
Tests cover the JSON (.mcp.json / ~/.claude.json) and TOML (Codex) writers,
status detection, and the init/wizard flow.
---
Cargo.lock | 268 ++++++++++--------
Cargo.toml | 31 +-
crates/gather-step-cli/Cargo.toml | 1 +
crates/gather-step-cli/src/commands/init.rs | 16 +-
.../gather-step-cli/src/commands/setup_mcp.rs | 94 +++++-
crates/gather-step-cli/src/commands/status.rs | 8 +-
crates/gather-step-cli/tests/cli_commands.rs | 6 +-
crates/gather-step-cli/tests/cli_setup_mcp.rs | 87 +++++-
.../gather-step-cli/tests/cli_wizard_full.rs | 4 +-
crates/gather-step-mcp/Cargo.toml | 2 +-
website/bun.lock | 12 +-
website/package.json | 4 +-
.../src/components/landing/Benchmark.astro | 4 +-
website/src/components/landing/Hero.astro | 2 +-
website/src/components/landing/Topology.astro | 2 +-
website/src/content/docs/changelog.md | 27 ++
.../src/content/docs/guides/mcp-clients.md | 19 +-
17 files changed, 404 insertions(+), 183 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 8753421..0f3c5c9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -159,9 +159,9 @@ dependencies = [
[[package]]
name = "autocfg"
-version = "1.5.0"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "backtrace"
@@ -299,9 +299,9 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.20.2"
+version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytecheck"
@@ -515,9 +515,9 @@ dependencies = [
[[package]]
name = "compact_str"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
+checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab"
dependencies = [
"castaway",
"cfg-if",
@@ -879,9 +879,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "either"
-version = "1.15.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "encode_unicode"
@@ -1103,7 +1103,7 @@ dependencies = [
[[package]]
name = "gather-step"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"anyhow",
"blake3",
@@ -1138,13 +1138,14 @@ dependencies = [
"tokio",
"tokio-util",
"toml",
+ "toml_edit",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "gather-step-analysis"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"gather-step-core",
"gather-step-parser",
@@ -1159,7 +1160,7 @@ dependencies = [
[[package]]
name = "gather-step-bench"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"anyhow",
"chrono",
@@ -1189,7 +1190,7 @@ dependencies = [
[[package]]
name = "gather-step-core"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"bitcode",
"blake3",
@@ -1203,7 +1204,7 @@ dependencies = [
[[package]]
name = "gather-step-deploy"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"gather-step-core",
"pretty_assertions",
@@ -1215,7 +1216,7 @@ dependencies = [
[[package]]
name = "gather-step-git"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"blake3",
"gather-step-core",
@@ -1232,7 +1233,7 @@ dependencies = [
[[package]]
name = "gather-step-mcp"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"blake3",
"criterion",
@@ -1263,7 +1264,7 @@ dependencies = [
[[package]]
name = "gather-step-output"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"chrono",
"gather-step-analysis",
@@ -1275,7 +1276,7 @@ dependencies = [
[[package]]
name = "gather-step-parser"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"aho-corasick",
"blake3",
@@ -1317,7 +1318,7 @@ dependencies = [
[[package]]
name = "gather-step-storage"
-version = "4.1.1"
+version = "4.2.0"
dependencies = [
"bitcode",
"blake3",
@@ -1466,9 +1467,9 @@ dependencies = [
[[package]]
name = "gix-actor"
-version = "0.41.0"
+version = "0.41.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "272916673b83714734b15d4ef3c8b5f1ccddb15fea8ff548430b97c1ab7b7ed8"
+checksum = "8bc998b8f746dda8565450d08a63b792ced9165d8c27a1ed3f02799ec6a7820f"
dependencies = [
"bstr",
"gix-date",
@@ -1490,9 +1491,9 @@ dependencies = [
[[package]]
name = "gix-attributes"
-version = "0.33.0"
+version = "0.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe17c5a1c0b6f2ef1476aa1d3222ea50cdff67608016613a58bfc3e078046000"
+checksum = "8d43f12e246d3bf7ec624c8fc15ac4a4b62b7c4c6f586cb82be6c90bf84c9d02"
dependencies = [
"bstr",
"gix-glob",
@@ -1507,9 +1508,9 @@ dependencies = [
[[package]]
name = "gix-bitmap"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ecbfc77ec6852294e341ecc305a490b59f2813e6ca42d79efda5099dcab1894"
+checksum = "52ebef0c26ad305747649e727bbcd56a7b7910754eb7cea88f6dff6f93c51283"
dependencies = [
"gix-error",
]
@@ -1536,18 +1537,18 @@ dependencies = [
[[package]]
name = "gix-chunk"
-version = "0.7.1"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edf288be9b60fe7231de03771faa292be1493d84786f68727e33ad1f91764320"
+checksum = "9faee47943b638e58ddd5e275a4906ad3e4b6c8584f1d41bd18ab9032ec52afb"
dependencies = [
"gix-error",
]
[[package]]
name = "gix-command"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86335306511abe43d75c866d4b1f3d90932fe202edcd43e1314036333e7384d8"
+checksum = "00706d4fef135ef4b01680d5218c6ee40cda8baf697b864296cbc887d19118f6"
dependencies = [
"bstr",
"gix-path",
@@ -1558,9 +1559,9 @@ dependencies = [
[[package]]
name = "gix-commitgraph"
-version = "0.37.0"
+version = "0.37.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe3b5aa0f24e19028c261d229aeeedafcaaa52ebd71021cc15184620fc9d32eb"
+checksum = "7f675d0df484a7f6a47e64bd6f311af489d947c0323b0564f36d14f3d7762abb"
dependencies = [
"bstr",
"gix-chunk",
@@ -1590,9 +1591,9 @@ dependencies = [
[[package]]
name = "gix-config-value"
-version = "0.18.0"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13b39ed39ee4c10a3b157f9fb94bac8098d9f8e56201f0cf7dee6c187416c4b2"
+checksum = "ed42168329552f6c2e5df09665c104199d45d84bedb53683738a49b57fe1baab"
dependencies = [
"bitflags",
"bstr",
@@ -1603,9 +1604,9 @@ dependencies = [
[[package]]
name = "gix-credentials"
-version = "0.38.0"
+version = "0.38.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65ca11598b70811d7b16ff90945a6e57dfe521e85b744e51636965fe39cc8f60"
+checksum = "f40cd22f0dd71988be12d6e78b1709de2370e1957c5f107ff31e56caeba3745d"
dependencies = [
"bstr",
"gix-command",
@@ -1621,15 +1622,14 @@ dependencies = [
[[package]]
name = "gix-date"
-version = "0.15.3"
+version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b94cdae4eb4b0f4136e3d9b3aa2d2cd03cfb5bb9b636b31263aea2df86d41543"
+checksum = "a3ecab64a98bbac9f8e02990a9ea5e3c974a7d49b95f2bd70ad94ad22fa6b48c"
dependencies = [
"bstr",
"gix-error",
"itoa",
"jiff",
- "smallvec",
]
[[package]]
@@ -1693,18 +1693,18 @@ dependencies = [
[[package]]
name = "gix-error"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e207b971746ab724fccdfced2e4e19e854744611904a0195d3aa8fda8a110613"
+checksum = "e57831e199be480af90dcd7e459abed8a174c09ec9a6e2cc8f7ca6c54598b06b"
dependencies = [
"bstr",
]
[[package]]
name = "gix-features"
-version = "0.48.0"
+version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af375693ad5333d0a2c66b4c5b2cbe9ccc38e34f8e8bf24e4ae42c12307fdc4f"
+checksum = "1849ae154d38bc403185be14fa871e38e3c93ee606875d94e207fdb9fba52dbc"
dependencies = [
"bytes",
"bytesize",
@@ -1745,9 +1745,9 @@ dependencies = [
[[package]]
name = "gix-fs"
-version = "0.21.1"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e1967daac9848757c47c2aef0c57bcadc1a897347f559778249bf286a536c86"
+checksum = "6cdff46db8798e47e2f727d84b9379aac5add3dd3d9d0b07bb4d7d5d640771fe"
dependencies = [
"bstr",
"fastrand",
@@ -1759,9 +1759,9 @@ dependencies = [
[[package]]
name = "gix-glob"
-version = "0.26.0"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08bf29249a069bf2507f5964f80997f37b134d320ea348d66527726b9be2c38c"
+checksum = "d1fcb8ef5b16bcf874abe9b68d8abb3c0493c876d367ab824151f30a0f3f3756"
dependencies = [
"bitflags",
"bstr",
@@ -1771,9 +1771,9 @@ dependencies = [
[[package]]
name = "gix-hash"
-version = "0.25.0"
+version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf70d1e252337eed16360f8b8ebb71865ece58eab7954b39ce38b420de703d2"
+checksum = "cb0926d3819c837750b4e03c7754901e73f68b8c9b690753a6372a1bed4eedce"
dependencies = [
"faster-hex",
"gix-features",
@@ -1783,20 +1783,20 @@ dependencies = [
[[package]]
name = "gix-hashtable"
-version = "0.15.0"
+version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d33b455e07b3c16d3b2eeebc7b38d2dafcbf8a653de1138ef55d4c2a1fd0b08b"
+checksum = "b0e30b93eea8718baf7d8153fcb938e2926175bbf18097c09f1c01b6f0be0563"
dependencies = [
"gix-hash",
- "hashbrown 0.16.1",
+ "hashbrown 0.17.0",
"parking_lot",
]
[[package]]
name = "gix-ignore"
-version = "0.21.0"
+version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bb13fbbeeafee943e52b61fcc88dfddf6a452fcaf0c4d0cdc8f218fa25bbec5"
+checksum = "d491bab9bf2c9f341dc754f425c31d5d3f63aca615312167b82e1deeaca97d8d"
dependencies = [
"bstr",
"gix-glob",
@@ -1807,12 +1807,12 @@ dependencies = [
[[package]]
name = "gix-imara-diff"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39eb0623e15e4cb83c02ce6a959e48fadd1ae3b715b36b5acc01816e01388c82"
+checksum = "19753d40da53d0ec41604750eeb969097a90fb2d7f7992730d904541c04e2c19"
dependencies = [
"bstr",
- "hashbrown 0.16.1",
+ "hashbrown 0.17.0",
]
[[package]]
@@ -1845,9 +1845,9 @@ dependencies = [
[[package]]
name = "gix-lock"
-version = "23.0.0"
+version = "23.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09b3bc074e5723027b482dcd9ab99d95804a53742f6de812d0172fbba4a186c1"
+checksum = "65c9dedd9e90b0d47624d2ed241d394e09294118364e87b9b7e5f1fe755f3c2c"
dependencies = [
"gix-tempfile",
"gix-utils",
@@ -1856,9 +1856,9 @@ dependencies = [
[[package]]
name = "gix-mailmap"
-version = "0.33.0"
+version = "0.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "023d3a6561cbebe45b89e0764d48928ad970667076f16fa5889e6f86d8432086"
+checksum = "195fd20808055824531be2fd0d34136d900e5fbca3ffb0a3c07e8beeefb9c828"
dependencies = [
"bstr",
"gix-actor",
@@ -1968,9 +1968,9 @@ dependencies = [
[[package]]
name = "gix-packetline"
-version = "0.21.3"
+version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "362246df440ee691699f0664cbf7006a6ece477db6734222be95e4198e5656e6"
+checksum = "bb18337ba2830bb43367d1af43819c8c78f31337f079fc76d0f1f1750a173126"
dependencies = [
"bstr",
"faster-hex",
@@ -1980,9 +1980,9 @@ dependencies = [
[[package]]
name = "gix-path"
-version = "0.12.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "671a6059e8a4c1b7f406e24716499cefa3926e060876fb1959ef225efeee346e"
+checksum = "afa6ac14cd14939ea94a496ce7460daa6511c09f5b84757e9cfc6f9c8d0f93a6"
dependencies = [
"bstr",
"gix-trace",
@@ -1992,9 +1992,9 @@ dependencies = [
[[package]]
name = "gix-pathspec"
-version = "0.18.0"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a84a4f083dd70fb49f4377e13afa6d90df2daaa1c705c49d6ff1331fc7e8855"
+checksum = "3050783b41ee11511e1e8fb35623df81806194f4030395f14f48ea37c2798c9f"
dependencies = [
"bitflags",
"bstr",
@@ -2007,9 +2007,9 @@ dependencies = [
[[package]]
name = "gix-prompt"
-version = "0.15.0"
+version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e041a626c64cb69e4117fcdf80da8d0e454fba3b1f420412792d191f52251aee"
+checksum = "3ee604d7746080ae7e1023bf47204bcc2c5f307bfbe2306a3c90b1bfd1a2c6d8"
dependencies = [
"gix-command",
"gix-config-value",
@@ -2039,9 +2039,9 @@ dependencies = [
[[package]]
name = "gix-quote"
-version = "0.7.1"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e97b73791a64bc0fa7dd2c5b3e551136115f97750b876ed1c952c7a7dbaf8be"
+checksum = "a6e541fc33cc2b783b7979040d445a0c86a2eca747c8faea4ca84230d06ae6ef"
dependencies = [
"bstr",
"gix-error",
@@ -2121,9 +2121,9 @@ dependencies = [
[[package]]
name = "gix-sec"
-version = "0.14.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5a3a2d3e504a238136751e646a6c028252286a0ea64ea9974bf0498633407c6"
+checksum = "ab8519976e4c7e486270740a5400369f37940779b80bd1377d94cfa1125d01b3"
dependencies = [
"bitflags",
"gix-path",
@@ -2133,9 +2133,9 @@ dependencies = [
[[package]]
name = "gix-shallow"
-version = "0.12.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29187305521bfacf4aefd284ab28dbfa9fb74abd39a5e63dd313b1baa5808c27"
+checksum = "a292fc2fe548c5dfa575479d16b445b0ddf1dd2f56f1fec6aed386f82553cd97"
dependencies = [
"bstr",
"gix-hash",
@@ -2184,9 +2184,9 @@ dependencies = [
[[package]]
name = "gix-tempfile"
-version = "23.0.0"
+version = "23.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "691ea1e31435c7e7d4d04705ec9d1c0d9482c46b2acf512bc723939d8f0af7fb"
+checksum = "27850097e1ff9515f46a0dad0f5f9c9d020e972727772dabab9450690c4adb22"
dependencies = [
"dashmap",
"gix-fs",
@@ -2199,15 +2199,15 @@ dependencies = [
[[package]]
name = "gix-trace"
-version = "0.1.19"
+version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f23569e55f2ffaf958617353b9734a7d52a7c19c439eeaa5e3efc217fd2270e"
+checksum = "44dc45eae785c0eb14173e0f152e6e224dcf4d45b6a6999a3aed22af541ad678"
[[package]]
name = "gix-transport"
-version = "0.57.0"
+version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffd6a5c676b92d4ead5f5a2b2935024415dec69edc997b6090ca9cac010a3018"
+checksum = "7cd0e34995b1aab0fa8dff2af8db726a0bfad3e119c89302604463264046e7ff"
dependencies = [
"bstr",
"gix-command",
@@ -2238,9 +2238,9 @@ dependencies = [
[[package]]
name = "gix-url"
-version = "0.36.0"
+version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35842d099e813f6f6bba529e88d4670572149c3df79b7a412952259887721ece"
+checksum = "65bb01ec69d55e82ccb7a19e264501ead4e6aac38463a8cebfdd81e22bb67ab2"
dependencies = [
"bstr",
"gix-path",
@@ -2250,9 +2250,9 @@ dependencies = [
[[package]]
name = "gix-utils"
-version = "0.3.2"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e477b4f07a6e8da4ba791c53c858102959703c60d70f199932010d5b94adb2c"
+checksum = "66c50966184123caf580ffa64e28031a878597f1c7fceb8fe19566c38eb1b771"
dependencies = [
"bstr",
"fastrand",
@@ -2261,9 +2261,9 @@ dependencies = [
[[package]]
name = "gix-validate"
-version = "0.11.1"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e26ac2602b43eadfdca0560b81d3341944162a3c9f64ccdeef8fc501ad80dad5"
+checksum = "7bc6fc771c4063ba7cd2f47b91fb6076251c6a823b64b7fe7b8874b0fe4afae3"
dependencies = [
"bstr",
]
@@ -2324,9 +2324,9 @@ dependencies = [
[[package]]
name = "glam"
-version = "0.32.1"
+version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f70749695b063ecbf6b62949ccccde2e733ec3ecbbd71d467dca4e5c6c97cca0"
+checksum = "8fb167719045debebe9f532320accc7b5c993c5a3b813f5696a11d5ca7bdc57b"
[[package]]
name = "globset"
@@ -2624,9 +2624,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "jiff"
-version = "0.2.24"
+version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d"
+checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102"
dependencies = [
"jiff-static",
"jiff-tzdb-platform",
@@ -2634,14 +2634,14 @@ dependencies = [
"portable-atomic",
"portable-atomic-util",
"serde_core",
- "windows-sys 0.61.2",
+ "windows-link",
]
[[package]]
name = "jiff-static"
-version = "0.2.24"
+version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7"
+checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47"
dependencies = [
"proc-macro2",
"quote",
@@ -2675,9 +2675,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.98"
+version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
+checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
@@ -2761,18 +2761,18 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libmimalloc-sys"
-version = "0.1.47"
+version = "0.1.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6"
+checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
dependencies = [
"cc",
]
[[package]]
name = "libredox"
-version = "0.1.16"
+version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
+checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@@ -2820,9 +2820,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.29"
+version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "lru"
@@ -2879,9 +2879,9 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.8.0"
+version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "memmap2"
@@ -2925,9 +2925,9 @@ checksum = "c505b3e17ed6b70a7ed2e67fbb2c560ee327353556120d6e72f5232b6880d536"
[[package]]
name = "mio"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
+checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
dependencies = [
"libc",
"log",
@@ -3385,9 +3385,9 @@ dependencies = [
[[package]]
name = "pastey"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5a797f0e07bdf071d15742978fc3128ec6c22891c31a3a931513263904c982a"
+checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4"
[[package]]
name = "percent-encoding"
@@ -4145,9 +4145,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.149"
+version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"indexmap",
"itoa",
@@ -4318,9 +4318,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "socket2"
-version = "0.6.3"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
+checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
dependencies = [
"libc",
"windows-sys 0.61.2",
@@ -4328,9 +4328,9 @@ dependencies = [
[[package]]
name = "sqlite-wasm-rs"
-version = "0.5.4"
+version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdd578e94101503d97e2b286bbf8db2135035ca24b2ce4cbf3f9e2fb2bbf1eee"
+checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75"
dependencies = [
"cc",
"js-sys",
@@ -4740,6 +4740,19 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "toml_edit"
+version = "0.25.12+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
[[package]]
name = "toml_parser"
version = "1.1.2+spec-1.1.0"
@@ -5122,9 +5135,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
-version = "0.2.121"
+version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
+checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
@@ -5135,9 +5148,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.121"
+version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
+checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -5145,9 +5158,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.121"
+version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
+checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -5158,9 +5171,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.121"
+version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
+checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
@@ -5201,9 +5214,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.98"
+version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
+checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -5396,6 +5409,9 @@ name = "winnow"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
+dependencies = [
+ "memchr",
+]
[[package]]
name = "wit-bindgen"
@@ -5505,18 +5521,18 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "zerocopy"
-version = "0.8.48"
+version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
+checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.48"
+version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
+checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index e3d0244..735b8fb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,7 +14,7 @@ members = [
]
[workspace.package]
-version = "4.1.1"
+version = "4.2.0"
authors = ["JJ Adonis"]
edition = "2024"
rust-version = "1.94.1"
@@ -24,15 +24,15 @@ homepage = "https://github.com/thedoublejay/gather-step"
description = "High-performance multi-repo codebase intelligence engine"
[workspace.dependencies]
-gather-step = { path = "crates/gather-step-cli", version = "4.1.1" }
-gather-step-analysis = { path = "crates/gather-step-analysis", version = "4.1.1" }
-gather-step-core = { path = "crates/gather-step-core", version = "4.1.1" }
-gather-step-deploy = { path = "crates/gather-step-deploy", version = "4.1.1" }
-gather-step-git = { path = "crates/gather-step-git", version = "4.1.1" }
-gather-step-mcp = { path = "crates/gather-step-mcp", version = "4.1.1" }
-gather-step-output = { path = "crates/gather-step-output", version = "4.1.1" }
-gather-step-parser = { path = "crates/gather-step-parser", version = "4.1.1" }
-gather-step-storage = { path = "crates/gather-step-storage", version = "4.1.1" }
+gather-step = { path = "crates/gather-step-cli", version = "4.2.0" }
+gather-step-analysis = { path = "crates/gather-step-analysis", version = "4.2.0" }
+gather-step-core = { path = "crates/gather-step-core", version = "4.2.0" }
+gather-step-deploy = { path = "crates/gather-step-deploy", version = "4.2.0" }
+gather-step-git = { path = "crates/gather-step-git", version = "4.2.0" }
+gather-step-mcp = { path = "crates/gather-step-mcp", version = "4.2.0" }
+gather-step-output = { path = "crates/gather-step-output", version = "4.2.0" }
+gather-step-parser = { path = "crates/gather-step-parser", version = "4.2.0" }
+gather-step-storage = { path = "crates/gather-step-storage", version = "4.2.0" }
tree-sitter = "=0.26.8"
tree-sitter-typescript = "0.23.2"
@@ -56,9 +56,10 @@ console = "0.16.3"
comfy-table = "7.2.2"
chrono = { version = "0.4.44", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] }
-serde_json = "1.0.149"
+serde_json = "1.0.150"
serde_norway = "0.9.42"
toml = "1.1.2"
+toml_edit = "0.25.12"
bitcode = "0.6.9"
blake3 = "1.8.5"
dirs = "6"
@@ -69,19 +70,19 @@ globset = "0.4.18"
rustc-hash = "2.1.2"
hashbrown = "=0.17.0"
parking_lot = "=0.12.5"
-tokio = { version = "1.52.2", features = ["macros", "rt-multi-thread", "sync", "time", "signal", "net", "io-util"] }
+tokio = { version = "1.52.3", features = ["macros", "rt-multi-thread", "sync", "time", "signal", "net", "io-util"] }
tokio-util = "0.7.18"
notify = "=9.0.0-rc.4"
gix = { version = "0.83", default-features = true }
regex = "1.12.3"
simdutf8 = "=0.1.5"
-similar = "3.1.0"
+similar = "3.1.1"
lru = "=0.18.0"
-quick_cache = "0.6.21"
+quick_cache = "0.6.22"
smallvec = { version = "=1.15.1", features = ["serde"] }
camino = "1.2.2"
aho-corasick = "1.1.4"
-memchr = "2.8.0"
+memchr = "2.8.1"
libc = "0.2"
dhat = "=0.3.3"
regex-automata = { version = "0.4.14", default-features = false, features = ["std", "syntax", "meta", "nfa", "dfa", "hybrid", "perf", "unicode"] }
diff --git a/crates/gather-step-cli/Cargo.toml b/crates/gather-step-cli/Cargo.toml
index e86c8f6..a641bf5 100644
--- a/crates/gather-step-cli/Cargo.toml
+++ b/crates/gather-step-cli/Cargo.toml
@@ -46,6 +46,7 @@ serde.workspace = true
thiserror.workspace = true
serde_json.workspace = true
serde_norway.workspace = true
+toml_edit.workspace = true
tokio.workspace = true
tokio-util.workspace = true
tracing.workspace = true
diff --git a/crates/gather-step-cli/src/commands/init.rs b/crates/gather-step-cli/src/commands/init.rs
index a5fdcac..00033e8 100644
--- a/crates/gather-step-cli/src/commands/init.rs
+++ b/crates/gather-step-cli/src/commands/init.rs
@@ -107,7 +107,13 @@ async fn run_non_interactive(app: &AppContext, args: InitArgs) -> Result<()> {
generate::run_summary_pair(app)?;
}
if let Some(scope) = args.setup_mcp {
- setup_mcp::run(app, setup_mcp::SetupMcpArgs { scope })?;
+ setup_mcp::run(
+ app,
+ setup_mcp::SetupMcpArgs {
+ client: setup_mcp::McpClient::Claude,
+ scope,
+ },
+ )?;
}
if args.watch && !args.no_watch {
emit_setup_complete(&output);
@@ -193,7 +199,13 @@ async fn run_wizard(app: &AppContext, args: InitArgs) -> Result<()> {
generate::run_summary_pair(app)?;
}
if let Some(scope) = scope {
- setup_mcp::run(app, setup_mcp::SetupMcpArgs { scope })?;
+ setup_mcp::run(
+ app,
+ setup_mcp::SetupMcpArgs {
+ client: setup_mcp::McpClient::Claude,
+ scope,
+ },
+ )?;
}
emit_setup_complete(&output);
if do_watch {
diff --git a/crates/gather-step-cli/src/commands/setup_mcp.rs b/crates/gather-step-cli/src/commands/setup_mcp.rs
index 72b459d..be753d6 100644
--- a/crates/gather-step-cli/src/commands/setup_mcp.rs
+++ b/crates/gather-step-cli/src/commands/setup_mcp.rs
@@ -7,6 +7,7 @@ use anyhow::{Context, Result};
use clap::{Args, ValueEnum};
use serde::Serialize;
use serde_json::{Map, Value, json};
+use toml_edit::{Array, DocumentMut, Item, Table, value};
use crate::app::AppContext;
@@ -17,8 +18,19 @@ pub enum McpScope {
Local,
}
+#[derive(Debug, Clone, Copy, ValueEnum, Serialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum McpClient {
+ Claude,
+ Codex,
+}
+
#[derive(Debug, Clone, Copy, Args)]
pub struct SetupMcpArgs {
+ /// MCP client to configure.
+ #[arg(long, value_enum, default_value = "claude")]
+ pub client: McpClient,
+ /// Configuration scope. Ignored for Codex, whose config is always global.
#[arg(long, value_enum, default_value = "local")]
pub scope: McpScope,
}
@@ -26,6 +38,7 @@ pub struct SetupMcpArgs {
#[derive(Debug, Serialize)]
struct SetupMcpOutput {
event: &'static str,
+ client: McpClient,
scope: McpScope,
settings_path: String,
path_resolution: PathResolution,
@@ -41,22 +54,22 @@ enum PathResolution {
}
pub fn run(app: &AppContext, args: SetupMcpArgs) -> Result<()> {
- let settings_path = match args.scope {
- McpScope::Local => app.workspace_path.join(".claude/settings.json"),
- McpScope::Global => home_dir()
- .context("cannot resolve HOME")?
- .join(".claude/settings.json"),
- };
+ let settings_path = resolve_settings_path(args.client, args.scope, &app.workspace_path)?;
let command_path = find_command_on_path("gather-step");
let path_resolution = if command_path.is_some() {
PathResolution::Ok
} else {
PathResolution::NotFound
};
- write_settings(&settings_path, &app.workspace_path)?;
+
+ match args.client {
+ McpClient::Claude => write_settings(&settings_path, &app.workspace_path)?,
+ McpClient::Codex => write_codex_config(&settings_path, &app.workspace_path)?,
+ }
let payload = SetupMcpOutput {
event: "setup_mcp_completed",
+ client: args.client,
scope: args.scope,
settings_path: settings_path.display().to_string(),
path_resolution,
@@ -73,6 +86,28 @@ pub fn run(app: &AppContext, args: SetupMcpArgs) -> Result<()> {
Ok(())
}
+/// Resolve the config file the chosen client actually reads MCP server
+/// definitions from.
+///
+/// Claude Code does not read `mcpServers` out of `settings.json`: project scope
+/// lives in `.mcp.json` at the workspace root and user scope in `~/.claude.json`.
+/// Codex reads a single global `~/.codex/config.toml`, so scope does not apply.
+fn resolve_settings_path(client: McpClient, scope: McpScope, workspace: &Path) -> Result {
+ match client {
+ McpClient::Claude => match scope {
+ McpScope::Local => Ok(workspace.join(".mcp.json")),
+ McpScope::Global => Ok(home_dir()
+ .context("cannot resolve HOME")?
+ .join(".claude.json")),
+ },
+ McpClient::Codex => Ok(home_dir()
+ .context("cannot resolve HOME")?
+ .join(".codex/config.toml")),
+ }
+}
+
+/// Merge a workspace-pinned `gather-step` entry into a JSON `mcpServers` map,
+/// preserving every other key. Used for Claude's `.mcp.json` and `~/.claude.json`.
pub fn write_settings(path: &Path, workspace: &Path) -> Result<()> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
@@ -112,6 +147,51 @@ pub fn write_settings(path: &Path, workspace: &Path) -> Result<()> {
Ok(())
}
+/// Merge a workspace-pinned `gather-step` entry into a Codex `config.toml`,
+/// preserving existing servers, other tables, comments, and formatting.
+pub fn write_codex_config(path: &Path, workspace: &Path) -> Result<()> {
+ if let Some(parent) = path.parent() {
+ std::fs::create_dir_all(parent)
+ .with_context(|| format!("creating {}", parent.display()))?;
+ }
+
+ let mut doc = if path.exists() {
+ let body =
+ std::fs::read_to_string(path).with_context(|| format!("reading {}", path.display()))?;
+ body.parse::()
+ .with_context(|| format!("parsing {}", path.display()))?
+ } else {
+ DocumentMut::new()
+ };
+
+ let workspace_str = workspace
+ .to_str()
+ .context("workspace path is not valid UTF-8")?;
+ let mut args = Array::new();
+ args.push("--workspace");
+ args.push(workspace_str);
+ args.push("serve");
+
+ let mut server = Table::new();
+ server.insert("command", value("gather-step"));
+ server.insert("args", value(args));
+
+ // Keep `mcp_servers` an implicit table so the entry renders as the
+ // idiomatic `[mcp_servers.gather-step]` section rather than an inline table.
+ if doc.get("mcp_servers").is_none() {
+ let mut servers = Table::new();
+ servers.set_implicit(true);
+ doc.insert("mcp_servers", Item::Table(servers));
+ }
+ let servers = doc["mcp_servers"]
+ .as_table_mut()
+ .context("mcp_servers is not a table")?;
+ servers.insert("gather-step", Item::Table(server));
+
+ std::fs::write(path, doc.to_string()).with_context(|| format!("writing {}", path.display()))?;
+ Ok(())
+}
+
fn home_dir() -> Option {
env::var_os("HOME").map(PathBuf::from)
}
diff --git a/crates/gather-step-cli/src/commands/status.rs b/crates/gather-step-cli/src/commands/status.rs
index 92e4727..38d9ffe 100644
--- a/crates/gather-step-cli/src/commands/status.rs
+++ b/crates/gather-step-cli/src/commands/status.rs
@@ -110,13 +110,13 @@ fn mcp_state(app: &AppContext) -> &'static str {
}
fn mcp_state_with_home(app: &AppContext, home: Option<&std::ffi::OsStr>) -> &'static str {
- let local = app.workspace_path.join(".claude/settings.json");
+ let local = app.workspace_path.join(".mcp.json");
if json_has_gather_step(&local) {
return "configured: local";
}
if let Some(home) = home {
- let global = std::path::PathBuf::from(home).join(".claude/settings.json");
+ let global = std::path::PathBuf::from(home).join(".claude.json");
if json_has_gather_step(&global) {
return "configured: global";
}
@@ -418,7 +418,7 @@ mod tests {
#[test]
fn mcp_state_reports_local_configuration_first() {
let temp = tempfile::tempdir().expect("temp dir");
- write_settings(&temp.path().join(".claude/settings.json"));
+ write_settings(&temp.path().join(".mcp.json"));
assert_eq!(
mcp_state_with_home(&app_for(temp.path()), None),
@@ -430,7 +430,7 @@ mod tests {
fn mcp_state_reports_global_configuration() {
let workspace = tempfile::tempdir().expect("workspace");
let home = tempfile::tempdir().expect("home");
- write_settings(&home.path().join(".claude/settings.json"));
+ write_settings(&home.path().join(".claude.json"));
assert_eq!(
mcp_state_with_home(&app_for(workspace.path()), Some(home.path().as_os_str())),
diff --git a/crates/gather-step-cli/tests/cli_commands.rs b/crates/gather-step-cli/tests/cli_commands.rs
index 2e4bac1..f38a90a 100644
--- a/crates/gather-step-cli/tests/cli_commands.rs
+++ b/crates/gather-step-cli/tests/cli_commands.rs
@@ -119,7 +119,7 @@ fn setup_mcp_local_writes_workspace_settings() {
let output = run_ok(temp.path(), &["setup-mcp", "--scope", "local"]);
let stdout = String::from_utf8_lossy(&output.stdout);
- let settings_path = temp.path().join(".claude/settings.json");
+ let settings_path = temp.path().join(".mcp.json");
let settings = fs::read_to_string(&settings_path).expect("settings file should be written");
let value: Value = serde_json::from_str(&settings).expect("settings json");
@@ -174,7 +174,7 @@ fn setup_mcp_json_reports_missing_path_resolution() {
}
#[test]
-fn setup_mcp_global_writes_home_claude_settings() {
+fn setup_mcp_global_writes_home_claude_json() {
let workspace = TempDir::new("setup-mcp-global-workspace");
let home = TempDir::new("setup-mcp-global-home");
@@ -194,7 +194,7 @@ fn setup_mcp_global_writes_home_claude_settings() {
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
- let settings_path = home.path().join(".claude/settings.json");
+ let settings_path = home.path().join(".claude.json");
let settings = fs::read_to_string(&settings_path).expect("settings file should be written");
let value: Value = serde_json::from_str(&settings).expect("settings json");
assert_eq!(value["mcpServers"]["gather-step"]["command"], "gather-step");
diff --git a/crates/gather-step-cli/tests/cli_setup_mcp.rs b/crates/gather-step-cli/tests/cli_setup_mcp.rs
index fc7cb4b..7600b42 100644
--- a/crates/gather-step-cli/tests/cli_setup_mcp.rs
+++ b/crates/gather-step-cli/tests/cli_setup_mcp.rs
@@ -1,10 +1,10 @@
-use gather_step::commands::setup_mcp::write_settings;
+use gather_step::commands::setup_mcp::{write_codex_config, write_settings};
#[test]
-fn writes_workspace_pinned_block_to_local_settings() {
+fn writes_workspace_pinned_block_to_mcp_json() {
let temp = tempfile::tempdir().expect("temp dir");
let workspace = temp.path().to_path_buf();
- let settings_path = workspace.join(".claude/settings.json");
+ let settings_path = workspace.join(".mcp.json");
write_settings(&settings_path, &workspace).expect("settings should write");
@@ -21,7 +21,7 @@ fn writes_workspace_pinned_block_to_local_settings() {
fn idempotent_merge_preserves_other_keys() {
let temp = tempfile::tempdir().expect("temp dir");
let workspace = temp.path().to_path_buf();
- let settings_path = workspace.join(".claude/settings.json");
+ let settings_path = workspace.join(".mcp.json");
std::fs::create_dir_all(settings_path.parent().expect("settings parent"))
.expect("settings parent");
std::fs::write(
@@ -44,7 +44,7 @@ fn idempotent_merge_preserves_other_keys() {
fn malformed_existing_settings_json_returns_error_and_preserves_file() {
let temp = tempfile::tempdir().expect("temp dir");
let workspace = temp.path().to_path_buf();
- let settings_path = workspace.join(".claude/settings.json");
+ let settings_path = workspace.join(".mcp.json");
std::fs::create_dir_all(settings_path.parent().expect("settings parent"))
.expect("settings parent");
let original = "{not valid json";
@@ -63,7 +63,7 @@ fn malformed_existing_settings_json_returns_error_and_preserves_file() {
fn existing_gather_step_entry_is_replaced_not_merged() {
let temp = tempfile::tempdir().expect("temp dir");
let workspace = temp.path().to_path_buf();
- let settings_path = workspace.join(".claude/settings.json");
+ let settings_path = workspace.join(".mcp.json");
std::fs::create_dir_all(settings_path.parent().expect("settings parent"))
.expect("settings parent");
std::fs::write(
@@ -89,7 +89,7 @@ fn existing_gather_step_entry_is_replaced_not_merged() {
fn non_object_mcp_servers_returns_error_and_preserves_file() {
let temp = tempfile::tempdir().expect("temp dir");
let workspace = temp.path().to_path_buf();
- let settings_path = workspace.join(".claude/settings.json");
+ let settings_path = workspace.join(".mcp.json");
std::fs::create_dir_all(settings_path.parent().expect("settings parent"))
.expect("settings parent");
let original = r#"{"mcpServers":[]}"#;
@@ -103,3 +103,76 @@ fn non_object_mcp_servers_returns_error_and_preserves_file() {
original
);
}
+
+#[test]
+fn writes_codex_server_block_to_config_toml() {
+ let temp = tempfile::tempdir().expect("temp dir");
+ let workspace = temp.path().to_path_buf();
+ let config_path = workspace.join(".codex/config.toml");
+
+ write_codex_config(&config_path, &workspace).expect("codex config should write");
+
+ let body = std::fs::read_to_string(&config_path).expect("config body");
+ let value: toml::Value = toml::from_str(&body).expect("config toml");
+ assert_eq!(
+ value["mcp_servers"]["gather-step"]["command"]
+ .as_str()
+ .unwrap(),
+ "gather-step"
+ );
+ let args = value["mcp_servers"]["gather-step"]["args"]
+ .as_array()
+ .expect("args array");
+ let args: Vec<&str> = args.iter().map(|v| v.as_str().unwrap()).collect();
+ assert_eq!(args, ["--workspace", workspace.to_str().unwrap(), "serve"]);
+}
+
+#[test]
+fn codex_merge_preserves_other_servers_and_comments() {
+ let temp = tempfile::tempdir().expect("temp dir");
+ let workspace = temp.path().to_path_buf();
+ let config_path = workspace.join(".codex/config.toml");
+ std::fs::create_dir_all(config_path.parent().expect("config parent")).expect("config parent");
+ std::fs::write(
+ &config_path,
+ "# top comment\nmodel = \"o3\"\n\n[mcp_servers.other]\ncommand = \"x\"\n",
+ )
+ .expect("seed config");
+
+ write_codex_config(&config_path, &workspace).expect("first write");
+ write_codex_config(&config_path, &workspace).expect("second write");
+
+ let body = std::fs::read_to_string(&config_path).expect("config body");
+ assert!(body.contains("# top comment"));
+ let value: toml::Value = toml::from_str(&body).expect("config toml");
+ assert_eq!(value["model"].as_str().unwrap(), "o3");
+ assert_eq!(
+ value["mcp_servers"]["other"]["command"].as_str().unwrap(),
+ "x"
+ );
+ assert_eq!(
+ value["mcp_servers"]["gather-step"]["command"]
+ .as_str()
+ .unwrap(),
+ "gather-step"
+ );
+}
+
+#[test]
+fn codex_non_table_mcp_servers_returns_error_and_preserves_file() {
+ let temp = tempfile::tempdir().expect("temp dir");
+ let workspace = temp.path().to_path_buf();
+ let config_path = workspace.join(".codex/config.toml");
+ std::fs::create_dir_all(config_path.parent().expect("config parent")).expect("config parent");
+ let original = "mcp_servers = 1\n";
+ std::fs::write(&config_path, original).expect("seed config");
+
+ let error =
+ write_codex_config(&config_path, &workspace).expect_err("non-table mcp_servers errors");
+
+ assert!(error.to_string().contains("mcp_servers is not a table"));
+ assert_eq!(
+ std::fs::read_to_string(&config_path).expect("config body"),
+ original
+ );
+}
diff --git a/crates/gather-step-cli/tests/cli_wizard_full.rs b/crates/gather-step-cli/tests/cli_wizard_full.rs
index 715654a..e20e877 100644
--- a/crates/gather-step-cli/tests/cli_wizard_full.rs
+++ b/crates/gather-step-cli/tests/cli_wizard_full.rs
@@ -72,7 +72,7 @@ fn init_flag_overrides_run_full_setup_without_prompting() {
.join(".agents/skills/gather-step-context/SKILL.md")
.exists()
);
- assert!(tmp.path().join(".claude/settings.json").exists());
+ assert!(tmp.path().join(".mcp.json").exists());
}
#[test]
@@ -140,7 +140,7 @@ fn init_flag_overrides_keep_setup_mcp_idempotent() {
);
}
- let settings = fs::read_to_string(tmp.path().join(".claude/settings.json")).expect("settings");
+ let settings = fs::read_to_string(tmp.path().join(".mcp.json")).expect("settings");
let value: serde_json::Value = serde_json::from_str(&settings).expect("settings json");
assert_eq!(
value["mcpServers"]
diff --git a/crates/gather-step-mcp/Cargo.toml b/crates/gather-step-mcp/Cargo.toml
index d2206ee..74b5948 100644
--- a/crates/gather-step-mcp/Cargo.toml
+++ b/crates/gather-step-mcp/Cargo.toml
@@ -22,7 +22,7 @@ gather-step-git.workspace = true
gather-step-output.workspace = true
gather-step-parser.workspace = true
gather-step-storage.workspace = true
-rmcp = { version = "1.5.0", features = ["client", "server", "macros", "transport-io"] }
+rmcp = { version = "1.7.0", features = ["client", "server", "macros", "transport-io"] }
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
diff --git a/website/bun.lock b/website/bun.lock
index 4f8073a..a20c36a 100644
--- a/website/bun.lock
+++ b/website/bun.lock
@@ -5,15 +5,15 @@
"": {
"name": "gather-step-website",
"dependencies": {
- "@astrojs/starlight": "^0.39.1",
- "astro": "^6.3.1",
+ "@astrojs/starlight": "^0.39.2",
+ "astro": "^6.3.5",
},
},
},
"packages": {
"@astrojs/compiler": ["@astrojs/compiler@4.0.0", "", {}, "sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA=="],
- "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.9.1", "", { "dependencies": { "picomatch": "^4.0.4" } }, "sha512-1pWuARqYom/TzuU3+0ZugsTrKlUydWKuULmDqSMTuonY+9IRDUEGKX/8PXQ1nBxRq3w85uGtd9q9SXfqEldMIQ=="],
+ "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.10.0", "", { "dependencies": { "@types/hast": "^3.0.4", "@types/mdast": "^4.0.4", "js-yaml": "^4.1.1", "picomatch": "^4.0.4", "retext-smartypants": "^6.2.0", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "unified": "^11.0.5" } }, "sha512-Ry2R3VPeIN4uPCSA4xQc+e+vsJXkalKpEbDc07hV+a/o5Bs2N/s/uDcPJH/05L19DKh9tAy7e6JM3YZ6Cxfezw=="],
"@astrojs/markdown-remark": ["@astrojs/markdown-remark@7.1.2", "", { "dependencies": { "@astrojs/internal-helpers": "0.9.1", "@astrojs/prism": "4.0.2", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "retext-smartypants": "^6.2.0", "shiki": "^4.0.0", "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.1.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-caXZ4Dc2St2dW8luEg22GlP0gupLdztCTQE4EzZOxW1pqWXz9mbeJEuHUkgDYcKWW8tjIHkydYDhWLVoxJ327Q=="],
@@ -287,7 +287,7 @@
"astring": ["astring@1.9.0", "", { "bin": "bin/astring" }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
- "astro": ["astro@6.3.5", "", { "dependencies": { "@astrojs/compiler": "^4.0.0", "@astrojs/internal-helpers": "0.9.1", "@astrojs/markdown-remark": "7.1.2", "@astrojs/telemetry": "3.3.2", "@capsizecss/unpack": "^4.0.0", "@clack/prompts": "^1.1.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", "cookie": "^1.1.1", "devalue": "^5.6.3", "diff": "^8.0.3", "dset": "^3.1.4", "es-module-lexer": "^2.0.0", "esbuild": "^0.27.3", "flattie": "^1.1.1", "fontace": "~0.4.1", "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "obug": "^2.1.1", "p-limit": "^7.3.0", "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.4", "rehype": "^13.0.2", "semver": "^7.7.4", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "svgo": "^4.0.1", "tinyclip": "^0.1.12", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "ultrahtml": "^1.6.0", "unifont": "~0.7.4", "unist-util-visit": "^5.1.0", "unstorage": "^1.17.5", "vfile": "^6.0.3", "vite": "^7.3.2", "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", "zod": "^4.3.6" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "./bin/astro.mjs" } }, "sha512-gU+4KedkbTuVgz7YoVAN+9Ftnq0GaYwejxK2NbqDzB0M9dWd0f3kXZBuaM9hzbchRFoRAJfJjFtdX9LK6Ir7ZA=="],
+ "astro": ["astro@6.4.2", "", { "dependencies": { "@astrojs/compiler": "^4.0.0", "@astrojs/internal-helpers": "0.10.0", "@astrojs/markdown-remark": "7.2.0", "@astrojs/telemetry": "3.3.2", "@capsizecss/unpack": "^4.0.0", "@clack/prompts": "^1.1.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", "cookie": "^1.1.1", "devalue": "^5.6.3", "diff": "^8.0.3", "dset": "^3.1.4", "es-module-lexer": "^2.0.0", "esbuild": "^0.27.3", "flattie": "^1.1.1", "fontace": "~0.4.1", "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "obug": "^2.1.1", "p-limit": "^7.3.0", "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.4", "rehype": "^13.0.2", "semver": "^7.7.4", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "svgo": "^4.0.1", "tinyclip": "^0.1.12", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "ultrahtml": "^1.6.0", "unifont": "~0.7.4", "unist-util-visit": "^5.1.0", "unstorage": "^1.17.5", "vfile": "^6.0.3", "vite": "^7.3.2", "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", "zod": "^4.3.6" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "./bin/astro.mjs" } }, "sha512-8H89CH2dKL5SCU99OCqdU9BGjmPkSJqaPurywj5XMo7eMFGUFD3vsNhdEKnEh4mK4LgGje3/QDTTSIIGst0G0Q=="],
"astro-expressive-code": ["astro-expressive-code@0.42.0", "", { "dependencies": { "rehype-expressive-code": "^0.42.0" }, "peerDependencies": { "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta" } }, "sha512-aiTePi2Cn0mJPYWZSzP1GcxCinX9mNtJyCCshVVPSg1yRwM7ADvFJOx0FnS440M9t65hp8JH//dc2qr22Bm4ag=="],
@@ -847,12 +847,16 @@
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
+ "@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.9.1", "", { "dependencies": { "picomatch": "^4.0.4" } }, "sha512-1pWuARqYom/TzuU3+0ZugsTrKlUydWKuULmDqSMTuonY+9IRDUEGKX/8PXQ1nBxRq3w85uGtd9q9SXfqEldMIQ=="],
+
"@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@7.1.1", "", { "dependencies": { "@astrojs/internal-helpers": "0.9.0", "@astrojs/prism": "4.0.1", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "retext-smartypants": "^6.2.0", "shiki": "^4.0.0", "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.1.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-C6e9BnLGlbdv6bV8MYGeHpHxsUHrCrB4OuRLqi5LI7oiBVcBcqfUN06zpwFQdHgV48QCCrMmLpyqBr7VqC+swA=="],
"@mdx-js/mdx/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
"anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
+ "astro/@astrojs/markdown-remark": ["@astrojs/markdown-remark@7.2.0", "", { "dependencies": { "@astrojs/internal-helpers": "0.10.0", "@astrojs/prism": "4.0.2", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.1.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-+YxmVQu1Bd+MFfSzjq1rOJvD9+nIOJzz5YIIhdIH01RrxRkKbyKoEgyIqP3yv51MhzMDgd79QaPv+kCVPT8vHw=="],
+
"csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
"dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
diff --git a/website/package.json b/website/package.json
index 2f40aa4..2019834 100644
--- a/website/package.json
+++ b/website/package.json
@@ -1,7 +1,7 @@
{
"name": "gather-step-website",
"type": "module",
- "version": "4.1.1",
+ "version": "4.2.0",
"private": true,
"packageManager": "bun@1.3.12",
"scripts": {
@@ -13,6 +13,6 @@
},
"dependencies": {
"@astrojs/starlight": "^0.39.2",
- "astro": "^6.3.5"
+ "astro": "^6.4.2"
}
}
diff --git a/website/src/components/landing/Benchmark.astro b/website/src/components/landing/Benchmark.astro
index efe3391..e79383b 100644
--- a/website/src/components/landing/Benchmark.astro
+++ b/website/src/components/landing/Benchmark.astro
@@ -69,7 +69,7 @@ const speedup = (totalManual / totalGatherStep).toFixed(1);
on the same machine; medians of three runs.
- v4.1.1 · 2026-05-20
+ v4.2.0 · 2026-05-29
@@ -141,7 +141,7 @@ const speedup = (totalManual / totalGatherStep).toFixed(1);
-
Planning oracle (v4.1.1)
+
Planning oracle (v4.2.0)
Full 25-scenario suite, every metric at the HIGH ceiling, latency well under release-gate thresholds (p50 ≤ 50 ms, p95 ≤ 300 ms, p99 ≤ 1000 ms).
diff --git a/website/src/components/landing/Hero.astro b/website/src/components/landing/Hero.astro
index bfc7e2f..5797629 100644
--- a/website/src/components/landing/Hero.astro
+++ b/website/src/components/landing/Hero.astro
@@ -6,7 +6,7 @@ const stats = [
},
{
label: 'Spec · Release',
- value: 'v4.1.1 · multi-PR review',
+ value: 'v4.2.0 · Claude & Codex MCP setup',
},
{
label: 'Spec · Deployment',
diff --git a/website/src/components/landing/Topology.astro b/website/src/components/landing/Topology.astro
index f3526bb..5979cf5 100644
--- a/website/src/components/landing/Topology.astro
+++ b/website/src/components/landing/Topology.astro
@@ -72,6 +72,6 @@ const consumers = [
CONSUMERS · N=4
-
Approved · v4.1.1
+
Approved · v4.2.0
diff --git a/website/src/content/docs/changelog.md b/website/src/content/docs/changelog.md
index ddc2db4..1ccd2be 100644
--- a/website/src/content/docs/changelog.md
+++ b/website/src/content/docs/changelog.md
@@ -5,6 +5,33 @@ description: "User-visible changes to gather-step, listed by release. Updated ma
This changelog lists significant user-visible changes. The latest release is shown in full at the top; earlier releases are collapsed under [Earlier releases](#earlier-releases) at the bottom of the page.
+## v4.2.0 (2026-05-29)
+
+Release status: **released**.
+
+Minor release on top of v4.1.1. Fixes `setup-mcp` so it writes to the files MCP clients actually read, adds Codex support, and refreshes dependencies. Rolls up the unreleased v4.0.6 and v4.1.1 changes.
+
+### Fixed
+
+- `setup-mcp --scope local` now writes the project-scoped `.mcp.json`, and `--scope global` writes the user-scoped `~/.claude.json`. Previously it wrote to `.claude/settings.json`, which Claude Code does not read for server definitions, so the registered server never appeared in the client.
+
+### Added
+
+- `setup-mcp --client codex` merges a `[mcp_servers.gather-step]` block into `~/.codex/config.toml`, preserving existing servers, other keys, and comments. The default client remains `claude`.
+
+### Docs
+
+- Corrected the MCP clients guide: the Claude user-scoped config path is `~/.claude.json` (not `~/.claude/settings.json`), and the Fast Path section now reflects the `.mcp.json` / `~/.claude.json` / Codex targets.
+
+### Changed
+
+- Refreshed Cargo dependencies to the latest SemVer-compatible versions, including `serde_json 1.0.149 → 1.0.150`, `tokio 1.52.2 → 1.52.3`, `rmcp 1.5.0 → 1.7.0`, `similar 3.1.0 → 3.1.1`, `quick_cache 0.6.21 → 0.6.22`, and `memchr 2.8.0 → 2.8.1`, plus transitive lockfile updates. Intentionally exact-pinned dependencies were left untouched.
+- Bumped the website `astro 6.3.5 → 6.4.2` floor and refreshed the website lockfile.
+
+### Release-wide
+
+- Bumped the app, Cargo workspace, internal crate dependency versions, and website package metadata to `4.2.0`.
+
## v4.0.6 (2026-05-20)
Release status: **prepared**.
diff --git a/website/src/content/docs/guides/mcp-clients.md b/website/src/content/docs/guides/mcp-clients.md
index 392c769..0aad0d2 100644
--- a/website/src/content/docs/guides/mcp-clients.md
+++ b/website/src/content/docs/guides/mcp-clients.md
@@ -20,17 +20,24 @@ Before connecting a client:
2. **The built binary** on your `PATH`. See [Installation](/guides/installation/)
for build instructions.
-## Fast Path for Claude
+## Fast Path
-For Claude Code, Gather Step can write the workspace-local MCP settings entry:
+For Claude Code, Gather Step writes the project-scoped `.mcp.json` entry:
```bash
gather-step --workspace /path/to/workspace setup-mcp --scope local
```
-Use `--scope global` only when you want the same workspace-pinned server entry
-in `~/.claude/settings.json`. The command is idempotent and updates the
-`mcpServers.gather-step` block without touching other server entries.
+Use `--scope global` to write the user-scoped entry to `~/.claude.json`
+instead. For Codex, pass `--client codex` to merge the server block into
+`~/.codex/config.toml` (scope is ignored — Codex has a single global config):
+
+```bash
+gather-step --workspace /path/to/workspace setup-mcp --client codex
+```
+
+The command is idempotent and updates only the `gather-step` entry without
+touching other servers, keys, or comments. Restart the client afterward.
## Start the Server (Smoke Test)
@@ -77,7 +84,7 @@ fits your workflow:
}
```
-**User-scoped:** `~/.claude/settings.json` (applies to all
+**User-scoped:** `~/.claude.json` (applies to all
projects for this user):
```json