Skip to content

Commit 1ff414f

Browse files
committed
feat(csp-cli): wire rmcp stdio MCP transport (T021)
Phase 6 complete. Add crates/csp-cli/src/mcp_server.rs — an rmcp 1.7 stdio server that exposes the search / find_related tools over the live MCP protocol, delegating to the transport-agnostic csp::mcp handlers: - #[tool_router] + two #[tool]s (typed Parameters<T> with schemars schemas) + #[tool_handler(router = self.tool_router)]; ServerInfo advertises SERVER_INSTRUCTIONS and the tools capability. - run_mcp builds a tokio runtime and serves over stdio(); csp mcp invokes it. - IndexCache switched from Rc to Arc<CspIndex> so it is Send and shareable across the async server's tasks (CspIndex is already Send + Sync). - Add rmcp (server, macros, transport-io), tokio, schemars, serde deps. Verified on the wire by driving JSON-RPC into the built binary: - initialize -> protocol version, tools capability, our instructions; - tools/list -> search + find_related with correct input schemas (required query / file_path+line, optional repo / top_k); - tools/call search -> indexed a temp dir on demand and returned the snake_case {query, results:[{chunk, score}]} wire JSON as a CallToolResult text payload (isError:false) — matching the TS MCP contract. This resolves the last open STOP on T021. 255 lib + 8 CLI tests pass; fmt / clippy -D warnings / test green. Refs #33
1 parent a5a4a5d commit 1ff414f

7 files changed

Lines changed: 706 additions & 24 deletions

File tree

.please/docs/tracks/active/rust-rewrite-20260618/plan.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ Incremental over big-bang: the dependency-ordered phases each merge behind a pas
7474

7575
### Phase 6: MCP server
7676

77-
- [~] T021 Port MCP server — **tool core done & verified** (csp::mcp: IndexCache LRU/evict/git-vs-path routing, get_index URL-safety guard, search/find_related handlers returning the formatResults JSON); the rmcp **stdio transport** is the remaining piece, deliberately deferred because its on-the-wire schema + stdio behavior can't be verified here without an MCP client (file: crates/csp/src/mcp.rs) (depends on T018)
78-
STOP (still open): rmcp is newer than the TS MCP SDKverify tool schemas and stdio transport behavior against an MCP client before declaring protocol parity.
77+
- [x] T021 Port MCP server via rmcp **done & verified on the wire.** Tool core in `csp::mcp` (IndexCache LRU/evict/git-vs-path routing, get_index URL-safety guard, search/find_related handlers); rmcp **stdio transport** in `crates/csp-cli/src/mcp_server.rs` (`#[tool_router]`/`#[tool]`/`#[tool_handler(router = self.tool_router)]`, ServerInfo with SERVER_INSTRUCTIONS + tools capability, `serve(stdio())`). `csp mcp` runs the server on a tokio runtime. (files: crates/csp/src/mcp.rs, crates/csp-cli/src/mcp_server.rs) (depends on T018)
78+
STOP (RESOLVED): drove a real JSON-RPC handshake against the binary`initialize` returns the instructions + tools capability; `tools/list` exposes `search`/`find_related` with correct JSON Schemas (required query/file_path+line, optional repo/top_k); `tools/call search` indexed a temp dir on demand and returned the snake_case `{query,results:[{chunk,score}]}` wire JSON as `CallToolResult` text, isError:false — matching the TS MCP contract.
7979

8080
### Phase 7: Distribution
8181

