Commit 68f4837
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
File tree
- .github/workflows
- docs
- src
- bin/det_cli
- context
- mcp
- tools
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
97 | | - | |
| 97 | + | |
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
104 | 111 | | |
105 | 112 | | |
106 | 113 | | |
| |||
203 | 210 | | |
204 | 211 | | |
205 | 212 | | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
206 | 219 | | |
207 | 220 | | |
208 | 221 | | |
| |||
213 | 226 | | |
214 | 227 | | |
215 | 228 | | |
| 229 | + | |
216 | 230 | | |
217 | 231 | | |
218 | 232 | | |
219 | 233 | | |
220 | 234 | | |
221 | 235 | | |
222 | 236 | | |
| 237 | + | |
223 | 238 | | |
224 | 239 | | |
225 | 240 | | |
| |||
487 | 502 | | |
488 | 503 | | |
489 | 504 | | |
490 | | - | |
| 505 | + | |
491 | 506 | | |
492 | 507 | | |
493 | 508 | | |
| 509 | + | |
| 510 | + | |
494 | 511 | | |
495 | 512 | | |
496 | 513 | | |
| |||
502 | 519 | | |
503 | 520 | | |
504 | 521 | | |
| 522 | + | |
505 | 523 | | |
506 | 524 | | |
507 | 525 | | |
508 | 526 | | |
509 | 527 | | |
510 | 528 | | |
511 | 529 | | |
| 530 | + | |
512 | 531 | | |
513 | 532 | | |
514 | 533 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
105 | 119 | | |
106 | 120 | | |
107 | 121 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
63 | 81 | | |
64 | 82 | | |
65 | 83 | | |
| |||
0 commit comments