mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 21:14:21 +08:00
MCP新增获取学生列表工具并补充使用文档
This commit is contained in:
+23
@@ -18,6 +18,7 @@
|
|||||||
当前已实现 MCP 工具:
|
当前已实现 MCP 工具:
|
||||||
|
|
||||||
- `add_score`:给指定学生加分或扣分,并写入 `score_events` 记录。
|
- `add_score`:给指定学生加分或扣分,并写入 `score_events` 记录。
|
||||||
|
- `list_students`:获取学生列表(姓名、积分、奖励积分、标签)。
|
||||||
|
|
||||||
## 2. 启动与停止 MCP 服务
|
## 2. 启动与停止 MCP 服务
|
||||||
|
|
||||||
@@ -99,6 +100,28 @@ curl -X POST http://127.0.0.1:3901/mcp \
|
|||||||
- `delta`(integer,必填):分值变化,正数加分,负数扣分。
|
- `delta`(integer,必填):分值变化,正数加分,负数扣分。
|
||||||
- `reason_content`(string,可选):原因,默认 `MCP 加分`。
|
- `reason_content`(string,可选):原因,默认 `MCP 加分`。
|
||||||
|
|
||||||
|
### 3.4 tools/call(调用 list_students)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://127.0.0.1:3901/mcp \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 4,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "list_students",
|
||||||
|
"arguments": {
|
||||||
|
"limit": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
`list_students` 参数:
|
||||||
|
|
||||||
|
- `limit`(integer,可选):最多返回多少条,默认返回全部学生。
|
||||||
|
|
||||||
## 4. 返回结果说明
|
## 4. 返回结果说明
|
||||||
|
|
||||||
调用 `add_score` 成功时:
|
调用 `add_score` 成功时:
|
||||||
|
|||||||
+140
-35
@@ -6,7 +6,10 @@ use axum::{
|
|||||||
Json, Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set, TransactionTrait};
|
use sea_orm::{
|
||||||
|
ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, Set,
|
||||||
|
TransactionTrait,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@@ -92,6 +95,12 @@ struct AddScoreArgs {
|
|||||||
reason_content: Option<String>,
|
reason_content: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Default)]
|
||||||
|
struct ListStudentsArgs {
|
||||||
|
#[serde(default)]
|
||||||
|
limit: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
struct AddScoreResult {
|
struct AddScoreResult {
|
||||||
event_id: i32,
|
event_id: i32,
|
||||||
@@ -104,6 +113,21 @@ struct AddScoreResult {
|
|||||||
event_time: String,
|
event_time: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct StudentListItem {
|
||||||
|
id: i32,
|
||||||
|
name: String,
|
||||||
|
score: i32,
|
||||||
|
reward_points: i32,
|
||||||
|
tags: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct ListStudentsResult {
|
||||||
|
total: usize,
|
||||||
|
students: Vec<StudentListItem>,
|
||||||
|
}
|
||||||
|
|
||||||
static MCP_SERVER_STATE: once_cell::sync::Lazy<Arc<Mutex<McpServerState>>> =
|
static MCP_SERVER_STATE: once_cell::sync::Lazy<Arc<Mutex<McpServerState>>> =
|
||||||
once_cell::sync::Lazy::new(|| Arc::new(Mutex::new(McpServerState::default())));
|
once_cell::sync::Lazy::new(|| Arc::new(Mutex::new(McpServerState::default())));
|
||||||
|
|
||||||
@@ -165,6 +189,16 @@ fn tools_list_result() -> Value {
|
|||||||
},
|
},
|
||||||
"required": ["student_name", "delta"]
|
"required": ["student_name", "delta"]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "list_students",
|
||||||
|
"description": "获取学生列表,包含姓名、积分、奖励积分和标签。",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"limit": {"type": "integer", "description": "最多返回多少条,默认全部"}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@@ -196,41 +230,75 @@ async fn handle_mcp(
|
|||||||
|
|
||||||
match params {
|
match params {
|
||||||
None => jsonrpc_error(id, -32602, "Invalid tools/call params"),
|
None => jsonrpc_error(id, -32602, "Invalid tools/call params"),
|
||||||
Some(params) if params.name != "add_score" => {
|
Some(params) => match params.name.as_str() {
|
||||||
jsonrpc_error(id, -32601, &format!("Unknown tool: {}", params.name))
|
"add_score" => match serde_json::from_value::<AddScoreArgs>(params.arguments) {
|
||||||
}
|
Ok(args) => match mcp_add_score(&app_state, args).await {
|
||||||
Some(params) => match serde_json::from_value::<AddScoreArgs>(params.arguments) {
|
Ok(payload) => jsonrpc_ok(
|
||||||
Ok(args) => match mcp_add_score(&app_state, args).await {
|
id,
|
||||||
Ok(payload) => jsonrpc_ok(
|
json!({
|
||||||
id,
|
"content": [
|
||||||
json!({
|
{
|
||||||
"content": [
|
"type": "text",
|
||||||
{
|
"text": format!(
|
||||||
"type": "text",
|
"已记录:{} {:+} 分({} -> {})",
|
||||||
"text": format!(
|
payload.student_name, payload.delta, payload.val_prev, payload.val_curr
|
||||||
"已记录:{} {:+} 分({} -> {})",
|
)
|
||||||
payload.student_name, payload.delta, payload.val_prev, payload.val_curr
|
}
|
||||||
)
|
],
|
||||||
}
|
"isError": false,
|
||||||
],
|
"structuredContent": payload
|
||||||
"isError": false,
|
}),
|
||||||
"structuredContent": payload
|
),
|
||||||
}),
|
Err(e) => jsonrpc_ok(
|
||||||
),
|
id,
|
||||||
Err(e) => jsonrpc_ok(
|
json!({
|
||||||
id,
|
"content": [
|
||||||
json!({
|
{
|
||||||
"content": [
|
"type": "text",
|
||||||
{
|
"text": format!("加分失败: {}", e)
|
||||||
"type": "text",
|
}
|
||||||
"text": format!("加分失败: {}", e)
|
],
|
||||||
}
|
"isError": true
|
||||||
],
|
}),
|
||||||
"isError": true
|
),
|
||||||
}),
|
},
|
||||||
),
|
Err(e) => jsonrpc_error(id, -32602, &format!("Invalid arguments: {}", e)),
|
||||||
},
|
},
|
||||||
Err(e) => jsonrpc_error(id, -32602, &format!("Invalid arguments: {}", e)),
|
"list_students" => {
|
||||||
|
match serde_json::from_value::<ListStudentsArgs>(params.arguments) {
|
||||||
|
Ok(args) => match mcp_list_students(&app_state, args).await {
|
||||||
|
Ok(payload) => jsonrpc_ok(
|
||||||
|
id,
|
||||||
|
json!({
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": format!("已获取 {} 名学生", payload.total)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isError": false,
|
||||||
|
"structuredContent": payload
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Err(e) => jsonrpc_ok(
|
||||||
|
id,
|
||||||
|
json!({
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": format!("获取学生列表失败: {}", e)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isError": true
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
jsonrpc_error(id, -32602, &format!("Invalid arguments: {}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => jsonrpc_error(id, -32601, &format!("Unknown tool: {}", params.name)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,6 +388,43 @@ async fn mcp_add_score(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn mcp_list_students(
|
||||||
|
app_state: &Arc<RwLock<AppState>>,
|
||||||
|
args: ListStudentsArgs,
|
||||||
|
) -> Result<ListStudentsResult, String> {
|
||||||
|
let db_conn = {
|
||||||
|
let state_guard = app_state.read();
|
||||||
|
let db_guard = state_guard.db.read();
|
||||||
|
db_guard.clone()
|
||||||
|
}
|
||||||
|
.ok_or_else(|| "Database not connected".to_string())?;
|
||||||
|
|
||||||
|
let limit = args.limit.unwrap_or(u64::MAX);
|
||||||
|
|
||||||
|
let rows = students::Entity::find()
|
||||||
|
.order_by_asc(students::Column::Name)
|
||||||
|
.limit(limit)
|
||||||
|
.all(&db_conn)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let students = rows
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| StudentListItem {
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
score: row.score,
|
||||||
|
reward_points: row.reward_points,
|
||||||
|
tags: serde_json::from_str::<Vec<String>>(&row.tags).unwrap_or_default(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(ListStudentsResult {
|
||||||
|
total: students.len(),
|
||||||
|
students,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn mcp_server_start(
|
pub async fn mcp_server_start(
|
||||||
config: Option<McpServerConfig>,
|
config: Option<McpServerConfig>,
|
||||||
|
|||||||
Reference in New Issue
Block a user