Skip to main content

Basics

Let’s use the Neva MCP client to connect to your MCP servers (and others too).

Create an app

Create a new binary-based app:

cargo new neva-mcp-client
cd neva-mcp-client

Add the following dependencies in your Cargo.toml:

[dependencies]
neva = { version = "...", features = "client-full" }
tokio = { version = "1", features = ["full"] }

Call a tool

First, let’s call the tool we created in the server basics.

use neva::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Error> {
let mut client = Client::new()
.with_options(|opt| opt
.with_stdio(
"cargo",
["run", "--manifest-path", "./neva-mcp-server/Cargo.toml"]));

client.connect().await?;

let args = ("name", "John");
let result = client.call_tool("hello", args).await?;

println!("{:?}", result.content);

client.disconnect().await
}

Here we configure the MCP Client to connect to the server via stdio.
Once connected, you can call tools, get prompts, or read resources until you disconnect (or the client is dropped).

disconnect() is local

It shuts down the transport and sends nothing on the wire. There is no goodbye message in the protocol — the param-less notifications/cancelled neva used to send does not validate against the spec's own schema, and a server learns the client is gone from the closed connection anyway.

Get a Prompt

Next, let’s fetch a prompt to see how prompts work from the client side.

let args = ("lang", "Rust");
let prompt = client.get_prompt("hello_world_code", args).await?;

Read a Resource

Then, let's read a resource that we declared here.

let resource = client.read_resource("res://resource-1").await?;

List Of Tools, Prompts, and Resources

Finally, here’s how to explore all available tools, prompts, and resources dynamically.

// Returns a list of tools
let tools = client
.list_tools(None)
.await?;

// Returns a list of resources
let resources = client
.list_resources(None)
.await?;

// Returns a list of resource templates
let templates = client
.list_resource_templates(None)
.await?;

// Returns a list of prompts
let prompts = client
.list_prompts(None)
.await?;

Pagination

Large lists are returned in pages of 10 items by default.
Use the next_cursor value to fetch subsequent pages:

// First 10
let resources = client
.list_resources(None)
.await?;

// Next 10
let resources = client
.list_resources(resources.next_cursor)
.await?;

// Next 10
let resources = client
.list_resources(resources.next_cursor)
.await?;

Listings are ordered deterministically by name on the server side, so paging can no longer skip or repeat an entry. See Listing Order.

Caching

Every list result — and server/discover and resources/read — carries ttlMs and cacheScope. Both are mandatory members under MCP 2026-07-28 rather than optional hints, so a client can always tell how long a result stays fresh and who may share it:

cacheScopeMeaning
privateCacheable only for this client (the default)
publicShareable across clients

Learn By Example

Here you may find the full example