use crate::common::string_utils::StringUtils;
use crate::mcp::model::mcp::{McpQueryParam, McpServerParam, McpServerValue};
use crate::mcp::model::tools::{McpSimpleTool, ToolRouteRule};
use crate::namespace;
use actix_web::{HttpMessage, HttpRequest};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpServerQueryRequest {
pub page_no: Option<usize>,
pub page_size: Option<usize>,
pub namespace_id: Option<String>,
pub name_filter: Option<String>,
}
impl McpServerQueryRequest {
pub fn to_mcp_query_param(&self) -> McpQueryParam {
let limit = self.page_size.unwrap_or(20);
let offset = (self.page_no.unwrap_or(1) - 1) * limit;
let namespace_id = if StringUtils::is_option_empty(&self.namespace_id) {
Arc::new(namespace::default_namespace("".to_string()))
} else {
Arc::new(self.namespace_id.clone().unwrap())
};
McpQueryParam {
offset,
limit,
namespace_id: Some(namespace_id),
name_filter: self.name_filter.as_ref().map(|s| Arc::new(s.clone())),
}
}
pub fn validate(&self) -> anyhow::Result<()> {
if let Some(page_no) = self.page_no {
if page_no == 0 {
return Err(anyhow::anyhow!("页码不能为0"));
}
}
if let Some(page_size) = self.page_size {
if page_size == 0 {
return Err(anyhow::anyhow!("页面大小不能为0"));
}
if page_size > 1000 {
return Err(anyhow::anyhow!("页面大小不能超过1000"));
}
}
Ok(())
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpServerHistoryQueryRequest {
pub id: u64,
pub page_no: Option<usize>,
pub page_size: Option<usize>,
pub start_time: Option<i64>,
pub end_time: Option<i64>,
}
impl McpServerHistoryQueryRequest {
pub fn validate(&self) -> anyhow::Result<()> {
if self.id == 0 {
return Err(anyhow::anyhow!("McpServer ID不能为0"));
}
if let Some(page_no) = self.page_no {
if page_no == 0 {
return Err(anyhow::anyhow!("页码不能为0"));
}
}
if let Some(page_size) = self.page_size {
if page_size == 0 {
return Err(anyhow::anyhow!("页面大小不能为0"));
}
if page_size > 1000 {
return Err(anyhow::anyhow!("页面大小不能超过1000"));
}
}
if let (Some(start_time), Some(end_time)) = (self.start_time, self.end_time) {
if start_time >= end_time {
return Err(anyhow::anyhow!("开始时间必须小于结束时间"));
}
}
Ok(())
}
pub fn get_pagination(&self) -> (usize, usize) {
let limit = self.page_size.unwrap_or(20);
let offset = (self.page_no.unwrap_or(1) - 1) * limit;
(offset, limit)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpServerHistoryPublishParams {
pub id: u64,
pub history_value_id: u64,
}
impl McpServerHistoryPublishParams {
pub fn validate(&self) -> anyhow::Result<()> {
if self.id == 0 {
return Err(anyhow::anyhow!("McpServer ID不能为0"));
}
if self.history_value_id == 0 {
return Err(anyhow::anyhow!("历史版本ID不能为0"));
}
Ok(())
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpSimpleToolParams {
pub id: Option<u64>,
pub tool_name: Arc<String>,
pub namespace: Arc<String>,
pub group: Arc<String>,
pub tool_version: Option<u64>,
pub route_rule: Option<ToolRouteRule>,
}
impl McpSimpleToolParams {
pub fn validate(&self) -> anyhow::Result<()> {
if self.tool_name.is_empty() {
return Err(anyhow::anyhow!("工具名称不能为空"));
}
if self.group.is_empty() {
return Err(anyhow::anyhow!("工具组不能为空"));
}
Ok(())
}
pub fn to_mcp_simple_tool(&self) -> McpSimpleTool {
let namespace = if self.namespace.is_empty() {
Arc::new(namespace::default_namespace("".to_string()))
} else {
self.namespace.clone()
};
McpSimpleTool {
tool_name: self.tool_name.clone(),
tool_key: crate::mcp::model::tools::ToolKey::new(
namespace,
self.group.clone(),
self.tool_name.clone(),
),
tool_version: self.tool_version.unwrap_or(1),
route_rule: self.route_rule.clone().unwrap_or_default(),
}
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpServerParams {
pub id: Option<u64>,
pub unique_key: Option<String>,
pub namespace: Option<String>,
pub name: Option<String>,
pub description: Option<String>,
pub auth_keys: Option<Vec<String>>,
pub tools: Option<Vec<McpSimpleToolParams>>,
}
impl McpServerParams {
pub fn validate(&self) -> anyhow::Result<()> {
if let Some(ref name) = self.name {
if name.is_empty() {
return Err(anyhow::anyhow!("McpServer名称不能为空"));
}
} else {
return Err(anyhow::anyhow!("McpServer名称不能为空"));
}
if let Some(ref auth_keys) = self.auth_keys {
if auth_keys.is_empty() {
return Err(anyhow::anyhow!("认证密钥不能为空"));
}
for key in auth_keys {
if key.is_empty() {
return Err(anyhow::anyhow!("认证密钥不能包含空值"));
}
}
} else {
return Err(anyhow::anyhow!("认证密钥不能为空"));
}
if let Some(ref tools) = self.tools {
for tool in tools {
tool.validate()?;
}
}
Ok(())
}
pub fn validate_for_update(&self) -> anyhow::Result<()> {
if self.id.is_none() || self.id == Some(0) {
return Err(anyhow::anyhow!("McpServer ID不能为空"));
}
if let Some(ref name) = self.name {
if name.is_empty() {
return Err(anyhow::anyhow!("McpServer名称不能为空"));
}
}
if let Some(ref auth_keys) = self.auth_keys {
if auth_keys.is_empty() {
return Err(anyhow::anyhow!("认证密钥不能为空"));
}
for key in auth_keys {
if key.is_empty() {
return Err(anyhow::anyhow!("认证密钥不能包含空值"));
}
}
}
if let Some(ref tools) = self.tools {
for tool in tools {
tool.validate()?;
}
}
Ok(())
}
pub fn validate_for_delete(&self) -> anyhow::Result<()> {
if self.id.is_none() || self.id == Some(0) {
return Err(anyhow::anyhow!("McpServer ID不能为空"));
}
Ok(())
}
pub fn to_mcp_server_param(&self, op_user: Option<Arc<String>>) -> McpServerParam {
let namespace = if let Some(ref ns) = self.namespace {
if ns.is_empty() {
Some(Arc::new(namespace::default_namespace("".to_string())))
} else {
Some(Arc::new(ns.clone()))
}
} else {
Some(Arc::new(namespace::default_namespace("".to_string())))
};
let unique_key = if let Some(ref unique_key) = self.unique_key {
if unique_key.is_empty() {
None
} else {
Some(Arc::new(unique_key.clone()))
}
} else {
None
};
McpServerParam {
id: self.id.unwrap_or(0),
unique_key,
value_id: 0, namespace,
name: self.name.as_ref().map(|s| Arc::new(s.clone())),
description: self.description.as_ref().map(|s| Arc::new(s.clone())),
auth_keys: self
.auth_keys
.as_ref()
.map(|keys| keys.iter().map(|k| Arc::new(k.clone())).collect()),
tools: self
.tools
.as_ref()
.map(|tools| tools.iter().map(|t| t.to_mcp_simple_tool()).collect())
.unwrap_or_default(),
op_user: op_user.unwrap_or_else(|| Arc::new("".to_string())),
update_time: chrono::Utc::now().timestamp_millis(),
publish_value_id: None,
token: None, }
}
pub fn with_user_from_request(&mut self, req: &HttpRequest) -> anyhow::Result<Arc<String>> {
if let Some(session) = req.extensions().get::<crate::common::model::UserSession>() {
Ok(session.username.clone())
} else {
Ok(Arc::new("system".to_string()))
}
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpServerValueDto {
pub id: u64,
pub description: Arc<String>,
pub tools: Vec<crate::mcp::model::tools::McpTool>,
pub op_user: Arc<String>,
pub update_time: i64,
}
impl McpServerValueDto {
pub fn from_value(value: &McpServerValue) -> Self {
Self {
id: value.id,
description: value.description.clone(),
tools: value.tools.clone(),
op_user: value.op_user.clone(),
update_time: value.update_time,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpServerImportDto {
pub unique_key: String,
pub name: String,
pub description: String,
pub auth_keys: Vec<String>,
pub tools: Vec<McpToolImportDto>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpToolImportDto {
pub tool_name: String,
pub tool_group: String,
pub route_rule: ToolRouteRule,
}
impl From<&crate::mcp::model::mcp::McpServerDto> for McpServerImportDto {
fn from(server: &crate::mcp::model::mcp::McpServerDto) -> Self {
let tools = if let Some(ref current_value) = server.current_value {
current_value
.tools
.iter()
.map(|tool| McpToolImportDto {
tool_name: tool.tool_key.tool_name.as_str().to_string(),
tool_group: tool.tool_key.group.as_str().to_string(),
route_rule: tool.route_rule.clone(),
})
.collect()
} else if let Some(ref release_value) = server.release_value {
release_value
.tools
.iter()
.map(|tool| McpToolImportDto {
tool_name: tool.tool_key.tool_name.as_str().to_string(),
tool_group: tool.tool_key.group.as_str().to_string(),
route_rule: tool.route_rule.clone(),
})
.collect()
} else {
Vec::new()
};
Self {
unique_key: server.unique_key.as_str().to_string(),
name: server.name.as_str().to_string(),
description: server.description.as_str().to_string(),
auth_keys: server
.auth_keys
.iter()
.map(|key| key.as_str().to_string())
.collect(),
tools,
}
}
}