Skip to content

Commit 68f4837

Browse files
lklimekclaudecoderabbitai[bot]
authored
feat: add MCP server and det-cli command-line interface (#773)
* feat: add MCP HTTP server for programmatic access Embed a streamable-HTTP MCP server (rmcp + axum) that exposes backend tasks as tools for AI agents. Feature-gated behind `mcp` feature flag and opt-in via MCP_API_KEY environment variable. Tools: list_wallets, generate_receive_address, list_core_wallets. Auth: Bearer token with constant-time comparison (subtle crate). Supports network switching -- MCP context follows GUI network changes via ArcSwap. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: support dual MCP transport (stdio + HTTP) with lazy init Refactor MCP module to support two feature-gated transports: - mcp-stdio: standalone binary with lazy AppContext initialization - mcp-http: embedded HTTP server sharing GUI app's context New binary: dash-evo-tool-mcp (requires mcp-stdio feature). Neither transport is enabled by default. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add det-cli MCP client with tool caching and completion Dynamic CLI client that discovers tools from the MCP server at runtime. Supports HTTP transport (default) and standalone mode (--standalone). Caches tool schemas locally for shell completion. New binary: det-cli (requires `cli` feature). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add MCP and CLI quick start guides Add docs/MCP.md covering the HTTP and stdio transport modes, available tools, environment variables, and security notes. Add docs/CLI.md covering det-cli connection modes, subcommands, and shell completion setup. Update README.md with a Programmatic Access section linking to both guides. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(cli): read MCP config from app .env file - Load app's .env on startup so MCP_API_KEY/MCP_LISTEN are available without separate DET_CLI_BEARER setup - Replace DET_CLI_BEARER with MCP_API_KEY (matches server config) - Derive server URL from MCP_LISTEN env var; fall back to 127.0.0.1:9527 - Auto-select stdio mode when no API key is configured; HTTP when set - Make subcommand optional: bare `det-cli` lists tools live - Inject cached tool list into --help output via print_cached_tools_help() - Update docs/CLI.md to reflect new config and connection behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(cli): implicit versioned cache, remove Cache subcommand - Remove explicit `det-cli cache` subcommand; tool list is cached automatically after every `tools` invocation - Add ToolCache struct with version field; cache includes server version from MCP peer info (falls back to PKG_VERSION) - Cache staleness: --help only shows cached tools when version matches the binary; stale cache prompts user to run `det-cli` to refresh - Add `#[command(version)]` so `det-cli --version` works - Fix server info access: use `client.peer().peer_info()` (correct rmcp API) instead of non-existent `peer_server_info()` - Update bash completion jq path to `.tools[].name` for new cache format - Update docs/CLI.md to reflect automatic caching behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * ci(release): build and package det-cli binary alongside dash-evo-tool Add --features cli to all release build commands and include the det-cli binary in release packages (zip for Linux/Windows, .app bundle for macOS). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: consolidate MCP features and embed stdio server in det-cli Simplify from 3 features (mcp-stdio, mcp-http, cli) to 2: - `mcp`: HTTP server embedded in GUI app - `cli`: det-cli binary with in-process MCP and `serve` subcommand Remove standalone `dash-evo-tool-mcp` binary — `det-cli serve` replaces it as the MCP stdio server for Claude Desktop and AI agents. Update docs (MCP.md, CLI.md, CONTRIBUTING.md) to reflect new layout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: expand feature flags documentation in CONTRIBUTING.md Add binary output mapping, dependency details, CI usage table, and combination examples for all cargo features. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: remove redundant build examples from feature flags section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: remove dependencies section from feature flags Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: remove CI feature usage section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(cli): auto-install bash completion on cache refresh Write bash completion script to ~/.local/share/bash-completion/completions/det-cli whenever the tool cache is rebuilt. bash-completion 2.x auto-loads from this directory — no .bashrc editing or manual setup needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(cli): direct tool subcommands with custom help - Remove `call` subcommand — tools are now first-class subcommands (e.g. `det-cli list-wallets` instead of `det-cli call list_wallets`) - Use hyphens in command and parameter names (CLI convention) - Custom help output shows all available tools as primary content, with management commands and options below - Hyphen-to-underscore conversion for MCP tool/param names Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update CLI.md for direct subcommand UX Rewrite examples and usage to reflect hyphenated commands (det-cli list-wallets), remove call subcommand references, document auto-installed bash completion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(cli): unify help output for bare invocation and --help Both `det-cli` (no args) and `det-cli --help` now display the same format. Bare invocation queries the server for fresh tools first; --help uses the disk cache for instant response. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(cli): replace MCP_NETWORK with --network flag and database default Network selection now follows the same pattern as the GUI: read from the database (last selected network), with --network flag as override. Removes the MCP_NETWORK env var. Also adds short flags: -n (network), -s (standalone), -a (addr), -b (bearer). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(mcp): remove list_core_wallets tool — MCP is SPV-only Core wallet operations require a local Dash Core node, which conflicts with the MCP server's SPV-only design. Remove the tool and all references from docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cli): show meaningful errors when AppContext init fails - Add tracing subscriber (stderr, warn level) for non-serve CLI paths so tracing::error!() from AppContext::new() is visible to users - Pre-validate network config exists before attempting AppContext init, giving a clear error like "no configuration found for network 'Dash'. Check your .env file has MAINNET_dapi_addresses set." - Fall through message now says "check logs for details" instead of the opaque "failed to create AppContext" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(mcp): add network tool, remove --network CLI flag Replace the --network CLI flag with a proper `network` MCP tool that returns the active network and available configured networks as JSON. This keeps det-cli as a thin client with no local logic — network info comes from the server, same as all other operations. Changes: - Add `network` tool to DashMcpService (active + available networks) - Remove --network flag from det-cli - Remove network_override threading (ContextProvider::Lazy, new_lazy, init_app_context, start_stdio) - Simplify init_app_context to use DB default only - Add available_network_names() and network_display_name() helpers - Make AppContext.network and data_dir pub (needed by MCP tools) - Update docs/CLI.md and docs/MCP.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: silently skip unconfigured networks in Config loading Missing network configs are normal — not every user configures all four networks. Remove tracing::error! spam and the hard mainnet requirement. Only fail when no networks are configured at all. The actual network availability check happens in init_app_context where it matters. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(cli): clean error messages and network tool fixes - Handle rmcp ServiceError with typed matching instead of string parsing. McpError variant extracts message + code directly from ErrorData fields. - Suppress rmcp service-level tracing warnings (duplicates handled errors) - Revert network tool to use AppContext (correct for embedded mode — needs working config to be useful) - Make AppContext.network and data_dir pub (needed by MCP tools) - Add collect_available() helper for listing configured networks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(mcp): start SPV and wait for wallets in standalone mode In CLI/stdio mode, init_app_context now starts the SPV client after creating AppContext so wallet operations work. The init returns immediately — tools like list-wallets and network are not blocked. The generate-receive-address tool polls ConnectionStatus via trigger_refresh() until SPV reaches Synced state (60s timeout), then verifies the specific wallet is loaded into SPV's det_wallets map before dispatching the backend task. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(cli): add per-tool --help support Intercept --help/-h in tool subcommand args and print tool-specific help from the disk cache instead of forwarding to the MCP server. Uses cached tool metadata to show description, usage, and parameters with required/optional markers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore(cli): bump SPV timeout to 600s, disable logs by default Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(mcp): add wallet_balances and send_core_funds tools Add two new MCP tools: - wallet_balances: read total/confirmed/unconfirmed balances in duffs - send_core_funds: send DASH from a wallet to an address via CoreTask Extract SPV wait loop from generate_receive_address into a reusable wait_for_spv_sync() helper shared by both SPV-dependent tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cli): use wrapper pattern for generate_completion bash output The generate_completion() function was emitting a standalone _det_cli_tools function with its own `complete -F` registration, overriding clap's built-in completions. Now uses the same _det_cli_wrapper pattern as install_bash_completion() — calls clap's _det-cli first, then adds dynamic tool/parameter names. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(mcp): wait for SPV sync before reading wallet balances wallet_balances was returning stale data because it read in-memory state without waiting for SPV to finish syncing. Now waits for green state like the other wallet-dependent tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(cli): split det_cli into modules and add headless feature Split the 546-line single-file binary into a multi-file directory: main.rs, connect.rs, cache.rs, completion.rs, help.rs. Add `headless` feature flag (= ["cli", "mcp"]) and `det-cli headless` command that runs as a standalone HTTP MCP server daemon with bearer auth, ctrl+c graceful shutdown, and eager AppContext initialization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(mcp): migrate tools from proc-macro to trait-based ToolBase/AsyncTool pattern Replace #[tool_router]/#[tool] proc-macro approach with rmcp's ToolBase + AsyncTool traits. Each tool is now a standalone struct in its own domain file, enabling auto-generated schemas, typed output with structuredContent, and per-tool annotations. New files: - error.rs: McpToolError enum with From<McpToolError> for ErrorData - resolve.rs: wallet resolution and SPV sync helpers (extracted) - tools/mod.rs: shared param types (WalletIdParams, EmptyParams, etc.) - tools/network.rs: NetworkTool, ListWalletsTool - tools/wallet.rs: GenerateReceiveAddress, WalletBalancesQuery, SendCoreFunds, FetchPlatformBalances (new) - tools/meta.rs: DescribeTool Also cleans up dispatch.rs (removes resolve_wallet/task_error_to_mcp) and simplifies server.rs (manual ServerHandler impl). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(mcp): add query_withdrawals tool for Platform withdrawal queries Wraps existing PlatformInfoTask backend (CurrentWithdrawalsInQueue, RecentlyCompletedWithdrawals) as a new MCP tool. Accepts status parameter: "queued" (default) or "completed". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(mcp): wait for SPV sync in query_withdrawals tool Platform queries require proof verification which needs SPV to be initialized. Without the sync wait, standalone CLI mode fails with "SPV client not initialized" after exhausting retries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(mcp): override bare `true` in describe_tool outputSchema schemars v1 derives bare `true` for serde_json::Value fields, which Claude Code's MCP client rejects during tools/list schema validation. Use `#[schemars(transform)]` to emit `{"type": "object"}` instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(mcp): add network verification guard to tools Add an optional `network` parameter to wallet, platform, and listing tools so MCP clients can assert the expected network before executing. If the caller provides a network name that does not match the server's active network, the request is rejected with an InvalidParams error. Tools guarded: generate_receive_address, wallet_balances, fetch_platform_address_balances, send_core_funds, query_withdrawals, list_wallets. Exempt (by design): network (discovery tool), describe_tool (meta). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update MCP, CLI, and CONTRIBUTING for current tool set - MCP.md: add all 8 tools to table (fetch_platform_address_balances, query_withdrawals, describe_tool were missing); add network verification section; add headless mode section; add Claude Code configuration example - CLI.md: add examples for query-withdrawals, fetch-platform-address-balances, describe-tool, and network guard usage; document headless subcommand - CONTRIBUTING.md: add headless feature to feature flags table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(mcp): rename tools to domain_object_action convention Adopt consistent naming: core_* for wallet/address operations, platform_* for Platform queries, tool_* and network_* for meta/infra. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add MCP/CLI architecture decisions to CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve merge artifacts after v1.0-dev merge Network::Dash was renamed to Network::Mainnet in dashcore; update two remaining references in src/mcp/server.rs that were missed during the v1.0-dev merge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Update src/mcp/server.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(mcp): typed McpToolError, input validation, mandatory network on send Replace String-based McpToolError with typed thiserror variants (WalletNotFound, InvalidParam, NetworkMismatch, SpvSyncFailed, TaskFailed, Internal) each mapped to a distinct MCP error code. Add input validation at the MCP layer for SendCoreFunds: reject zero amounts, validate Dash address prefix format, and require the 'network' parameter on destructive operations to prevent accidental cross-network transfers. Add INTENTIONAL(PROJ-003) annotation for tool_describe naming. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(mcp): auth hardening, API key minimum length, dispatch comment - Enforce minimum 16-character MCP_API_KEY at server startup; refuse to start and log error if too short. - Return JSON body {"error": "unauthorized"} on 401 instead of bare status code. - Log failed auth attempts at warn level with client address (never log the attempted key). - Add ConnectInfo<SocketAddr> extraction for auth logging. - Document why the dispatch channel receiver is intentionally dropped in headless/CLI mode. - Fix collapsible_if clippy lint in server.rs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: pub(crate) AppContext fields, deduplicate bash completion - Change AppContext.data_dir and .network from pub to pub(crate) and add data_dir()/network() accessor methods for external consumers. - Extract the bash completion wrapper script to a shared constant in completion.rs, eliminating duplication between generate and install. - Document TOCTOU-safe pattern in DashMcpService::ctx() docstring (each tool calls ctx() exactly once and passes the Arc snapshot). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(config): log parse failures instead of silently swallowing them Add tracing::debug! before .ok() when parsing per-network configs from environment variables, so parse errors are visible in logs instead of silently falling through to "no config found". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(mcp): add unit tests for MCP validation layer 15 tests covering: - API key length validation (too short rejected, 16+ accepted, empty) - Amount validation (zero rejected, positive accepted) - Address format validation (empty, valid mainnet/testnet, invalid prefix) - McpToolError Display output for all variants - MCP error code distinctness for custom codes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: headless build note, feature flag deps, MCP user stories - Add note in MCP.md that headless mode requires building from source. - Fix CONTRIBUTING.md feature flag table: clarify headless depends on cli + mcp rather than claiming all features are independent. - Add MCP-001 and MCP-002 user stories for CLI wallet management and AI agent MCP server access. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add guide for exposing backend tasks via MCP/CLI Add docs/EXPOSING_BACKEND_TASKS.md — a concise reference with architecture rules, step-by-step checklist, and don'ts for adding new MCP tools that wrap BackendTask variants. Cross-reference from CLAUDE.md and CONTRIBUTING.md. https://claude.ai/code/session_01D4TGENSgE6fFCrXn5iPMnD * fix: address review findings from CodeRabbit and Copilot - Fix jq query in bash completion: use `input_schema` (snake_case) instead of `inputSchema` (camelCase) to match rmcp serialization - Validate hex seed hash exists in wallet map before accepting it, preventing misleading errors for non-existent wallets - Version-check cache in print_tool_help() to reject stale entries - Add headless subcommand to custom help output (cfg-gated) - Return non-zero exit for unknown tool help lookups - Add Accept: application/json header to MCP curl examples Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address 7 PR review findings for MCP server - docs/MCP.md: mark `network` as required for `core_funds_send` - docs/CLI.md: add `network=testnet` to send example, remove misleading "optional" example - src/app.rs: initialize MCP HTTP server with context matching `chosen_network` instead of hardcoded mainnet - src/mcp/tools/wallet.rs: make `SendFundsParams.network` a non-optional `String` to match runtime requirement - docs/EXPOSING_BACKEND_TASKS.md: fix typo `InvalidParams` → `InvalidParam` - CLAUDE.md: fix same `InvalidParams` → `InvalidParam` typo - src/mcp/tests.rs: remove env var tests that race with parallel tests due to unsynchronized `set_var`/`remove_var` Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR #773 review comments across MCP server Bot issues fixed: - #35: WalletNotFound stores only the identifier, not full error sentence - #36: MCP log differentiates unset vs invalid MCP_API_KEY - #37: Release workflow splits GUI and CLI builds (GUI without --features cli, CLI with --features headless --bin det-cli) - #38: SendCoreFunds validates empty network string before require_network - #39: Remove unnecessary ensure_spv_synced() from QueryWithdrawals - #40: Remove input_schema() override from NetworkTool Human issues addressed: - #41: Tool table includes det-cli command column - #42: CLI section added to MCP.md - #43: Headless mode performance characteristics documented - #45: Authentication section with setup, behavior, and security guidance - #46: ListWalletsTool moved from network.rs to wallet.rs - #47: TODO added for withdrawal pagination (requires backend changes) - #48: TODO added for structured JSON output (requires new backend variant) - #49: Verified correct BackendTask dispatch for withdrawals Issue #44 (CLAUDE.md duplication): no actual duplication found — the MCP section in CLAUDE.md covers architecture guidance while docs/MCP.md covers usage. Both serve distinct purposes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 65358ef commit 68f4837

