Skip to content

Commit

Permalink
WIP - notification and request dispatch and handling
Browse files Browse the repository at this point in the history
  • Loading branch information
cbrit committed Feb 6, 2025
1 parent 2b07482 commit 45dafaa
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 16 deletions.
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
[workspace]
members = [
"crates/mcp-client-sse",
"crates/mcp-core",
"crates/mcp-transport-sse",
"crates/mcp-transport-stdio",
"crates/mcp-types",
]
default-members = [
"crates/mcp-client-sse",
"crates/mcp-core",
"crates/mcp-transport-sse",
"crates/mcp-transport-stdio",
Expand Down
9 changes: 9 additions & 0 deletions crates/mcp-client-sse/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "mcp-client-sse"
version = "0.1.0"
edition = "2021"

[dependencies]
mcp-core = { path = "../mcp-core" }
mcp-transport-sse = { path = "../mcp-transport-sse" }
mcp-types = { path = "../mcp-types" }
14 changes: 14 additions & 0 deletions crates/mcp-client-sse/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use mcp_core::protocol::Protocol;
use mcp_transport_sse::{client::SSEClientTransport, error::SSETransportError};

pub struct SSEClient {
protocol: Protocol<SSETransportError>,
}

impl SSEClient {
pub fn new(transport: SSEClientTransport) -> Self {
Self {
protocol: Protocol::new(Box::new(transport)),
}
}
}
1 change: 1 addition & 0 deletions crates/mcp-client-sse/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod client;
28 changes: 14 additions & 14 deletions crates/mcp-core/src/protocol.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use std::collections::HashMap;

use mcp_types::{
JSONRPCError, JSONRPCNotification, JSONRPCNotificationParams, JSONRPCRequest,
JSONRPCRequestParams, JSONRPCRequestParamsMeta, JSONRPCResponse, Notification, Request,
RequestId,
ClientCapabilities, Implementation, InitializeRequest, InitializeRequestParams, JSONRPCError,
JSONRPCNotification, JSONRPCNotificationParams, JSONRPCRequest, JSONRPCRequestParams,
JSONRPCRequestParamsMeta, JSONRPCResponse, MessageSchema, Notification, Request, RequestId,
Result as MCPResult, LATEST_PROTOCOL_VERSION,
};

use crate::transport::Transport;

pub struct Protocol<E: Into<Box<dyn std::error::Error + Send + Sync>> + Send + Sync + 'static> {
notification_handlers: HashMap<String, Box<dyn Fn(JSONRPCNotification)>>,
request_handlers:
HashMap<String, Box<dyn Fn(JSONRPCRequest) -> Result<JSONRPCResponse, JSONRPCError>>>,
notification_handlers: HashMap<String, Box<dyn Fn(JSONRPCNotification) -> Result<(), E>>>,
request_handlers: HashMap<String, Box<dyn Fn(JSONRPCRequest) -> Result<MCPResult, E>>>,
#[cfg(not(feature = "uuid"))]
request_id: i64,
transport: Box<dyn Transport<Error = E>>,
Expand All @@ -31,20 +31,20 @@ where
}
}

