Spaces:
Running
Running
File size: 3,752 Bytes
61bcaab 0f5c565 61bcaab |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
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";
#[tokio::main]
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(())
}
#[derive(Clone)]
pub struct HfFile {
http_client: reqwest::Client,
}
#[tool(tool_box)]
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,
}
}
#[tool(description = "List files in HF Hub")]
async fn list_repo_file(
&self,
#[tool(param)]
#[schemars(description = "repo")]
repository: String,
#[tool(param)]
#[schemars(description = "repo type (models, datasets, spaces.)")]
repo_type: String,
) -> Result<CallToolResult, McpError> {
let response = self
.http_client
.get(format!(
"https://huggingface.co/api/{repo_type}/{repository}"
))
.send()
.await
.unwrap();
if !response.status().is_success() {
return Err(McpError::internal_error("Failed to list files", None));
}
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)?]))
}
#[tool(description = "List files in HF Hub")]
async fn get_file_content(
&self,
#[tool(param)]
#[schemars(description = "repo")]
repository: String,
#[tool(param)]
#[schemars(description = "repo type (models, datasets, spaces.)")]
repo_type: String,
#[tool(param)]
#[schemars(description = "file path")]
file_path: String,
) -> Result<CallToolResult, McpError> {
let response = self
.http_client
.get(format!(
"https://huggingface.co/{repo_type}/{repository}/resolve/main/{file_path}"
))
.send()
.await
.unwrap();
if !response.status().is_success() {
return Err(McpError::internal_error("Failed to get file content", None));
}
Ok(CallToolResult::success(vec![Content::text(
response.text().await.unwrap(),
)]))
}
}
#[tool(tool_box)]
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()),
}
}
}
|