chore(mcp): Add helpers to parse parameters (#2821)

Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
Colin Walters
2025-08-03 04:51:36 -04:00
committed by GitHub
parent da8f64b370
commit 412ceb8128
4 changed files with 41 additions and 33 deletions
+7 -20
View File
@@ -12,7 +12,9 @@ use tokio::{process::Command, sync::mpsc};
use std::os::unix::fs::PermissionsExt;
use mcp_core::{
handler::{PromptError, ResourceError, ToolError},
handler::{
require_str_parameter, require_u64_parameter, PromptError, ResourceError, ToolError,
},
protocol::ServerCapabilities,
};
use mcp_server::router::CapabilitiesBuilder;
@@ -595,11 +597,7 @@ impl ComputerControllerRouter {
}
async fn web_scrape(&self, params: Value) -> Result<Vec<Content>, ToolError> {
let url = params
.get("url")
.and_then(|v| v.as_str())
.ok_or_else(|| ToolError::InvalidParameters("Missing 'url' parameter".into()))?;
let url = require_str_parameter(&params, "url")?;
let save_as = params
.get("save_as")
.and_then(|v| v.as_str())
@@ -916,20 +914,9 @@ impl ComputerControllerRouter {
))])
}
"update_cell" => {
let row = params.get("row").and_then(|v| v.as_u64()).ok_or_else(|| {
ToolError::InvalidParameters("Missing 'row' parameter".into())
})?;
let col = params.get("col").and_then(|v| v.as_u64()).ok_or_else(|| {
ToolError::InvalidParameters("Missing 'col' parameter".into())
})?;
let value = params
.get("value")
.and_then(|v| v.as_str())
.ok_or_else(|| {
ToolError::InvalidParameters("Missing 'value' parameter".into())
})?;
let row = require_u64_parameter(&params, "row")?;
let col = require_u64_parameter(&params, "col")?;
let value = require_str_parameter(&params, "value")?;
let worksheet_name = params
.get("worksheet")
+2 -7
View File
@@ -24,7 +24,7 @@ use url::Url;
use include_dir::{include_dir, Dir};
use mcp_core::{
handler::{PromptError, ResourceError, ToolError},
handler::{require_str_parameter, PromptError, ResourceError, ToolError},
protocol::ServerCapabilities,
};
@@ -919,12 +919,7 @@ impl DeveloperRouter {
self.text_editor_view(&path, view_range).await
}
"write" => {
let file_text = params
.get("file_text")
.and_then(|v| v.as_str())
.ok_or_else(|| {
ToolError::InvalidParameters("Missing 'file_text' parameter".into())
})?;
let file_text = require_str_parameter(&params, "file_text")?;
self.text_editor_write(&path, file_text).await
}
+2 -5
View File
@@ -3,6 +3,7 @@ use axum::http::{HeaderMap, HeaderName};
use chrono::{DateTime, TimeZone, Utc};
use futures::stream::{FuturesUnordered, StreamExt};
use futures::{future, FutureExt};
use mcp_core::handler::require_str_parameter;
use mcp_core::{ToolCall, ToolError};
use rmcp::service::ClientInitializeError;
use rmcp::transport::streamable_http_client::StreamableHttpClientTransportConfig;
@@ -551,11 +552,7 @@ impl ExtensionManager {
// Function that gets executed for read_resource tool
pub async fn read_resource(&self, params: Value) -> Result<Vec<Content>, ToolError> {
let uri = params
.get("uri")
.and_then(|v| v.as_str())
.ok_or_else(|| ToolError::InvalidParameters("Missing 'uri' parameter".to_string()))?;
let uri = require_str_parameter(&params, "uri")?;
let extension_name = params.get("extension_name").and_then(|v| v.as_str());
// If extension name is provided, we can just look it up
+30 -1
View File
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
#[allow(unused_imports)] // this is used in schema below
use serde_json::json;
use serde_json::{json, Value};
use thiserror::Error;
#[non_exhaustive]
@@ -35,3 +35,32 @@ pub enum PromptError {
#[error("Prompt not found: {0}")]
NotFound(String),
}
/// Helper function to require a string, returning a ToolError
pub fn require_str_parameter<'a>(
v: &'a serde_json::Value,
name: &str,
) -> Result<&'a str, ToolError> {
let v = v
.get(name)
.ok_or_else(|| ToolError::InvalidParameters(format!("The parameter {name} is required")))?;
match v.as_str() {
Some(r) => Ok(r),
None => Err(ToolError::InvalidParameters(format!(
"The parameter {name} must be a string"
))),
}
}
/// Helper function to require a u64, returning a ToolError
pub fn require_u64_parameter(v: &serde_json::Value, name: &str) -> Result<u64, ToolError> {
let v = v
.get(name)
.ok_or_else(|| ToolError::InvalidParameters(format!("The parameter {name} is required")))?;
match v.as_u64() {
Some(r) => Ok(r),
None => Err(ToolError::InvalidParameters(format!(
"The parameter {name} must be a number"
))),
}
}