34 files changed

Lines changed: 3100 additions & 75 deletions

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,9 @@ LOCAL_core_rpc_user=dashmate
3333
# dashmate config get core.rpc.users.dashmate.password --config=local_seed
3434
LOCAL_core_rpc_password=password
3535
LOCAL_core_zmq_endpoint=tcp://127.0.0.1:50298
36+
37+
# MCP Server (Model Context Protocol)
38+
# Set an API key to enable the MCP HTTP server for programmatic access.
39+
# Leave empty or remove to disable. Binds to localhost only by default.
40+
MCP_API_KEY=
41+
MCP_LISTEN=127.0.0.1:9527

.github/workflows/release.yml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,20 @@ jobs:
9494
env:
9595
PROTOC: /usr/local/bin/protoc
9696

97-
- name: Build project
97+
- name: Build GUI
9898
run: |
9999
cargo build --release --target ${{ matrix.target }}
100100
mv target/${{ matrix.target }}/release/dash-evo-tool${{ matrix.ext }} dash-evo-tool/dash-evo-tool${{ matrix.ext }}
101101
env:
102102
OPENSSL_STATIC: "1"
103103

104+
- name: Build CLI (det-cli)
105+
run: |
106+
cargo build --release --features headless --bin det-cli --target ${{ matrix.target }}
107+
mv target/${{ matrix.target }}/release/det-cli${{ matrix.ext }} dash-evo-tool/det-cli${{ matrix.ext }}
108+
env:
109+
OPENSSL_STATIC: "1"
110+
104111
- name: Verify Windows binary is self-contained
105112
if: ${{ matrix.target == 'x86_64-pc-windows-gnu' }}
106113
run: |
@@ -203,6 +210,12 @@ jobs:
203210
cp target/aarch64-apple-darwin/release/dash-evo-tool build/dash-evo-tool
204211
chmod +x build/dash-evo-tool
205212
213+
- name: Build CLI (det-cli)
214+
run: |
215+
cargo build --release --features headless --bin det-cli --target aarch64-apple-darwin
216+
cp target/aarch64-apple-darwin/release/det-cli build/det-cli
217+
chmod +x build/det-cli
218+
206219
# Targeted cleanup - only remove build artifacts we don't need
207220
rm -rf target/aarch64-apple-darwin/release/deps
208221
rm -rf target/aarch64-apple-darwin/release/build
@@ -213,13 +226,15 @@ jobs:
213226
214227
# Remove the actual binary from target since we copied it
215228
rm -f target/aarch64-apple-darwin/release/dash-evo-tool
229+
rm -f target/aarch64-apple-darwin/release/det-cli
216230
217231
# Create app bundle structure
218232
mkdir -p "build/Dash Evo Tool.app/Contents/MacOS"
219233
mkdir -p "build/Dash Evo Tool.app/Contents/Resources"
220234
221235
# Move binary into app bundle
222236
cp build/dash-evo-tool "build/Dash Evo Tool.app/Contents/MacOS/dash-evo-tool"
237+
cp build/det-cli "build/Dash Evo Tool.app/Contents/MacOS/det-cli"
223238
224239
# Create icon set and convert to ICNS
225240
mkdir -p AppIcon.iconset
@@ -487,10 +502,12 @@ jobs:
487502
488503
- name: Build x86_64 architecture
489504
run: |
490-
cargo build --release --target x86_64-apple-darwin
505+
cargo build --release --features cli --target x86_64-apple-darwin
491506
mkdir -p build
492507
cp target/x86_64-apple-darwin/release/dash-evo-tool build/dash-evo-tool
493508
chmod +x build/dash-evo-tool
509+
cp target/x86_64-apple-darwin/release/det-cli build/det-cli
510+
chmod +x build/det-cli
494511
495512
# Targeted cleanup - only remove build artifacts we don't need
496513
rm -rf target/x86_64-apple-darwin/release/deps
@@ -502,13 +519,15 @@ jobs:
502519
503520
# Remove the actual binary from target since we copied it
504521
rm -f target/x86_64-apple-darwin/release/dash-evo-tool
522+
rm -f target/x86_64-apple-darwin/release/det-cli
505523
506524
# Create app bundle structure
507525
mkdir -p "build/Dash Evo Tool.app/Contents/MacOS"
508526
mkdir -p "build/Dash Evo Tool.app/Contents/Resources"
509527
510528
# Move binary into app bundle
511529
cp build/dash-evo-tool "build/Dash Evo Tool.app/Contents/MacOS/dash-evo-tool"
530+
cp build/det-cli "build/Dash Evo Tool.app/Contents/MacOS/det-cli"
512531
513532
# Create icon set and convert to ICNS
514533
mkdir -p AppIcon.iconset

