contextvm-sdk 0.1.0

Rust SDK for the ContextVM protocol — MCP over Nostr
Documentation
# Transport Guide

Use this page when you want to understand the transport layer itself.

If you are building a normal native server or client, start with the dedicated native server or native client guide first.

- `NostrClientTransport`: client-side direct transport
- `NostrServerTransport`: server-side direct transport

## Why use the transport layer directly

Use transports directly when you need to:

- integrate with your own request loop
- control announcement timing yourself
- tune authorization and session behavior
- embed the transport in higher-level abstractions

## Signer choice

All transport constructors accept an existing signer, not just a newly generated one.

- Use `generate()` for temporary identities in examples, tests, and short-lived sessions.
- Use `from_sk()` when you need a stable identity backed by a pre-existing hex or `nsec` private key.

```rust
use contextvm_sdk::signer;

let signer = signer::from_sk("<hex-or-nsec-private-key>")?;
```

## Low-level client transport example

```rust
use contextvm_sdk::core::types::{JsonRpcMessage, JsonRpcRequest};
use contextvm_sdk::signer;
use contextvm_sdk::transport::client::{
    NostrClientTransport, NostrClientTransportConfig,
};

#[tokio::main]
async fn main() -> contextvm_sdk::Result<()> {
    let keys = signer::generate();
    let mut transport = NostrClientTransport::new(
        keys,
        NostrClientTransportConfig {
            relay_urls: vec!["wss://relay.damus.io".to_string()],
            server_pubkey: "<server-hex-pubkey>".to_string(),
            ..Default::default()
        },
    )
    .await?;

    transport.start().await?;
    let mut rx = transport.take_message_receiver().expect("receiver available");

    transport
        .send(&JsonRpcMessage::Request(JsonRpcRequest {
            jsonrpc: "2.0".to_string(),
            id: serde_json::json!(1),
            method: "tools/list".to_string(),
            params: None,
        }))
        .await?;

    if let Some(message) = rx.recv().await {
        println!("received: {:?}", message);
    }

    transport.close().await?;
    Ok(())
}
```

## Low-level server transport example

```rust
use contextvm_sdk::core::types::{JsonRpcMessage, JsonRpcResponse};
use contextvm_sdk::signer;
use contextvm_sdk::transport::server::{
    NostrServerTransport, NostrServerTransportConfig,
};

#[tokio::main]
async fn main() -> contextvm_sdk::Result<()> {
    let keys = signer::generate();
    let mut transport = NostrServerTransport::new(
        keys,
        NostrServerTransportConfig {
            is_announced_server: true,
            ..Default::default()
        },
    )
    .await?;

    transport.start().await?;
    let mut rx = transport.take_message_receiver().expect("receiver available");

    while let Some(req) = rx.recv().await {
        if let Some(id) = req.message.id() {
            transport
                .send_response(
                    &req.event_id,
                    JsonRpcMessage::Response(JsonRpcResponse {
                        jsonrpc: "2.0".to_string(),
                        id: id.clone(),
                        result: serde_json::json!({"ok": true}),
                    }),
                )
                .await?;
        }
    }

    Ok(())
}
```

## Server-side semantics to understand

The server transport does more than relay bytes.

It manages:

- multi-client session state
- request route storage
- authorization via `allowed_public_keys`
- allowlist bypasses via `CapabilityExclusion`
- announcement publication
- encryption negotiation and response mirroring

Those behaviors are part of the server transport implementation and are exercised heavily by the integration tests.

## What the server receives

Incoming traffic is delivered as `IncomingRequest`, which includes:

- the parsed `JsonRpcMessage`
- the client pubkey
- the original Nostr request event id
- whether the incoming message was encrypted

That extra metadata is what allows correct response routing and encryption mirroring.