Skip to content

test: add new tests for client runtime #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 61 additions & 27 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -3,24 +3,23 @@ on:
push:
branches:
- main
# pull_request:
# branches:
# - "**"
workflow_call:

# on:
# push:
# branches:
# - main
# pull_request:
# branches:
# - "**"
#

jobs:
rust_check:
name: Rust check
runs-on: ubuntu-latest
name: Rust Checks (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
fail-fast: false # Continue testing other OSes even if one fails
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Cache Rust
uses: actions/cache@v4
with:
@@ -29,42 +28,77 @@ jobs:
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-rust-${{ steps.toolchain.outputs.cachekey }}
restore-keys: ${{ runner.os }}-rust-
key: ${{ matrix.os }}-rust-${{ hashFiles('Cargo.lock') }}
restore-keys: ${{ matrix.os }}-rust-

- name: Install Rust Toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: rustfmt
components: rustfmt, clippy

- uses: davidB/rust-cargo-make@v1
- uses: taiki-e/install-action@nextest
- name: Install cargo-make
uses: davidB/rust-cargo-make@v1

- name: Install nextest
uses: taiki-e/install-action@nextest

- name: Run Clippy
run: |
cargo make clippy
run: cargo make clippy
continue-on-error: false

- name: Run Rustfmt
run: |
cargo make fmt
run: cargo make fmt -- --check
if: matrix.os == 'ubuntu-latest' # Run fmt only on Linux

- name: Run cargo doc
env:
RUSTDOCFLAGS: "-Dwarnings"
run: cargo doc --no-deps
if: matrix.os == 'ubuntu-latest' # Run doc only on Linux

- name: Spell Check
env:
RUSTDOCFLAGS: "-Dwarnings"
uses: crate-ci/typos@master
if: matrix.os == 'ubuntu-latest' # Run typos only on Linux

- name: Audit
- name: Audit Dependencies
uses: actions-rust-lang/audit@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
if: matrix.os == 'ubuntu-latest' # Run audit only on Linux

# install nodejs that is required for tests
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20" # Stable Node.js version
# Verify npx is available
- name: Verify npx
run: npx --version
shell: bash

- name: Install server-everything globally
run: npm install -g @modelcontextprotocol/server-everything
shell: bash

# install Python and uvx that is required for tests
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11" # Stable Python version

- name: Install uv
run: pip install uv
shell: bash

- name: Verify uvx
run: uvx --version
shell: bash

- name: Run Tests
run: |
cargo make test
run: cargo make test
shell: bash # Ensure consistent shell

- name: Run Doc Tests
run: |
cargo make doc-test
run: cargo make doc-test
shell: bash # Ensure consistent shell
26 changes: 26 additions & 0 deletions crates/rust-mcp-sdk/tests/common/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use async_trait::async_trait;
use rust_mcp_schema::{
ClientCapabilities, Implementation, InitializeRequestParams, JSONRPC_VERSION,
};
use rust_mcp_sdk::mcp_client::ClientHandler;

pub const NPX_SERVER_EVERYTHING: &str = "@modelcontextprotocol/server-everything";

#[cfg(unix)]
pub const UVX_SERVER_GIT: &str = "mcp-server-git";

pub fn test_client_info() -> InitializeRequestParams {
InitializeRequestParams {
capabilities: ClientCapabilities::default(),
client_info: Implementation {
name: "test-rust-mcp-client".into(),
version: "0.1.0".into(),
},
protocol_version: JSONRPC_VERSION.into(),
}
}

pub struct TestClientHandler;

#[async_trait]
impl ClientHandler for TestClientHandler {}
56 changes: 56 additions & 0 deletions crates/rust-mcp-sdk/tests/test_client_runtime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use common::{test_client_info, TestClientHandler, NPX_SERVER_EVERYTHING};
use rust_mcp_sdk::{mcp_client::client_runtime, McpClient, StdioTransport, TransportOptions};

#[cfg(unix)]
use common::UVX_SERVER_GIT;

#[path = "common/common.rs"]
pub mod common;

#[tokio::test]
async fn tets_client_launch_npx_server() {
// NPM based MCP servers should launch successfully using `npx`
let transport = StdioTransport::create_with_server_launch(
"npx",
vec!["-y".into(), NPX_SERVER_EVERYTHING.into()],
None,
TransportOptions::default(),
)
.unwrap();

let client = client_runtime::create_client(test_client_info(), transport, TestClientHandler {});

client.clone().start().await.unwrap();

let server_capabilities = client.server_capabilities().unwrap();
let server_info = client.server_info().unwrap();

assert!(server_info.server_info.name.len() > 0);
assert!(server_info.server_info.version.len() > 0);
assert!(server_capabilities.tools.is_some());
}

#[cfg(unix)]
#[tokio::test]
async fn tets_client_launch_uvx_server() {
// The Python-based MCP server should launch successfully
// provided that `uvx` is installed and accessible in the system's PATH
let transport = StdioTransport::create_with_server_launch(
"uvx",
vec![UVX_SERVER_GIT.into()],
None,
TransportOptions::default(),
)
.unwrap();

let client = client_runtime::create_client(test_client_info(), transport, TestClientHandler {});

client.clone().start().await.unwrap();

let server_capabilities = client.server_capabilities().unwrap();
let server_info = client.server_info().unwrap();

assert!(server_info.server_info.name.len() > 0);
assert!(server_info.server_info.version.len() > 0);
assert!(server_capabilities.tools.is_some());
}