v0.2: 8 chain_* read-only Koios passthrough MCP tools

Adds a parallel read-only API surface alongside wallet_*:

  chain_tx_info        full Koios tx_info (any hash)
  chain_address_info   balance + utxos at any address
  chain_pool_list      filter by ticker / pool_id_bech32
  chain_pool_info      detail per pool (delegators, blocks)
  chain_epoch_params   protocol params for an epoch
  chain_asset_info     supply, holders, mint history
  chain_account_info   stake address state
  chain_tip            current chain tip

All passthrough — Koios JSON returned verbatim, no re-shaping.
Network-aware via existing ALDABRA_KOIOS_BASE; mainnet vs preprod
just changes the URL. No keys touched, no signing path. Saves
the bash-curl friction Sulkta flagged 2026-05-05 mid-mainnet
testing arc.

Wire-up: KoiosClient gets `post_raw_json` + `get_raw_json`
helpers that return raw response strings instead of decoding
into typed structures. The chain_* tools are thin wrappers
around those.

ServerInfo `instructions` updated to advertise the chain_*
surface alongside wallet_*.
This commit is contained in:
Sulkta 2026-05-05 07:01:32 -07:00
parent 0777e9e91d
commit 1e7e2bcab6
2 changed files with 247 additions and 1 deletions

View file

@ -145,6 +145,51 @@ impl KoiosClient {
.await
.map_err(|e| ChainError::Decode(e.to_string()))
}
/// Generic POST that returns the raw JSON response as a `String` —
/// for the `chain_*` MCP passthrough tools where we don't want to
/// re-shape Koios's response into typed Rust structures. Caller
/// passes a serializable body (often `serde_json::json!({...})`)
/// and gets back the response body verbatim.
pub async fn post_raw_json<T: Serialize>(
&self,
path: &str,
body: &T,
) -> Result<String, ChainError> {
self.http
.post(self.url(path))
.json(body)
.send()
.await
.map_err(|e| ChainError::Network(e.to_string()))?
.error_for_status()
.map_err(|e| ChainError::Network(e.to_string()))?
.text()
.await
.map_err(|e| ChainError::Decode(e.to_string()))
}
/// Generic GET (with optional query string) that returns the raw
/// JSON response as a `String`. Used for Koios endpoints that
/// take filters as query params (`pool_list?ticker=eq.AHL`,
/// `epoch_params`, `tip`, etc.).
pub async fn get_raw_json(
&self,
path: &str,
query: &[(&str, &str)],
) -> Result<String, ChainError> {
self.http
.get(self.url(path))
.query(query)
.send()
.await
.map_err(|e| ChainError::Network(e.to_string()))?
.error_for_status()
.map_err(|e| ChainError::Network(e.to_string()))?
.text()
.await
.map_err(|e| ChainError::Decode(e.to_string()))
}
}
fn parse_u64(s: &str, field: &str) -> Result<u64, ChainError> {