The Rust SDK exposes public discovery helpers for finding announced servers and their published capabilities.
These functions query public announcement events so clients can find servers before opening a direct session.
The current implementation supports:
- servers via
discover_servers() - tools via
discover_tools() - resources via
discover_resources() - prompts via
discover_prompts() - resource templates via
discover_resource_templates()
When the rmcp feature is enabled, typed variants are also available for tools, resources, prompts, and resource templates.
This follows the repository discovery example.
use contextvm_sdk::discovery;
use contextvm_sdk::relay::RelayPool;
use contextvm_sdk::signer;
#[tokio::main]
async fn main() -> contextvm_sdk::Result<()> {
let keys = signer::generate();
let relays = vec!["wss://relay.damus.io".to_string()];
let relay_pool = RelayPool::new(keys).await?;
relay_pool.connect(&relays).await?;
let client = relay_pool.client();
let servers = discovery::discover_servers(client, &relays).await?;
for server in &servers {
println!("server: {:?}", server.server_info.name);
let tools = discovery::discover_tools(client, &server.pubkey_parsed, &relays).await?;
println!("tools: {}", tools.len());
}
relay_pool.disconnect().await?;
Ok(())
}The event kinds follow the public announcement model summarized in the repository root README:
11316: server announcement11317: tools list11318: resources list11319: resource templates11320: prompts list
These event kinds are the SDK's public discovery model for server metadata and advertised MCP capabilities.
Clients can discover which relays a server uses without hardcoding relay URLs. Set server_pubkey to an nprofile (which embeds relay hints) and leave relay_urls empty:
NostrClientTransportConfig::default()
.with_server_pubkey("nprofile1...") // contains pubkey + relay hintsWhen start() is called with empty relay_urls, the transport runs a 6-stage resolution pipeline:
- Configured relays -- if
relay_urlsis non-empty, use them directly - nprofile hints -- relay URLs embedded in the nprofile identity
- CEP-17 discovery -- fetch kind 10002 relay-list events from bootstrap relays
- Fallback probing -- probe
fallback_operational_relay_urlsin parallel with discovery - Sequential fallback -- if the race winner returned empty, await the other
- Bootstrap default -- fall back to
DEFAULT_BOOTSTRAP_RELAY_URLSas last resort
The discovery_relay_urls and fallback_operational_relay_urls config fields customize stages 3-4.
- discovery is public metadata, not a replacement for direct transport negotiation
- the current helpers fetch and parse latest public lists, but they do not replace direct session learning
- direct session learning still matters for encryption preferences, gift-wrap support, and first-message capability hints on an active connection