huskies: merge 855
This commit is contained in:
@@ -1,26 +1,25 @@
|
||||
//! `tools/call` MCP method — dispatches a tool name to the appropriate `*_tools` module.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use serde_json::Value;
|
||||
|
||||
use super::JsonRpcResponse;
|
||||
use super::{
|
||||
agent_tools, diagnostics, git_tools, merge_tools, qa_tools, shell_tools, status_tools,
|
||||
story_tools, wizard_tools,
|
||||
};
|
||||
use crate::http::context::AppContext;
|
||||
use crate::slog_warn;
|
||||
|
||||
// ── Tool dispatch ─────────────────────────────────────────────────
|
||||
|
||||
pub(super) async fn handle_tools_call(
|
||||
id: Option<Value>,
|
||||
params: &Value,
|
||||
/// Execute an MCP tool by name, returning the text result or an error string.
|
||||
///
|
||||
/// This is the shared dispatch entry point used by both the WebSocket
|
||||
/// rendezvous channel and API-based agent runtimes (Gemini, OpenAI).
|
||||
pub async fn dispatch_tool_call(
|
||||
tool_name: &str,
|
||||
args: Value,
|
||||
ctx: &AppContext,
|
||||
) -> JsonRpcResponse {
|
||||
let tool_name = params.get("name").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let args = params.get("arguments").cloned().unwrap_or(json!({}));
|
||||
|
||||
let result = match tool_name {
|
||||
) -> Result<String, String> {
|
||||
match tool_name {
|
||||
// Workflow tools
|
||||
"create_story" => story_tools::tool_create_story(&args, ctx),
|
||||
"validate_stories" => story_tools::tool_validate_stories(ctx),
|
||||
@@ -120,31 +119,43 @@ pub(super) async fn handle_tools_call(
|
||||
"wizard_skip" => wizard_tools::tool_wizard_skip(ctx),
|
||||
"wizard_retry" => wizard_tools::tool_wizard_retry(ctx),
|
||||
_ => Err(format!("Unknown tool: {tool_name}")),
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(content) => JsonRpcResponse::success(
|
||||
id,
|
||||
json!({
|
||||
"content": [{ "type": "text", "text": content }]
|
||||
}),
|
||||
),
|
||||
Err(msg) => {
|
||||
slog_warn!("[mcp] Tool call failed: tool={tool_name} error={msg}");
|
||||
JsonRpcResponse::success(
|
||||
id,
|
||||
json!({
|
||||
"content": [{ "type": "text", "text": msg }],
|
||||
"isError": true
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::gateway::jsonrpc::JsonRpcResponse;
|
||||
use crate::slog_warn;
|
||||
use serde_json::json;
|
||||
|
||||
/// Test helper: invoke a `tools/call` JSON-RPC request and return the response.
|
||||
pub(in crate::http::mcp) async fn handle_tools_call(
|
||||
id: Option<serde_json::Value>,
|
||||
params: &serde_json::Value,
|
||||
ctx: &crate::http::context::AppContext,
|
||||
) -> JsonRpcResponse {
|
||||
let tool_name = params.get("name").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let args = params.get("arguments").cloned().unwrap_or(json!({}));
|
||||
|
||||
match super::dispatch_tool_call(tool_name, args, ctx).await {
|
||||
Ok(content) => JsonRpcResponse::success(
|
||||
id,
|
||||
json!({
|
||||
"content": [{ "type": "text", "text": content }]
|
||||
}),
|
||||
),
|
||||
Err(msg) => {
|
||||
slog_warn!("[mcp] Tool call failed: tool={tool_name} error={msg}");
|
||||
JsonRpcResponse::success(
|
||||
id,
|
||||
json!({
|
||||
"content": [{ "type": "text", "text": msg }],
|
||||
"isError": true
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user