CLAUDE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ User-facing error messages (shown in `MessageBanner` via `Display`) must follow
102102
- **spv/** - Simplified Payment Verification for light wallet support
103103
- **components/core_zmq_listener** - Real-time Dash Core event listening via ZMQ
104104

105+
### MCP Server & CLI (`src/mcp/`, `src/bin/det_cli/`)
106+
107+
- **Dual transport**: HTTP (`mcp` feature, embedded in GUI via ArcSwap) and stdio (`cli` feature, lazy-init standalone). `headless` combines both.
108+
- **CLI ≠ MCP**: `src/bin/det_cli/` is a separate client that talks to the MCP server — it must work over HTTP too, not just in-process. Never put tool logic in the CLI binary; tools live in `src/mcp/tools/` and the CLI discovers them dynamically via `tools/list`.
109+
- **Tool architecture**: each tool is a struct implementing `ToolBase` (metadata) + `AsyncTool<DashMcpService>` (invocation). Adding a tool requires only the struct + registering in `tool_router()` — zero CLI changes.
110+
- **Tool naming**: `{domain}_{object}_{action}` — e.g. `core_address_create`, `platform_withdrawals_get`, `tool_describe`. CLI converts underscores to hyphens.
111+
- **Context provider**: `ContextProvider::Shared(ArcSwap)` for HTTP mode (follows GUI network switches), `ContextProvider::Lazy(OnceCell)` for stdio (init on first tool call).
112+
- **Network safety**: tools accept optional `network` param — request fails if it doesn't match the active network. Exempt: `network_info`, `tool_describe`.
113+
- **SPV sync**: wallet tools call `resolve::ensure_spv_synced()` before operating — polls SPV status with 1s interval, 10min timeout.
114+
- **Backend dispatch**: tools reuse the app's `BackendTask` system via `dispatch::dispatch_task()` — creates a throwaway channel, calls `app_context.run_backend_task()`.
115+
- **Schema quirk**: `schemars` v1 derives bare `true` for `serde_json::Value` fields — some MCP clients reject this. Use `#[schemars(transform)]` to override.
116+
- **Error type**: `McpToolError` enum (InvalidParam, WalletNotFound, SpvSyncFailed, TaskFailed, Internal) converts to `rmcp::ErrorData` via `From`.
117+
- **Docs**: `docs/MCP.md` (server config, tool reference), `docs/CLI.md` (usage, examples), `docs/EXPOSING_BACKEND_TASKS.md` (checklist for adding new MCP tools).
118+
105119
### Key Dependencies
106120

107121
- `dash-sdk` - Dash blockchain SDK (git dep from dashpay/platform)

CONTRIBUTING.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,24 @@ Run the application:
6060
cargo run
6161
```
6262

63+
## Feature flags
64+
65+
The default `cargo build` produces only the `dash-evo-tool` GUI binary. Optional features enable additional capabilities:
66+
67+
| Feature | Binary | What it adds |
68+
|---|---|---|
69+
| _(none)_ | `dash-evo-tool` | GUI application (default) |
70+
| `mcp` | `dash-evo-tool` | Embeds an MCP HTTP server in the GUI app. Activated at runtime by setting `MCP_API_KEY`. See [docs/MCP.md](docs/MCP.md). |
71+
| `cli` | `det-cli` | Standalone CLI binary. Includes an in-process MCP service (no server needed), HTTP client mode, `det-cli serve` stdio server, tool caching, and shell completion. See [docs/CLI.md](docs/CLI.md). |
72+
| `headless` | `det-cli` | Combines `cli` + `mcp` for headless HTTP server mode via `det-cli headless`. No GUI required; `MCP_API_KEY` must be set. See [docs/MCP.md](docs/MCP.md). |
73+
| `testing` || Test-only utilities (not for production builds) |
74+
75+
`mcp` and `cli` are independent of each other. `headless` depends on both `cli` and `mcp` (it enables both automatically).
76+
77+
### Adding MCP tools
78+
79+
To expose a `BackendTask` as a new MCP/CLI tool, follow the step-by-step checklist in [docs/EXPOSING_BACKEND_TASKS.md](docs/EXPOSING_BACKEND_TASKS.md). It covers architecture rules, the standard invocation pattern, registration, and common pitfalls.
80+
6381
## Code quality
6482

6583
Before submitting changes, run the formatter and linter:

0 commit comments

Comments
 (0)