phase 1 scaffold: cargo workspace + 3 crates + roadmap + architecture
Repo skeleton for aldabra, the rust-native cardano lite wallet
with MCP server interface. Builds end-to-end, types in place,
real cardano primitives land next pass.
Crates:
wallet-core — pure crypto + types. mnemonic, key derivation,
signing. No I/O. Security boundary.
wallet-chain — pluggable backends. ChainBackend trait, Koios
client (stub for now). Ogmios + submit in phase 2.
wallet-mcp — the binary. stdio MCP transport via rmcp.
Phase plan in ROADMAP.md, threat model in docs/architecture.md.
This is also Sulkta's first Rust project + a real-world workout for
ci-runner's rust toolchain.
This commit is contained in:
commit
56bcceb593
11 changed files with 735 additions and 0 deletions
30
crates/wallet-mcp/Cargo.toml
Normal file
30
crates/wallet-mcp/Cargo.toml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# wallet-mcp — the binary. MCP server speaking stdio that exposes
|
||||
# the wallet's tools to an LLM. Spawned as a subprocess from any MCP
|
||||
# client (e.g. Claude Code).
|
||||
#
|
||||
# Owns: process lifecycle, stdio transport, config loading, glue
|
||||
# between core + chain crates.
|
||||
|
||||
[package]
|
||||
name = "wallet-mcp"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license-file.workspace = true
|
||||
repository.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "aldabra"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
wallet-core = { path = "../wallet-core" }
|
||||
wallet-chain = { path = "../wallet-chain" }
|
||||
|
||||
tokio = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
rmcp = { workspace = true }
|
||||
74
crates/wallet-mcp/src/main.rs
Normal file
74
crates/wallet-mcp/src/main.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
//! aldabra — MCP server entry point.
|
||||
//!
|
||||
//! Speaks MCP over stdio. Any MCP client (e.g. Claude Code)
|
||||
//! launches this as a subprocess and gets a wallet's worth of tools.
|
||||
//!
|
||||
//! ## Phase 1 tools
|
||||
//!
|
||||
//! - `wallet.address` — return the derived base address (placeholder
|
||||
//! until wallet-core's CIP-1852 derivation lands)
|
||||
//! - `wallet.balance` — query balance via the configured chain backend
|
||||
//!
|
||||
//! ## Phase 2-4 tools (TODO)
|
||||
//!
|
||||
//! See ROADMAP.md at the repo root.
|
||||
//!
|
||||
//! ## Config
|
||||
//!
|
||||
//! For now: hardcoded mainnet + a stub Koios client. Real config
|
||||
//! loading + mnemonic-from-encrypted-file lands once the core
|
||||
//! derivation API is real.
|
||||
//!
|
||||
//! ## Logging
|
||||
//!
|
||||
//! Stderr only — stdout is the MCP transport, must stay clean.
|
||||
|
||||
use anyhow::Result;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// Stderr only — stdout is MCP transport
|
||||
tracing_subscriber::fmt()
|
||||
.with_writer(std::io::stderr)
|
||||
.with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
|
||||
.init();
|
||||
|
||||
tracing::info!("aldabra starting (phase 1 scaffold)");
|
||||
|
||||
// TODO(phase 1):
|
||||
// 1. Load config (network, koios url, mnemonic path)
|
||||
// 2. Bootstrap mnemonic (interactive on first run, age-decrypt thereafter)
|
||||
// 3. Derive root key
|
||||
// 4. Build the chain backend
|
||||
// 5. Construct the MCP server with tool handlers
|
||||
// 6. Run it on stdio
|
||||
|
||||
// For now: a smoke-test print so the binary actually does something
|
||||
// when invoked manually (not through MCP).
|
||||
tracing::info!(
|
||||
target_address = %wallet_core::derive_base_address(
|
||||
&dummy_root_key()?,
|
||||
wallet_core::Network::Mainnet,
|
||||
0,
|
||||
0,
|
||||
)?,
|
||||
"scaffold smoke test — derived placeholder address",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Phase 1 only — produces a zero-bytes RootKey so the placeholder
|
||||
/// address derivation runs. Will be deleted once real mnemonic loading
|
||||
/// lands.
|
||||
fn dummy_root_key() -> Result<wallet_core::RootKey> {
|
||||
// Need a way to construct one from this crate without exposing
|
||||
// private fields. Phase 1: temporary public constructor on
|
||||
// wallet-core, gated behind a #[cfg(test)] or feature flag and
|
||||
// removed before phase 2.
|
||||
//
|
||||
// For tonight: this fn is a TODO marker — the smoke test won't
|
||||
// actually run until we finish wallet-core::Mnemonic::into_root_key.
|
||||
anyhow::bail!("phase 1 scaffold: real mnemonic loading not yet implemented")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue