1763261503
* docs: v0.8.46 CHANGELOG — platform archives, palette, sub-agents, sandbox, web install, search fixes Closes #2188 * feat(v0.8.46): quick fixes — palette, model picker Esc, sub-agent sidebar, shell chip, model name casing, CVE bump (#2212) * fix: bump qs to >=6.15.2 for CVE-2026-8723 Add qs override in feishu-bridge package.json to force transitive dependency resolution to >=6.15.2, addressing CVE-2026-8723. Refs: #2198 * fix: Esc in model picker applies last-highlighted choice Previously Esc reverted to the initial model when the user hadn't moved the selection. Now Esc always applies the currently highlighted model and thinking-effort tier, making Esc consistent with Enter. Also updates the picker footer hint from 'Esc cancel' to 'Esc apply'. Refs: #2196 * feat: show '⏳ shell running' chip in TUI footer Adds a footer_shell_chip function that displays a '⏳ shell running' status chip in the footer's right cluster whenever a foreground shell command is active via exec_shell. The chip is always visible regardless of user-configured status items. Refs: #2194 * feat: auto-collapse finished sub-agents in sidebar When a sub-agent completes (status = 'done'), its detail lines (id, steps, duration, progress) are now hidden in the sidebar agents panel. Only the summary label line is shown, keeping the sidebar compact. Running agents still show full detail. Refs: #2195 * feat: refresh Whale dark palette for better contrast Improve contrast and layer separation in the Whale dark theme: - Deepen base background for more depth (10,17,32) - Lighten panel (22,34,56) for clearer distinction from bg - Lighten elevated surface (36,52,78) for better elevation - Lighten selection (48,68,100) for clearer selected state - Boost text hint (138,150,174) and dim (118,130,156) readability - Brighter border (52,88,145) for better edge definition - Update tool surface colors for consistency Refs: #2197 * fix: preserve model name casing in normalize_model_name_for_provider When the user enters a model name like 'DeepSeek-V4-Flash', the normalizer was lowercasing it to 'deepseek-v4-flash' via the canonical_official_deepseek_model_id function. Now the normalizer preserves the caller's casing when the input already matches a known model id case-insensitively. Compact aliases like 'deepseek-v4pro' are still rewritten to 'deepseek-v4-pro'. Refs: #2109 * feat(web): install download tile with arch detection, SHA256, China mirrors + companion binary fix (#2213) * fix(web): download both codewhale and codewhale-tui binaries in install snippets The SNIPPETS map only fetched one binary per platform, causing the dispatcher to fail with MISSING_COMPANION_BINARY. Every arch now downloads both codewhale AND codewhale-tui side-by-side. - macOS/Linux: added second curl + combined chmod/xattr/mv for tui - Windows: added second Invoke-WebRequest for codewhale-tui.exe - VERIFY: PowerShell now hashes both binaries; Unix --ignore-missing covers all present binaries in a single sha256sum pass * feat(web): add install download tile with arch detection, SHA256, and China mirrors (#2192) * feat(sandbox/linux): process hardening — PR_SET_DUMPABLE, NO_NEW_PRIVS, RLIMIT_CORE (#2214) * feat(sandbox/linux): add process hardening module — PR_SET_DUMPABLE, NO_NEW_PRIVS, RLIMIT_CORE (#2183) * feat(sandbox/linux): seccomp filter + bwrap passthrough - seccomp: BPF filter whitelisting safe syscalls, denying ptrace/mount/kexec and other dangerous syscalls. Uses raw BPF instructions via libc prctl to avoid external dependencies (#2182). - bwrap: optional bubblewrap passthrough when /usr/bin/bwrap is present and [sandbox] prefer_bwrap=true in config. Creates read-only rootfs with write access limited to the working directory (#2184). - landlock detect_denial extended to recognize seccomp SIGSYS/"Bad system call" patterns alongside existing Landlock EACCES/EPERM detection. - SandboxManager gains prefer_bwrap field; set_prefer_bwrap on ShellManager. - EngineConfig gains prefer_bwrap field, wired through main/ui/runtime_threads. - Diagnostics now reports bwrap_available and cgroup_version. - config.example.toml documents the prefer_bwrap key. Pre-existing clippy fixes picked up in the same build: - collapsible_if in ui.rs version-check - cmp_owned in goal.rs test - consecutive str::replace in normalize_auth_mode Closes #2182, closes #2184 * docs: add cross-links to issue and PR templates in CONTRIBUTING.md (#2215) - Link .github/ISSUE_TEMPLATE/bug_report.md and feature_request.md from the Reporting Issues section - Link .github/PULL_REQUEST_TEMPLATE.md from the Pull Request Guidelines section * feat(release): bundle platform archives with install scripts (#2216) - Add bundle job to release workflow that creates per-platform archives (tar.gz for Linux/macOS, .zip for Windows) containing both codewhale and codewhale-tui binaries plus install scripts - Create install.bat (Windows) — copies binaries to %USERPROFILE%\bin - Create install.sh (Unix) — copies binaries to ~/.local/bin - Windows gets a portable .zip variant without install script - Release notes updated to promote archives as primary download method - Individual binaries retained for npm wrapper and scripting Closes #2193 * fix(web_search): fall back to DuckDuckGo when Bing returns zero results (#2130) When the configured search provider is Bing and the query returns zero results (common for technical/compound queries), fall through to the DuckDuckGo path instead of reporting empty. A provenance message is surfaced: "Bing returned no results; used DuckDuckGo fallback". Also adds Security and Code of Conduct cross-links to CONTRIBUTING.md per the sub-agent renovation (#2203). * docs: SANDBOX.md threat model + RFCs for persistence and MCP + SandboxExecutor trait - docs/SANDBOX.md: complete threat model describing each platform's sandbox (Seatbelt, Landlock, seccomp, process hardening, bwrap, Windows v1). Covers defense-in-depth layering, config keys, denial detection, limitations. - docs/rfcs/2189-persistence-sqlite.md: RFC for SQLite migration (drafted by sub-agent) - docs/rfcs/2190-mcp-modularization.md: RFC for MCP crate split into protocol/client/server with OAuth support - crates/tui/src/sandbox/policy.rs: SandboxExecutor trait definition and SafetyLevel→SandboxPolicyBehavior mapping function with tests Closes #2180, closes #2186, closes #2189, closes #2190 * feat: sandbox parity tests + remove sub-agent 100-turn cap - Add sandbox parity tests covering platform detection, denial patterns, bwrap preference, and policy consistency across modes (#2187) - Remove arbitrary 100-turn sub-agent cap: DEFAULT_MAX_STEPS changed from 100 to u32::MAX. Sub-agents now run until they produce a final text response, are cancelled by the parent, or hit a configured explicit budget (#2034) Closes #2187, closes #2034
227 lines
7.1 KiB
Markdown
227 lines
7.1 KiB
Markdown
# RFC: MCP Modularization
|
|
|
|
**Issue:** #2190
|
|
**Status:** Draft
|
|
**Date:** 2026-05-26
|
|
|
|
## 1. Current state
|
|
|
|
### 1.1 `codewhale-mcp` crate (`crates/mcp/`)
|
|
|
|
The current MCP implementation lives in a single crate with two responsibilities:
|
|
|
|
- **MCP client** — connects to MCP servers over stdio, manages protocol handshake,
|
|
tool discovery, and tool invocation. Used by the TUI to surface MCP tools as
|
|
`mcp_<server>_<tool>` entries in the tool registry.
|
|
- **MCP stdio server** — a minimal MCP server that exposes CodeWhale's own tools
|
|
over stdio for external MCP clients. Used by the `codewhale mcp` CLI subcommand.
|
|
|
|
Both the client and server share protocol types (JSON-RPC messages, tool schemas)
|
|
but have different lifecycle concerns and different callers.
|
|
|
|
### 1.2 Integration points
|
|
|
|
- `crates/tui/src/mcp.rs` — MCP client integration: server lifecycle, tool
|
|
discovery, tool execution forwarding
|
|
- `crates/tui/src/mcp_server.rs` — MCP stdio server: exposes TUI tools via
|
|
stdio MCP protocol
|
|
- `docs/MCP.md` — user-facing documentation
|
|
|
|
## 2. Motivation
|
|
|
|
### 2.1 Separation of concerns
|
|
|
|
The client and server share a crate but have no shared code paths at runtime.
|
|
They import the same protocol types but serve different roles:
|
|
- The client is **outbound** — it connects to external servers
|
|
- The server is **inbound** — it accepts connections from external clients
|
|
|
|
Mixing them in one crate creates unnecessary coupling: changes to the server
|
|
API recompile the client, and vice versa.
|
|
|
|
### 2.2 OAuth support
|
|
|
|
The current MCP client has no OAuth support. MCP servers that require OAuth
|
|
(e.g., GitHub, Google) cannot be used. Adding OAuth to the client requires:
|
|
- Token storage (keychain, env-based, or config-based)
|
|
- OAuth flow (device code, PKCE, or client credentials)
|
|
- Token refresh and expiry handling
|
|
|
|
These concerns are client-side only and should not affect the server crate.
|
|
|
|
### 2.3 Reuse outside the TUI
|
|
|
|
The MCP client is currently embedded in the TUI binary. If we want to use
|
|
MCP tools from:
|
|
- The `app-server` (HTTP/SSE runtime API)
|
|
- The `codewhale` CLI (non-interactive mode)
|
|
- External consumers (library use)
|
|
|
|
...the client needs to be a standalone crate with a clean public API.
|
|
|
|
## 3. Proposed crate split
|
|
|
|
```
|
|
crates/mcp/ → crates/mcp-protocol/ (shared types, no I/O)
|
|
crates/mcp-client/ (client implementation)
|
|
crates/mcp-server/ (server implementation)
|
|
```
|
|
|
|
### 3.1 `codewhale-mcp-protocol`
|
|
|
|
**Contents:** JSON-RPC message types, tool schema types, protocol constants,
|
|
handshake types, error types. No I/O, no async runtime dependency.
|
|
|
|
**Dependencies:** `serde`, `serde_json`, `codewhale-protocol` (for tool schema)
|
|
|
|
**Public API:**
|
|
```rust
|
|
pub mod messages; // JSON-RPC request/response/notification types
|
|
pub mod tools; // MCP tool schema types
|
|
pub mod errors; // MCP error codes
|
|
pub mod version; // Protocol version constants
|
|
```
|
|
|
|
### 3.2 `codewhale-mcp-client`
|
|
|
|
**Contents:** MCP client: stdio transport, process management, handshake,
|
|
tool discovery, tool invocation, OAuth support.
|
|
|
|
**Dependencies:** `codewhale-mcp-protocol`, `tokio`, `serde_json`, `tracing`,
|
|
`oauth2` (new, for OAuth), `keyring` (optional, for token storage)
|
|
|
|
**Public API:**
|
|
```rust
|
|
pub struct McpClient {
|
|
// Configuration
|
|
}
|
|
|
|
impl McpClient {
|
|
pub async fn connect(config: McpClientConfig) -> Result<Self>;
|
|
pub async fn list_tools(&self) -> Result<Vec<ToolSchema>>;
|
|
pub async fn call_tool(&self, name: &str, args: Value) -> Result<Value>;
|
|
pub async fn disconnect(self);
|
|
}
|
|
|
|
pub struct McpClientConfig {
|
|
pub command: String, // e.g., "npx", "python"
|
|
pub args: Vec<String>, // e.g., ["-y", "@modelcontextprotocol/server-github"]
|
|
pub env: HashMap<String, String>,
|
|
pub oauth: Option<OAuthConfig>,
|
|
pub timeout: Duration,
|
|
}
|
|
|
|
pub struct OAuthConfig {
|
|
pub provider: OAuthProvider,
|
|
pub client_id: String,
|
|
pub scopes: Vec<String>,
|
|
pub token_storage: TokenStorage,
|
|
}
|
|
|
|
pub enum OAuthProvider {
|
|
Github,
|
|
Google,
|
|
Custom { auth_url: String, token_url: String },
|
|
}
|
|
```
|
|
|
|
### 3.3 `codewhale-mcp-server`
|
|
|
|
**Contents:** MCP stdio server: accepts connections, exposes tool list,
|
|
handles tool calls, manages stdio transport.
|
|
|
|
**Dependencies:** `codewhale-mcp-protocol`, `codewhale-tools`, `tokio`,
|
|
`serde_json`, `tracing`
|
|
|
|
**Public API:**
|
|
```rust
|
|
pub struct McpServer {
|
|
// Tool registry
|
|
}
|
|
|
|
impl McpServer {
|
|
pub fn new(tools: Vec<Arc<dyn ToolSpec>>) -> Self;
|
|
pub async fn serve_stdio(self) -> Result<()>;
|
|
pub async fn serve_sse(self, addr: SocketAddr) -> Result<()>;
|
|
}
|
|
```
|
|
|
|
## 4. Migration path
|
|
|
|
### Phase 1: Extract protocol crate (non-breaking)
|
|
|
|
1. Move shared types from `crates/mcp/src/` to `crates/mcp-protocol/src/`
|
|
2. Re-export from `codewhale-mcp` for backward compatibility
|
|
3. Update `Cargo.toml` in `codewhale-mcp` to depend on `codewhale-mcp-protocol`
|
|
|
|
### Phase 2: Split client and server (breaking for direct imports)
|
|
|
|
1. Create `crates/mcp-client/` with client code
|
|
2. Create `crates/mcp-server/` with server code
|
|
3. Update `codewhale-tui` to depend on `codewhale-mcp-client`
|
|
4. Update `codewhale-cli` to depend on `codewhale-mcp-server`
|
|
5. Deprecate `codewhale-mcp` crate (re-exports from new crates)
|
|
|
|
### Phase 3: Remove legacy crate
|
|
|
|
1. Remove `crates/mcp/` after a deprecation cycle (one release)
|
|
|
|
## 5. OAuth integration
|
|
|
|
### 5.1 Token storage
|
|
|
|
Tokens should be stored securely. Options (in priority order):
|
|
1. OS keychain via `keyring` crate (macOS Keychain, Windows Credential Manager,
|
|
Linux Secret Service)
|
|
2. Encrypted file in `~/.codewhale/mcp-credentials/` (fallback)
|
|
3. Environment variable `MCP_OAUTH_TOKEN_<PROVIDER>`
|
|
|
|
### 5.2 OAuth flows
|
|
|
|
Initial implementation supports:
|
|
- **Device Code Flow** (GitHub) — user opens a URL, enters a code
|
|
- **Client Credentials** — for service-to-service MCP servers
|
|
|
|
Future (deferred):
|
|
- **PKCE** — for user-facing OAuth with redirect
|
|
- **Token refresh** — automatic refresh with refresh_token
|
|
|
|
### 5.3 Configuration
|
|
|
|
```toml
|
|
# ~/.codewhale/config.toml
|
|
[mcp.servers.github]
|
|
command = "npx"
|
|
args = ["-y", "@modelcontextprotocol/server-github"]
|
|
|
|
[mcp.servers.github.oauth]
|
|
provider = "github"
|
|
client_id = "your-client-id"
|
|
scopes = ["repo", "read:org"]
|
|
```
|
|
|
|
## 6. Risks and unknowns
|
|
|
|
| Risk | Mitigation |
|
|
|---|---|
|
|
| Crate proliferation | 3 small crates vs 1 medium crate; each has a clear purpose |
|
|
| Breaking internal imports | Phase 2 carries `codewhale-mcp` deprecation shim for one release |
|
|
| OAuth token security | OS keychain preferred; encrypted fallback with file permissions |
|
|
| Testing complexity | Each crate has its own test suite; integration tests remain in `crates/tui/tests/` |
|
|
| Dependency bloat | `oauth2` and `keyring` are optional features; consumers opt in |
|
|
|
|
## 7. Out of scope (future RFCs)
|
|
|
|
- MCP over HTTP/SSE transport (currently stdio only)
|
|
- MCP server discovery (currently explicit config)
|
|
- MCP tool result streaming (currently request-response)
|
|
- MCP server-side tool approval flows
|
|
|
|
## Related
|
|
|
|
- `crates/mcp/src/` — current implementation
|
|
- `crates/tui/src/mcp.rs` — TUI MCP integration
|
|
- `crates/tui/src/mcp_server.rs` — MCP stdio server
|
|
- `docs/MCP.md` — user-facing documentation
|
|
- Issue #2190 — this RFC
|