Repository navigation
v0.7.0
neva 0.7.0 hands MCP tools to a model through svir, gives Client and Context a namespaced API, and cancels the requests a client gives up on, on the wire and on the server. It is a minor bump for three narrow source breaks; see Migration. MSRV is unchanged at 1.90.
The svir bridge
New svir feature, neva::svir: MCP tools as a svir::Toolbox, for handing them to a model. A connected server's tools, or a server's own, called in-process through its middleware, so authorization, rate limits and audit apply to the model as to any other caller (#144).
use neva::svir::RemoteTools;
use svir::Toolbox;
// A connected server's tools, under a prefix of their own...
let tools = RemoteTools::new(client).with_prefix("board_").load().await?;
// ...or this server's own, with no MCP in between:
// let tools = app.into_toolbox().load().await?;
let model = svir::Client::openai("http://127.0.0.1:1234").build()?;
let request = svir::Request::new("qwen3").user("Plan my week").tools(&tools);
let done = model.complete(&request).await?;
let results = tools.call_all(&done.calls).await;RemoteToolswraps a connectedClient, or anArcof one;App::into_toolboxconsumes the server,App::with_toolboxkeeps it serving as well, andctx.tools().toolbox()hands a model the server's tools from inside a handler, holding that request's claims.filter,renameandwith_prefixchoose what is offered and under which name; a call runs the tool the server knows by the original name. A name a model API cannot carry, or one two tools share, failsloadinstead of being renamed behind your back.ctx.tools().toolbox()leaves out the tool it is called from, which would otherwise start its loop over inside its own call (#147);with_caller()keeps it for a tool that means to recurse. In-process calls nest at most four deep, counted along the chain whichever toolbox makes them;with_max_depth(n)changes the bound.prompt_messagesandresource_partsturn a prompt and a resource into svir messages;sampling_requestandsampling_resultanswer a server's sampling with a model, tool calls included (#150).
The feature is in neither server-full nor client-full while svir is 0.x. The model call itself is svir's (its client feature). Example: examples/svir.
A namespaced API on Client and Context
One namespace per MCP method prefix (#143):
let client = Arc::new(client); // request methods take `&self` now
for tool in client.tools().list_all().await? {
println!("{}", tool.name);
}
let sum = client.tools().call("add", [("a", 1), ("b", 2)]).await?;
let page = client.resources().list(None).await?;client.tools(),resources(),prompts()andtasks(); on a handler'sContext,ctx.tools(),resources()andprompts().list_all()walks every page, and fails rather than return a partial list past 64 pages.tools().as_task()starts a task-augmented call.Clientrequest methods take&self, so a connected client can be shared across tasks; setup (connect,map_*,on_*, roots) keeps&mut self.Contextmethods take&selftoo.
The flat methods are deprecated, not removed; each #[deprecated] note names its replacement.
Abandoned requests are cancelled
MCP 2026-07-28 makes closing the response stream the cancellation over Streamable HTTP, has the client send notifications/cancelled over stdio, and has the sender cancel on a timeout. neva used to stop waiting and leave the request running on the server (#152).
- Client. A request that times out or whose call is dropped is cancelled, the requests of an abandoned
call_batchincluded;initializenever is. Under 2026-07-28 over Streamable HTTP that is closing the request's stream; over stdio and to a legacy peer,notifications/cancelledwith the reason. - Server, 2026-07-28 HTTP. A POST closed before its answer cancels the requests it carried; a
subscriptions/listenamong them ends through its stream instead. The handler used to run on to an answer no one read. Since 0.4.0. - Server, both profiles. A
notifications/cancelledon an HTTP session, batched or not, now finds its request; since 0.1.0 it was looked up without the session and cancelled nothing. A cancel that overtakes its request on the way to the handler is no longer lost, and a request cancelled by then never starts its handler.
Migration
ctx.tools() returns the tools namespace. ctx.tools().await no longer compiles, as the namespace is not a future; write ctx.tools().list().await.
TaskApi methods take &self, and wait_to_completion takes &A. Only implementations of TaskApi outside neva need the new receivers; callers are unaffected.
map_sampling is bound by ClientHandler<_, Result<CreateMessageResult, Error>, _>, so a sampling handler can fail: under legacy-spec the error answers the server, or fails the sampling task; under 2026-07-28 the asking call fails with it. A handler returning CreateMessageResult still fits; only code naming the old bound changes.
Deprecated, with their replacements: client.list_tools(cursor) -> client.tools().list(cursor), call_tool(name, args) -> tools().call(name, args), read_resource(uri) -> resources().read(uri), get_prompt(name, args) -> prompts().get(name, args); on Context, find_tool(name) -> ctx.tools().find(name), add_tool(tool) -> ctx.tools().add(tool), resource(uri) -> ctx.resources().read(uri), and so on.
Behaviour changes
- A request the client stops waiting for is cancelled on the wire, as above. A server that relied on finishing work its caller abandoned now sees it cancelled.
- Under 2026-07-28 the HTTP server stops a request whose POST the client closed.
- Over Streamable HTTP under 2026-07-28, a cancelled subscription is ended by closing its stream alone, without a
notifications/cancelledPOST. call_batchsends its requests under ids the client generates, and puts the caller's ids back on the responses: a caller-chosen id can no longer collide with one in flight.mut ctxin a handler now warns (unused_mut), asContextmethods take&self.
Fixed
Client::subscribeand theon_*_changedhelpers no longer panic on acurrent_threadruntime (#139). Since 0.0.8.- A
tasks/updateortasks/cancelthe server refuses is an error, notOk(()), andwait_to_completionstops at it. Since 0.5.4. tools().call_rawkeeps the_metaits params carry, atraceparentsay, instead of replacing it (#145). Since 0.2.5. A request's own trace context wins over the trace context provider's (#137). Since 0.4.0.- Under
legacy-spec, the client answers a failedtasks/resultwith the error's own code, not alwaysInvalidParams. x-mcp-header: atools/listtraversal that starts over no longer clears the registrations of later pages or lifts the block on a malformed tool.
The full list is in CHANGELOG.md. Diff: 0.6.2...0.7.0.