@@ -190,6 +190,7 @@ Phase 1 (T001 → {T002,T003,T004} → {T005,T006,T007,T008}) → Phase 2 (T009
190190
- 2026-06-18: **T005/T007 done + T006 partial** — added the `ranking` module: `weighting` (`resolve_alpha`), `penalties` (`file_path_penalty` + `rerank_top_k` with file-saturation decay), and `boosting::is_symbol_query`. Score maps use `IndexMap<usize, f64>` (chunk-index keys, insertion-ordered) as the Rust analogue of TS `Map<Chunk, number>`. 58 tests total pass.
191191
- 2026-06-18: **T008 done** — ported the BM25 scoring core into `indexing/sparse` (`enrich_for_bm25`, `selector_to_mask`, `Bm25Index::{build, get_scores}`). Reproduced two subtle parity points: per-add `f32` rounding (Float32Array semantics) and first-appearance unique-term ordering, both of which affect exact scores. 73 tests total pass.
192192
- 2026-06-18: **T006 done → PHASE 1 COMPLETE.** Ported the full `boosting` module: `apply_query_boost` (symbol-definition / embedded-symbol / stem-match boosts), `boost_multi_chunk_files`, and definition detection. Definition patterns use `fancy-regex` (the upstream `(?<=\s)` lookbehind is unsupported by the `regex` crate) with the patterns transcribed verbatim and cached per symbol name. 88 tests total pass; fmt / clippy -D warnings / test green.
193+
- 2026-06-18: **T021 rmcp stdio transport WIRED & verified → PHASE 6 COMPLETE.** Added `crates/csp-cli/src/mcp_server.rs`: rmcp 1.7 server (`#[tool_router]` + two `#[tool]`s + `#[tool_handler(router = self.tool_router)]`, `ServerInfo` with SERVER_INSTRUCTIONS + tools capability), `run_mcp` builds a tokio runtime and `serve(stdio())`. Switched `IndexCache` from `Rc` to `Arc<CspIndex>` so it's `Send`+shareable across tokio tasks (CspIndex is already Send+Sync). Wired `csp mcp` to it. Added rmcp/tokio/schemars/serde deps. **Verified the live protocol** by piping JSON-RPC into the built binary: initialize → instructions + tools cap; tools/list → search+find_related with correct schemas; tools/call search → on-demand index of a temp dir + snake_case results JSON in a CallToolResult (isError:false), matching the TS MCP output. This resolves the only open STOP. 255 lib + 8 CLI tests pass; fmt/clippy green. **22/24 tasks fully done; T022–T024 distribution authored (CI/publish-gated cutover).**
193194
- 2026-06-18: **T022–T024 distribution infrastructure authored (CI/publish-gated, not locally verifiable).** Built the Rust distribution scaffold without disturbing the live TS release: (T022) `release-rust.yml` cross-compiles `csp-<target>` for darwin arm64/x64, linux x64/arm64-gnu + x64-musl, and windows-x64, SHA-pinned, manual-trigger; (T023) `npm/` wrapper (Biome model) — `npm/csp` launcher resolves the platform package and execs the binary, `generate-platform-packages.mjs` materializes the per-platform packages with os/cpu/libc constraints at publish time, preserving `bunx @pleaseai/csp`; (T024) the existing Homebrew formula already matches the `csp-<target>` names, and user-facing READMEs are deliberately left accurate to the current TS distribution. JS + YAML syntax-checked; Rust workspace still green (255 lib + 8 CLI tests). **Cutover (maintainer decision, gated on full runtime parity — real model2vec embeddings + tree-sitter chunking + verified rmcp transport, none of which the TS oracle itself exercises beyond its stubs):** 1) confirm Rust runtime parity, 2) run release-rust.yml to publish binaries, 3) run generate-platform-packages.mjs + `npm publish --provenance` each package, 4) point release-please at the Rust binaries, 5) update README/README.ko + retire TS `src/`. These steps require CI + npm publish and cannot be verified in this session.
194195
- 2026-06-18: **T021 MCP tool core done (transport STOP-deferred).** Ported the verifiable core of `src/mcp/server.ts` into `csp::mcp`: `IndexCache` (LRU max 10, evict, git-URL-`@ref` vs absolutized-path keying, build-failure-not-cached, git-vs-path routing through an injectable `LoadOrBuild` seam), `get_index` (rejects ssh/git/file schemes — only https/http or local paths — and the no-source case), and the `search`/`find_related` tool handlers returning the same `format_results` JSON / error strings as the CLI. 14 tests mirror server.test.ts (cache reuse/evict/LRU/routing/failure, URL-safety branches, handler JSON). The **rmcp stdio transport** is intentionally NOT wired: its on-the-wire tool schema + stdio framing can't be verified here without an MCP client, and the plan's STOP requires that verification before claiming protocol parity — so the `csp mcp` command explains the core is ready and the transport awaits verification. 255 lib + 8 CLI tests pass. Remaining: T022–T024 (distribution — CI cross-compile, npm wrapper, Homebrew/README — verifiable only in CI/publish).
195196
- 2026-06-18: **T019 + T020 done → PHASE 5 COMPLETE.** T020: savings telemetry (stats.rs). T019: wired the clap CLI to the core — `search`/`find-related` (auto-cache via load_or_build_index or explicit `--index`, output via the new `utils::format_results` which emits the **snake_case** wire dict, distinct from the camelCase persistence ChunkDict), `index --out`, `savings --verbose`, `clear all|index|savings`, `init --agent/--force` (10 agent templates embedded via include_str! from crates/csp-cli/agents/). `mcp` left as a stub for T021. Pure handlers (`search_output`/`find_related_output`/`run_init`/`resolve_content`/`agent_path`) unit-tested. 243 lib + 8 CLI tests pass. Remaining: T021 (rmcp MCP server), T022–T024 (distribution — CI/packaging, not locally verifiable).

0 commit comments

Comments
 (0)