Skip to content

Remove dependency on tokio/rt and tokio::spawn(...)#710

Draft
AadamZ5 wants to merge 9 commits intomodelcontextprotocol:mainfrom
AadamZ5:dev/remove-tokio-rt
Draft

Remove dependency on tokio/rt and tokio::spawn(...)#710
AadamZ5 wants to merge 9 commits intomodelcontextprotocol:mainfrom
AadamZ5:dev/remove-tokio-rt

Conversation

@AadamZ5
Copy link

@AadamZ5 AadamZ5 commented Feb 28, 2026

These changes aim to remove most calls to tokio::spawn(...) and other runtime-intertwined calls. These changes are to support runtime-agnosticism.

Motivation and Context

This will allow the project to be used in other environments where tokio/rt is not available or cannot be used. I originally raised this issue in #290, but some real demand for this particular change may be present in #379.

Ultimately, the goal is to remove dependency on the Tokio runtime. However, as I progress, I see a few repeated smaller sub-issues I am trying to tackle to accomplish the larger goal:

  • Remove calls to tokio::spawn(...) (which mostly encompasses below)
  • Remove async side effects (via tokio::spawn(...)) in Drop implementations
  • Give control to the caller for how to run asynchronous background work

How Has This Been Tested?

This refactor should be testable via the existing unit tests. As development continues, we can add more unit tests if needed. I also hope to perform real smoke-test, minimally using the already existing examples in this repo.

Breaking Changes

Yes, users will most likely need to update their code. This will very likely be a breaking change.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

This is an ongoing draft. Please feel free to interject with comments or concerns.

Could eventually close #290

Refactor by using a worker future and bubling that up to the top-level of the API.

The callee is now responsible for polling the worker task, or else no work will get done.
@github-actions github-actions bot added T-dependencies Dependencies related changes T-test Testing related changes T-config Configuration file changes T-core Core library changes T-service Service layer changes T-transport Transport layer changes labels Feb 28, 2026
larger refactor for the way progress is multiplexed

this needed a redesign of the broadcast multiplex logic to a more stateless design.

this design removes the need for mutating any state on drop,

the stream dropping implicitly removes broadcast listeners.

this design also allows for multiple subscribers of the same progress token.
@github-actions github-actions bot added the T-handler Handler implementation changes label Mar 1, 2026
@AadamZ5
Copy link
Author

AadamZ5 commented Mar 1, 2026

Next note for myself: crates/rmcp/src/transport/child_process.rs will need a lot of consideration about how to refactor to be runtime-agnostic or at least adaptable. We could include feature-guarded implementations of a new ChildProcessRunner trait, perhaps wrapped in a common struct to ease usage.

Idea:

/// Underlying implementation and contract about what a command runner needs to provide
pub trait ChildProcessRunner {
   pub fn send_input(&self, input &[u8]) -> Result<...>;

   pub fn get_output_stream(&self) -> Result<PinnedStream<Vec<u8>>, ...>;
   pub fn get_exit_code(&self) -> Result<u8, ...>;
}

/// The `ChildProcess` struct would "control" the runner, and properly orchestrate methods calls (like
/// ensuring only one call to `get_output_stream(...)` etc)
///
/// This would simplify usage for the caller or library user
pub struct ChildProcess {
   inner: Box<dyn ChildProcessRunner>;
}

Then we could provide different implementations for the command runner, or provide a way for the library consumer to provide their own.

All of the ChildProcess usage might need to be behind a feature-flag.

Edit: I discovered the project is using the process_wrap crate, going to learn about that first before I make any major changes :)

@github-actions github-actions bot added the T-examples Example code changes label Mar 1, 2026
@AadamZ5
Copy link
Author

AadamZ5 commented Mar 1, 2026

The ChildProcess API seems to be functional. We can later write an async-std implementation now without changing too many concrete types 😀 I hope that refactor is not too disruptive from a user standpoint. I did try to update and run unit tests involving ChildProcess stuff. It could use a little more documentation about how to write one's own implementation for command running.

Still need to continue eliminating calls to tokio::spawn(...). There are plenty still, but a manageable amount! And fyi, I am not removing calls to tokio::spawn(...) in examples or tests. I think those are typically appropriate places to setup and use a runtime.

Comment on lines -236 to -245
#[cfg(unix)]
#[cfg(test)]
mod tests {
use tokio::process::Command;

use super::*;

#[tokio::test]
async fn test_tokio_child_process_drop() {
let r = TokioChildProcess::new(Command::new("sleep").configure(|cmd| {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, need to bring back some command tests.

@@ -1,2 +1,2 @@
#[cfg(feature = "transport-streamable-http-client-reqwest")]
mod streamable_http_client;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This did not need to be changed.

pub mod http_header;

#[cfg(feature = "__reqwest")]
mod reqwest;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This did not need to be changed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-config Configuration file changes T-core Core library changes T-dependencies Dependencies related changes T-examples Example code changes T-handler Handler implementation changes T-service Service layer changes T-test Testing related changes T-transport Transport layer changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove dependency on tokio/rt

1 participant