Skip to content
Clone
aaaaf4c
84 lines 2.6 KB Rust
use rmcp::ErrorData;
use rmcp::ServerHandler;
use rmcp::handler::server::router::tool::ToolRouter;
use rmcp::handler::server::tool::ToolCallContext;
use rmcp::model::{
CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, ListToolsResult,
PaginatedRequestParams,
};
use rmcp::service::RequestContext;
use rmcp::{RoleServer, tool_handler};
use crate::auth::Principal;
use crate::services::SharedServices;
use crate::settings;
#[derive(Clone)]
pub struct McpServer {
pub(crate) services: SharedServices,
pub(crate) tool_router: ToolRouter<Self>,
}
impl McpServer {
pub fn new(services: SharedServices) -> Self {
Self {
services,
tool_router: Self::tool_router(),
}
}
pub(crate) fn principal(
&self,
ctx: &RequestContext<RoleServer>,
) -> Result<Principal, ErrorData> {
Principal::from_ctx(ctx)
}
}
#[tool_handler(
name = "gitdata-mcp",
version = "1.0.0",
instructions = "GitData 平台的 MCP 工具集。调用结果遵循调用者访问密钥的权限:只读密钥只能调用只读工具,空间/仓库内的操作受成员角色与仓库 ACL 限制。"
)]
impl ServerHandler for McpServer {
async fn list_tools(
&self,
_request: Option<PaginatedRequestParams>,
context: RequestContext<RoleServer>,
) -> Result<ListToolsResult, ErrorData> {
let principal = self.principal(&context)?;
let disabled = settings::read_disabled(&self.services.state).await;
let mut tools = self.tool_router.list_all();
tools.retain(|tool| !disabled.contains(tool.name.as_ref()));
if !principal.can_write() {
tools.retain(|tool| {
tool.annotations
.as_ref()
.and_then(|annotations| annotations.read_only_hint)
.unwrap_or(false)
});
}
Ok(ListToolsResult {
tools,
..Default::default()
})
}
async fn call_tool(
&self,
request: CallToolRequestParams,
context: RequestContext<RoleServer>,
) -> Result<CallToolResponse, ErrorData> {
self.principal(&context)?;
let name = request.name.to_string();
let disabled = settings::read_disabled(&self.services.state).await;
if disabled.contains(&name) {
return Ok(CallToolResult::error(vec![ContentBlock::text(format!(
"工具 {name} 已被管理员停用"
))])
.into());
}
let call = ToolCallContext::new(self, request, context);
self.tool_router.call(call).await
}
}