Spaces:
Sleeping
Sleeping
| use std::time::Duration; | |
| use rmcp::{serde_json, transport::StreamableHttpServer}; | |
| use rmcp::{Error as McpError, ServerHandler, model::*, schemars, tool}; | |
| use tracing_subscriber::{ | |
| layer::SubscriberExt, | |
| util::SubscriberInitExt, | |
| {self}, | |
| }; | |
| const BIND_ADDRESS: &str = "0.0.0.0:9090"; | |
| async fn main() -> anyhow::Result<()> { | |
| tracing_subscriber::registry() | |
| .with( | |
| tracing_subscriber::EnvFilter::try_from_default_env() | |
| .unwrap_or_else(|_| "hf_file_mcp=debug".to_string().into()), | |
| ) | |
| .with(tracing_subscriber::fmt::layer()) | |
| .init(); | |
| let ct = StreamableHttpServer::serve(BIND_ADDRESS.parse()?) | |
| .await? | |
| .with_service(HfFile::new); | |
| tokio::signal::ctrl_c().await?; | |
| ct.cancel(); | |
| Ok(()) | |
| } | |
| pub struct HfFile { | |
| http_client: reqwest::Client, | |
| } | |
| impl HfFile { | |
| pub fn new() -> Self { | |
| let http_client = reqwest::Client::builder() | |
| .timeout(Duration::from_secs(10)) | |
| .build() | |
| .expect("Failed to create HTTP client"); | |
| Self { | |
| http_client: http_client, | |
| } | |
| } | |
| async fn list_repo_file( | |
| &self, | |
| repository: String, | |
| repo_type: String, | |
| ) -> Result<CallToolResult, McpError> { | |
| println!("Listing files in HF Hub {repo_type}/{repository}"); | |
| let response = self | |
| .http_client | |
| .get(format!( | |
| "https://huggingface.co/api/{repo_type}/{repository}" | |
| )) | |
| .send() | |
| .await | |
| .unwrap(); | |
| if !response.status().is_success() { | |
| return Ok(CallToolResult::success(vec![Content::text( | |
| response.text().await.unwrap(), | |
| )])); | |
| } | |
| println!("Successfully listed files in HF Hub {repo_type}/{repository}"); | |
| let body = response.json::<serde_json::Value>().await.unwrap(); | |
| let siblings = body.get("siblings").unwrap().as_array().unwrap(); | |
| let mut contents = Vec::new(); | |
| for sibling in siblings { | |
| contents.push(sibling.get("rfilename").unwrap().as_str().unwrap()); | |
| } | |
| Ok(CallToolResult::success(vec![Content::json(contents)?])) | |
| } | |
| async fn get_file_content( | |
| &self, | |
| repository: String, | |
| repo_type: String, | |
| file_path: String, | |
| ) -> Result<CallToolResult, McpError> { | |
| println!("Getting file content in HF Hub {file_path} for {repo_type}/{repository}"); | |
| let response = self | |
| .http_client | |
| .get(format!( | |
| "https://huggingface.co/{repo_type}/{repository}/resolve/main/{file_path}" | |
| )) | |
| .send() | |
| .await | |
| .unwrap(); | |
| Ok(CallToolResult::success(vec![Content::text( | |
| response.text().await.unwrap(), | |
| )])) | |
| } | |
| } | |
| impl ServerHandler for HfFile { | |
| fn get_info(&self) -> ServerInfo { | |
| ServerInfo { | |
| protocol_version: ProtocolVersion::V_2025_03_26, | |
| capabilities: ServerCapabilities::builder() | |
| .enable_tools() | |
| .build(), | |
| server_info: Implementation::from_build_env(), | |
| instructions: Some("This server provides a Hugging Face file tool that can list and get files from Hugging Face Hub.".to_string()), | |
| } | |
| } | |
| } | |