pub fn register_notification_handler(
pub fn set_notification_handler<S: MessageSchema>(
&mut self,
method: String,
handler: Box<dyn Fn(JSONRPCNotification)>,
schema: S,
handler: Box<dyn Fn(JSONRPCNotification) -> Result<(), E>>,
) {
self.notification_handlers.insert(method, handler);
self.notification_handlers.insert(schema.method(), handler);
}

pub fn register_request_handler(
pub fn set_request_handler<S: MessageSchema>(
&mut self,
method: String,
handler: Box<dyn Fn(JSONRPCRequest) -> Result<JSONRPCResponse, JSONRPCError>>,
schema: S,
handler: Box<dyn Fn(JSONRPCRequest) -> Result<MCPResult, E>>,
) {
self.request_handlers.insert(method, handler);
self.request_handlers.insert(schema.method(), handler);
}

pub async fn send_request(&mut self, request: Request) -> Result<(), E> {
Expand Down
2 changes: 1 addition & 1 deletion crates/mcp-types/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn generate(version: &str) {
let contents = syn::parse2::<syn::File>(type_space.to_stream()).unwrap();
let contents = prettyplease::unparse(&contents);

let file_name = format!("src/v{}.rs", version.replace("-", "_"));
let file_name = format!("src/v{}/types.rs", version.replace("-", "_"));
let mut out_file = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).to_path_buf();
out_file.push(file_name);

Expand Down
4 changes: 3 additions & 1 deletion crates/mcp-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ mod v2024_11_05;

/// Re-export of the types module.
#[cfg(feature = "2024_11_05")]
pub use v2024_11_05::{
pub use v2024_11_05::types::{
JsonrpcError as JSONRPCError, JsonrpcErrorError as JSONRPCInnerError,
JsonrpcMessage as JSONRPCMessage, JsonrpcNotification as JSONRPCNotification,
JsonrpcNotificationParams as JSONRPCNotificationParams, JsonrpcRequest as JSONRPCRequest,
JsonrpcRequestParams as JSONRPCRequestParams,
JsonrpcRequestParamsMeta as JSONRPCRequestParamsMeta, JsonrpcResponse as JSONRPCResponse, *,
};

pub use v2024_11_05::messages::*;
80 changes: 80 additions & 0 deletions crates/mcp-types/src/v2024_11_05/messages.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use serde::de::DeserializeOwned;

pub trait MessageSchema: DeserializeOwned {
fn method(&self) -> String;
fn params(&self) -> Option<serde_json::Map<String, serde_json::Value>>;
}

/// Macro for implementing the `MessageSchema` trait for a given type that has
/// a `method` field and a `params` field.
macro_rules! impl_message_schema {
($type:ty) => {
impl MessageSchema for $type {
fn method(&self) -> String {
self.method.clone()
}

fn params(&self) -> Option<serde_json::Map<String, serde_json::Value>> {
serde_json::to_value(&self.params)
.ok()
.and_then(|v| v.as_object().cloned())
}
}
};
}

// Implement the `MessageSchema` trait for all generated message types
use super::types::*;

impl_message_schema!(CancelledNotification);
impl_message_schema!(InitializedNotification);
impl_message_schema!(LoggingMessageNotification);
impl_message_schema!(ProgressNotification);
impl_message_schema!(PromptListChangedNotification);
impl_message_schema!(ResourceListChangedNotification);
impl_message_schema!(ResourceUpdatedNotification);
impl_message_schema!(ToolListChangedNotification);

// Implement the `MessageSchema` trait for all generated request types
impl_message_schema!(CallToolRequest);
impl_message_schema!(CompleteRequest);
impl_message_schema!(CreateMessageRequest);
impl_message_schema!(GetPromptRequest);
impl_message_schema!(InitializeRequest);
impl_message_schema!(ListPromptsRequest);
impl_message_schema!(ListResourcesRequest);
impl_message_schema!(ListResourceTemplatesRequest);
impl_message_schema!(ListRootsRequest);
impl_message_schema!(ListToolsRequest);
impl_message_schema!(PingRequest);
impl_message_schema!(ReadResourceRequest);
impl_message_schema!(SetLevelRequest);
impl_message_schema!(SubscribeRequest);
impl_message_schema!(UnsubscribeRequest);

#[cfg(test)]
mod tests {
use crate::{InitializeRequest, InitializeRequestParams, LATEST_PROTOCOL_VERSION};

use super::*;

#[test]
fn test_message_schema() {
let request = InitializeRequest {
method: "initialize".to_string(),
params: InitializeRequestParams {
capabilities: ClientCapabilities::default(),
client_info: Implementation {
name: "test".to_string(),
version: "1.0.0".to_string(),
},
protocol_version: LATEST_PROTOCOL_VERSION.to_string(),
},
};
assert_eq!(request.method(), "initialize");
assert_eq!(
request.params().unwrap().get("protocolVersion").unwrap(),
LATEST_PROTOCOL_VERSION
);
}
}
2 changes: 2 additions & 0 deletions crates/mcp-types/src/v2024_11_05/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod messages;
pub mod types;
File renamed without changes.

0 comments on commit 45dafaa

Please sign in to comment.