Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion sgl-router/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ minijinja = { version = "2.0", features = ["unstable_machinery", "json", "builti
minijinja-contrib = { version = "2.0", features = ["pycompat"] }
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
hf-hub = { version = "0.4.3", features = ["tokio"] }
rmcp = { version = "0.6.3", features = ["client", "server",
rmcp = { version = "0.8.3", features = ["client", "server",
"transport-child-process",
"transport-sse-client-reqwest",
"transport-streamable-http-client-reqwest",
Expand Down
34 changes: 2 additions & 32 deletions sgl-router/src/mcp/config.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,9 @@
use std::collections::HashMap;

// Re-export rmcp types for convenient access
pub use rmcp::model::{Prompt, RawResource, Tool};
use serde::{Deserialize, Serialize};

// ============================================================================
// MCP Data Structures
// ============================================================================

/// Information about an available tool
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolInfo {
pub name: String,
pub description: String,
pub server: String,
pub parameters: Option<serde_json::Value>,
}

/// Information about an available prompt
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PromptInfo {
pub name: String,
pub description: Option<String>,
pub server: String,
pub arguments: Option<Vec<serde_json::Value>>,
}

/// Information about an available resource
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceInfo {
pub uri: String,
pub name: String,
pub description: Option<String>,
pub mime_type: Option<String>,
pub server: String,
}

// ============================================================================
// Configuration Structures
// ============================================================================
Expand Down
73 changes: 45 additions & 28 deletions sgl-router/src/mcp/inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,29 @@ use std::time::{Duration, Instant};

use dashmap::DashMap;

use crate::mcp::config::{PromptInfo, ResourceInfo, ToolInfo};
use crate::mcp::config::{Prompt, RawResource, Tool};

/// Cached tool with metadata
#[derive(Clone)]
pub struct CachedTool {
pub server_name: String,
pub tool: ToolInfo,
pub tool: Tool,
pub cached_at: Instant,
}

/// Cached prompt with metadata
#[derive(Clone)]
pub struct CachedPrompt {
pub server_name: String,
pub prompt: PromptInfo,
pub prompt: Prompt,
pub cached_at: Instant,
}

/// Cached resource with metadata
#[derive(Clone)]
pub struct CachedResource {
pub server_name: String,
pub resource: ResourceInfo,
pub resource: RawResource,
pub cached_at: Instant,
}

Expand Down Expand Up @@ -74,7 +74,7 @@ impl ToolInventory {
/// Get a tool if it exists and is fresh (within TTL)
///
/// Returns None if the tool doesn't exist or has expired.
pub fn get_tool(&self, tool_name: &str) -> Option<(String, ToolInfo)> {
pub fn get_tool(&self, tool_name: &str) -> Option<(String, Tool)> {
self.tools.get(tool_name).and_then(|entry| {
let cached = entry.value();

Expand All @@ -94,7 +94,7 @@ impl ToolInventory {
}

/// Insert or update a tool
pub fn insert_tool(&self, tool_name: String, server_name: String, tool: ToolInfo) {
pub fn insert_tool(&self, tool_name: String, server_name: String, tool: Tool) {
self.tools.insert(
tool_name,
CachedTool {
Expand All @@ -106,7 +106,7 @@ impl ToolInventory {
}

/// Get all tools (fresh only)
pub fn list_tools(&self) -> Vec<(String, String, ToolInfo)> {
pub fn list_tools(&self) -> Vec<(String, String, Tool)> {
let now = Instant::now();
self.tools
.iter()
Expand All @@ -130,7 +130,7 @@ impl ToolInventory {
// ============================================================================

/// Get a prompt if it exists and is fresh (within TTL)
pub fn get_prompt(&self, prompt_name: &str) -> Option<(String, PromptInfo)> {
pub fn get_prompt(&self, prompt_name: &str) -> Option<(String, Prompt)> {
self.prompts.get(prompt_name).and_then(|entry| {
let cached = entry.value();

Expand All @@ -149,7 +149,7 @@ impl ToolInventory {
}

/// Insert or update a prompt
pub fn insert_prompt(&self, prompt_name: String, server_name: String, prompt: PromptInfo) {
pub fn insert_prompt(&self, prompt_name: String, server_name: String, prompt: Prompt) {
self.prompts.insert(
prompt_name,
CachedPrompt {
Expand All @@ -161,7 +161,7 @@ impl ToolInventory {
}

/// Get all prompts (fresh only)
pub fn list_prompts(&self) -> Vec<(String, String, PromptInfo)> {
pub fn list_prompts(&self) -> Vec<(String, String, Prompt)> {
let now = Instant::now();
self.prompts
.iter()
Expand All @@ -185,7 +185,7 @@ impl ToolInventory {
// ============================================================================

/// Get a resource if it exists and is fresh (within TTL)
pub fn get_resource(&self, resource_uri: &str) -> Option<(String, ResourceInfo)> {
pub fn get_resource(&self, resource_uri: &str) -> Option<(String, RawResource)> {
self.resources.get(resource_uri).and_then(|entry| {
let cached = entry.value();

Expand All @@ -208,7 +208,7 @@ impl ToolInventory {
&self,
resource_uri: String,
server_name: String,
resource: ResourceInfo,
resource: RawResource,
) {
self.resources.insert(
resource_uri,
Expand All @@ -221,7 +221,7 @@ impl ToolInventory {
}

/// Get all resources (fresh only)
pub fn list_resources(&self) -> Vec<(String, String, ResourceInfo)> {
pub fn list_resources(&self) -> Vec<(String, String, RawResource)> {
let now = Instant::now();
self.resources
.iter()
Expand Down Expand Up @@ -316,38 +316,55 @@ impl ToolInventory {
#[cfg(test)]
mod tests {
use super::*;
use crate::mcp::config::{Prompt, RawResource, Tool};

// Helper to create a test tool
fn create_test_tool(name: &str) -> ToolInfo {
ToolInfo {
name: name.to_string(),
description: format!("Test tool: {}", name),
server: "test_server".to_string(),
parameters: Some(serde_json::json!({
"type": "object",
"properties": {}
})),
fn create_test_tool(name: &str) -> Tool {
use std::{borrow::Cow, sync::Arc};

let schema_obj = serde_json::json!({
"type": "object",
"properties": {}
});

let schema_map = if let serde_json::Value::Object(m) = schema_obj {
m
} else {
serde_json::Map::new()
};

Tool {
name: Cow::Owned(name.to_string()),
title: None,
description: Some(Cow::Owned(format!("Test tool: {}", name))),
input_schema: Arc::new(schema_map),
output_schema: None,
annotations: None,
icons: None,
}
}

// Helper to create a test prompt
fn create_test_prompt(name: &str) -> PromptInfo {
PromptInfo {
fn create_test_prompt(name: &str) -> Prompt {
Prompt {
name: name.to_string(),
title: None,
description: Some(format!("Test prompt: {}", name)),
server: "test_server".to_string(),
arguments: None,
icons: None,
}
}

// Helper to create a test resource
fn create_test_resource(uri: &str) -> ResourceInfo {
ResourceInfo {
fn create_test_resource(uri: &str) -> RawResource {
RawResource {
uri: uri.to_string(),
name: uri.to_string(),
title: None,
description: Some(format!("Test resource: {}", uri)),
mime_type: Some("text/plain".to_string()),
server: "test_server".to_string(),
size: None,
icons: None,
}
}

Expand Down
Loading
Loading