feat!: add MRTR behavior support (SEP-2322) (#929)
* feat!: add MRTR behavior support * feat: harden SEP-2322 MRTR support * ci: diff public API only on features common to base and head cargo public-api builds both revisions with the same feature set, so a feature introduced (or removed) by a PR broke the build of the other revision. Restrict the all-features diff to features present in both the base and head revisions.
This commit is contained in:
parent
a7194590ff
commit
dd30a70f84
7 changed files with 2121 additions and 127 deletions
|
|
@ -27,6 +27,9 @@ impl<H: ServerHandler> Service<RoleServer> for H {
|
|||
) -> Result<<RoleServer as ServiceRole>::Resp, McpError> {
|
||||
// `context` is moved into the dispatch below, so read the negotiated version first.
|
||||
let protocol_version = context.protocol_version();
|
||||
let mrtr_supported = protocol_version
|
||||
.as_ref()
|
||||
.is_some_and(|v| v.as_str() >= ProtocolVersion::V_2026_07_28.as_str());
|
||||
let result = match request {
|
||||
ClientRequest::InitializeRequest(request) => self
|
||||
.initialize(request.params, context)
|
||||
|
|
@ -46,7 +49,7 @@ impl<H: ServerHandler> Service<RoleServer> for H {
|
|||
ClientRequest::GetPromptRequest(request) => self
|
||||
.get_prompt(request.params, context)
|
||||
.await
|
||||
.map(ServerResult::GetPromptResult),
|
||||
.map(ServerResult::from),
|
||||
ClientRequest::ListPromptsRequest(request) => self
|
||||
.list_prompts(request.params, context)
|
||||
.await
|
||||
|
|
@ -62,7 +65,7 @@ impl<H: ServerHandler> Service<RoleServer> for H {
|
|||
ClientRequest::ReadResourceRequest(request) => self
|
||||
.read_resource(request.params, context)
|
||||
.await
|
||||
.map(ServerResult::ReadResourceResult),
|
||||
.map(ServerResult::from),
|
||||
ClientRequest::SubscribeRequest(request) => self
|
||||
.subscribe(request.params, context)
|
||||
.await
|
||||
|
|
@ -105,7 +108,7 @@ impl<H: ServerHandler> Service<RoleServer> for H {
|
|||
} else {
|
||||
self.call_tool(request.params, context)
|
||||
.await
|
||||
.map(ServerResult::CallToolResult)
|
||||
.map(ServerResult::from)
|
||||
}
|
||||
}
|
||||
ClientRequest::ListToolsRequest(request) => self
|
||||
|
|
@ -133,6 +136,17 @@ impl<H: ServerHandler> Service<RoleServer> for H {
|
|||
.await
|
||||
.map(ServerResult::CancelTaskResult),
|
||||
};
|
||||
let result = result.and_then(|result| {
|
||||
if matches!(result, ServerResult::InputRequiredResult(_)) && !mrtr_supported {
|
||||
Err(McpError::invalid_request(
|
||||
"InputRequiredResult requires negotiated protocol version 2026-07-28 or newer",
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
Ok(result)
|
||||
}
|
||||
});
|
||||
|
||||
// SEP-2164: peers negotiating 2026-07-28+ get the standard INVALID_PARAMS code for
|
||||
// resource-not-found; older peers keep RESOURCE_NOT_FOUND. ISO `YYYY-MM-DD` versions
|
||||
// compare lexically the same as chronologically.
|
||||
|
|
@ -229,7 +243,7 @@ macro_rules! server_handler_methods {
|
|||
&self,
|
||||
request: GetPromptRequestParams,
|
||||
context: RequestContext<RoleServer>,
|
||||
) -> impl Future<Output = Result<GetPromptResult, McpError>> + MaybeSendFuture + '_ {
|
||||
) -> impl Future<Output = Result<GetPromptResponse, McpError>> + MaybeSendFuture + '_ {
|
||||
std::future::ready(Err(McpError::method_not_found::<GetPromptRequestMethod>()))
|
||||
}
|
||||
fn list_prompts(
|
||||
|
|
@ -259,7 +273,7 @@ macro_rules! server_handler_methods {
|
|||
&self,
|
||||
request: ReadResourceRequestParams,
|
||||
context: RequestContext<RoleServer>,
|
||||
) -> impl Future<Output = Result<ReadResourceResult, McpError>> + MaybeSendFuture + '_ {
|
||||
) -> impl Future<Output = Result<ReadResourceResponse, McpError>> + MaybeSendFuture + '_ {
|
||||
std::future::ready(Err(
|
||||
McpError::method_not_found::<ReadResourceRequestMethod>(),
|
||||
))
|
||||
|
|
@ -312,7 +326,7 @@ macro_rules! server_handler_methods {
|
|||
&self,
|
||||
request: CallToolRequestParams,
|
||||
context: RequestContext<RoleServer>,
|
||||
) -> impl Future<Output = Result<CallToolResult, McpError>> + MaybeSendFuture + '_ {
|
||||
) -> impl Future<Output = Result<CallToolResponse, McpError>> + MaybeSendFuture + '_ {
|
||||
std::future::ready(Err(McpError::method_not_found::<CallToolRequestMethod>()))
|
||||
}
|
||||
fn list_tools(
|
||||
|
|
@ -485,7 +499,7 @@ macro_rules! impl_server_handler_for_wrapper {
|
|||
&self,
|
||||
request: GetPromptRequestParams,
|
||||
context: RequestContext<RoleServer>,
|
||||
) -> impl Future<Output = Result<GetPromptResult, McpError>> + MaybeSendFuture + '_ {
|
||||
) -> impl Future<Output = Result<GetPromptResponse, McpError>> + MaybeSendFuture + '_ {
|
||||
(**self).get_prompt(request, context)
|
||||
}
|
||||
|
||||
|
|
@ -518,7 +532,7 @@ macro_rules! impl_server_handler_for_wrapper {
|
|||
&self,
|
||||
request: ReadResourceRequestParams,
|
||||
context: RequestContext<RoleServer>,
|
||||
) -> impl Future<Output = Result<ReadResourceResult, McpError>> + MaybeSendFuture + '_ {
|
||||
) -> impl Future<Output = Result<ReadResourceResponse, McpError>> + MaybeSendFuture + '_ {
|
||||
(**self).read_resource(request, context)
|
||||
}
|
||||
|
||||
|
|
@ -542,7 +556,7 @@ macro_rules! impl_server_handler_for_wrapper {
|
|||
&self,
|
||||
request: CallToolRequestParams,
|
||||
context: RequestContext<RoleServer>,
|
||||
) -> impl Future<Output = Result<CallToolResult, McpError>> + MaybeSendFuture + '_ {
|
||||
) -> impl Future<Output = Result<CallToolResponse, McpError>> + MaybeSendFuture + '_ {
|
||||
(**self).call_tool(request, context)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub use super::common::{Extension, RequestId};
|
|||
use crate::{
|
||||
RoleServer,
|
||||
handler::server::wrapper::Parameters,
|
||||
model::{GetPromptResult, PromptMessage},
|
||||
model::{GetPromptResponse, GetPromptResult, InputRequiredResult, PromptMessage},
|
||||
service::{MaybeBoxFuture, MaybeSend, MaybeSendFuture, RequestContext},
|
||||
};
|
||||
|
||||
|
|
@ -59,12 +59,12 @@ pub trait GetPromptHandler<S, A> {
|
|||
fn handle(
|
||||
self,
|
||||
context: PromptContext<'_, S>,
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResult, crate::ErrorData>>;
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResponse, crate::ErrorData>>;
|
||||
}
|
||||
|
||||
/// Type alias for dynamic prompt handlers
|
||||
#[cfg(not(feature = "local"))]
|
||||
pub type DynGetPromptHandler<S> = dyn for<'a> Fn(PromptContext<'a, S>) -> BoxFuture<'a, Result<GetPromptResult, crate::ErrorData>>
|
||||
pub type DynGetPromptHandler<S> = dyn for<'a> Fn(PromptContext<'a, S>) -> BoxFuture<'a, Result<GetPromptResponse, crate::ErrorData>>
|
||||
+ Send
|
||||
+ Sync;
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ pub type DynGetPromptHandler<S> = dyn for<'a> Fn(
|
|||
PromptContext<'a, S>,
|
||||
) -> futures::future::LocalBoxFuture<
|
||||
'a,
|
||||
Result<GetPromptResult, crate::ErrorData>,
|
||||
Result<GetPromptResponse, crate::ErrorData>,
|
||||
>;
|
||||
|
||||
/// Adapter type for async methods that return `Vec<PromptMessage>`
|
||||
|
|
@ -91,28 +91,35 @@ pub struct SyncPromptMethodAdapter<P, R>(PhantomData<fn(P) -> R>);
|
|||
|
||||
/// Trait for types that can be converted into GetPromptResult
|
||||
pub trait IntoGetPromptResult {
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResult, crate::ErrorData>;
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResponse, crate::ErrorData>;
|
||||
}
|
||||
|
||||
impl IntoGetPromptResult for GetPromptResult {
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResult, crate::ErrorData> {
|
||||
Ok(self)
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResponse, crate::ErrorData> {
|
||||
Ok(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGetPromptResult for InputRequiredResult {
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResponse, crate::ErrorData> {
|
||||
Ok(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGetPromptResult for Vec<PromptMessage> {
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResult, crate::ErrorData> {
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResponse, crate::ErrorData> {
|
||||
Ok(GetPromptResult {
|
||||
result_type: Default::default(),
|
||||
description: None,
|
||||
messages: self,
|
||||
meta: None,
|
||||
})
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IntoGetPromptResult> IntoGetPromptResult for Result<T, crate::ErrorData> {
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResult, crate::ErrorData> {
|
||||
fn into_get_prompt_result(self) -> Result<GetPromptResponse, crate::ErrorData> {
|
||||
self.and_then(|v| v.into_get_prompt_result())
|
||||
}
|
||||
}
|
||||
|
|
@ -129,7 +136,7 @@ pin_project_lite::pin_project! {
|
|||
},
|
||||
Ready {
|
||||
#[pin]
|
||||
result: futures::future::Ready<Result<GetPromptResult, crate::ErrorData>>,
|
||||
result: futures::future::Ready<Result<GetPromptResponse, crate::ErrorData>>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +146,7 @@ where
|
|||
F: Future<Output = R>,
|
||||
R: IntoGetPromptResult,
|
||||
{
|
||||
type Output = Result<GetPromptResult, crate::ErrorData>;
|
||||
type Output = Result<GetPromptResponse, crate::ErrorData>;
|
||||
|
||||
fn poll(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
|
|
@ -216,7 +223,7 @@ macro_rules! impl_prompt_handler_for {
|
|||
fn handle(
|
||||
self,
|
||||
mut context: PromptContext<'_, S>,
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResult, crate::ErrorData>>
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResponse, crate::ErrorData>>
|
||||
{
|
||||
$(
|
||||
let result = $Tn::from_context_part(&mut context);
|
||||
|
|
@ -249,7 +256,7 @@ macro_rules! impl_prompt_handler_for {
|
|||
fn handle(
|
||||
self,
|
||||
mut context: PromptContext<'_, S>,
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResult, crate::ErrorData>>
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResponse, crate::ErrorData>>
|
||||
{
|
||||
$(
|
||||
let result = $Tn::from_context_part(&mut context);
|
||||
|
|
@ -280,7 +287,7 @@ macro_rules! impl_prompt_handler_for {
|
|||
fn handle(
|
||||
self,
|
||||
mut context: PromptContext<'_, S>,
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResult, crate::ErrorData>>
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResponse, crate::ErrorData>>
|
||||
{
|
||||
// Extract all parameters before moving into the async block
|
||||
$(
|
||||
|
|
@ -315,7 +322,7 @@ macro_rules! impl_prompt_handler_for {
|
|||
fn handle(
|
||||
self,
|
||||
mut context: PromptContext<'_, S>,
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResult, crate::ErrorData>>
|
||||
) -> MaybeBoxFuture<'_, Result<GetPromptResponse, crate::ErrorData>>
|
||||
{
|
||||
$(
|
||||
let result = $Tn::from_context_part(&mut context);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ where
|
|||
context,
|
||||
);
|
||||
let result = self.tool_router.call(tool_call_context).await?;
|
||||
Ok(ServerResult::CallToolResult(result))
|
||||
Ok(ServerResult::from(result))
|
||||
} else {
|
||||
self.service
|
||||
.handle_request(ClientRequest::CallToolRequest(request), context)
|
||||
|
|
@ -129,7 +129,7 @@ where
|
|||
context,
|
||||
);
|
||||
let result = self.prompt_router.get_prompt(prompt_context).await?;
|
||||
Ok(ServerResult::GetPromptResult(result))
|
||||
Ok(ServerResult::from(result))
|
||||
} else {
|
||||
self.service
|
||||
.handle_request(ClientRequest::GetPromptRequest(request), context)
|
||||
|
|
@ -193,7 +193,7 @@ mod tests {
|
|||
async fn test_router_deferred_notifier_e2e() {
|
||||
let mut router = Router::new(DummyHandler).with_tool(tool::ToolRoute::new_dyn(
|
||||
Tool::new("my_tool", "test", Arc::new(Default::default())),
|
||||
|_ctx| Box::pin(async { Ok(CallToolResult::default()) }),
|
||||
|_ctx| Box::pin(async { Ok(CallToolResult::default().into()) }),
|
||||
));
|
||||
|
||||
let id_provider: Arc<dyn RequestIdProvider> =
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{borrow::Cow, sync::Arc};
|
|||
|
||||
use crate::{
|
||||
handler::server::prompt::{DynGetPromptHandler, GetPromptHandler, PromptContext},
|
||||
model::{GetPromptResult, Prompt},
|
||||
model::{GetPromptResponse, Prompt},
|
||||
service::{MaybeBoxFuture, MaybeSend},
|
||||
};
|
||||
|
||||
|
|
@ -50,7 +50,8 @@ impl<S: MaybeSend + 'static> PromptRoute<S> {
|
|||
where
|
||||
H: for<'a> Fn(
|
||||
PromptContext<'a, S>,
|
||||
) -> MaybeBoxFuture<'a, Result<GetPromptResult, crate::ErrorData>>
|
||||
)
|
||||
-> MaybeBoxFuture<'a, Result<GetPromptResponse, crate::ErrorData>>
|
||||
+ MaybeSend
|
||||
+ 'static,
|
||||
{
|
||||
|
|
@ -175,7 +176,7 @@ where
|
|||
pub async fn get_prompt(
|
||||
&self,
|
||||
context: PromptContext<'_, S>,
|
||||
) -> Result<GetPromptResult, crate::ErrorData> {
|
||||
) -> Result<GetPromptResponse, crate::ErrorData> {
|
||||
let item = self.map.get(context.name.as_str()).ok_or_else(|| {
|
||||
crate::ErrorData::invalid_params(
|
||||
format!("prompt '{}' not found", context.name),
|
||||
|
|
|
|||
|
|
@ -137,21 +137,19 @@ use crate::{
|
|||
tool::{CallToolHandler, DynCallToolHandler, ToolCallContext},
|
||||
tool_name_validation::validate_and_warn_tool_name,
|
||||
},
|
||||
model::{CallToolResult, ContentBlock, ErrorCode, Tool, ToolAnnotations},
|
||||
model::{CallToolResponse, CallToolResult, ContentBlock, ErrorCode, Tool, ToolAnnotations},
|
||||
service::{MaybeBoxFuture, MaybeSend},
|
||||
};
|
||||
|
||||
const TOOL_ARGUMENT_DESERIALIZATION_ERROR_PREFIX: &str = "failed to deserialize parameters:";
|
||||
|
||||
fn into_tool_argument_error(error: crate::ErrorData) -> Result<CallToolResult, crate::ErrorData> {
|
||||
fn into_tool_argument_error(error: crate::ErrorData) -> Result<CallToolResponse, crate::ErrorData> {
|
||||
if error.code == ErrorCode::INVALID_PARAMS
|
||||
&& error
|
||||
.message
|
||||
.starts_with(TOOL_ARGUMENT_DESERIALIZATION_ERROR_PREFIX)
|
||||
{
|
||||
return Ok(CallToolResult::error(vec![ContentBlock::text(
|
||||
error.message,
|
||||
)]));
|
||||
return Ok(CallToolResult::error(vec![ContentBlock::text(error.message)]).into());
|
||||
}
|
||||
|
||||
Err(error)
|
||||
|
|
@ -200,7 +198,8 @@ impl<S: MaybeSend + 'static> ToolRoute<S> {
|
|||
where
|
||||
C: for<'a> Fn(
|
||||
ToolCallContext<'a, S>,
|
||||
) -> MaybeBoxFuture<'a, Result<CallToolResult, crate::ErrorData>>
|
||||
)
|
||||
-> MaybeBoxFuture<'a, Result<CallToolResponse, crate::ErrorData>>
|
||||
+ MaybeSend
|
||||
+ 'static,
|
||||
{
|
||||
|
|
@ -561,7 +560,7 @@ where
|
|||
pub async fn call(
|
||||
&self,
|
||||
context: ToolCallContext<'_, S>,
|
||||
) -> Result<CallToolResult, crate::ErrorData> {
|
||||
) -> Result<crate::model::CallToolResponse, crate::ErrorData> {
|
||||
let name = context.name();
|
||||
if self.disabled.contains(name) {
|
||||
return Err(crate::ErrorData::invalid_params("tool not found", None));
|
||||
|
|
@ -679,6 +678,9 @@ mod tests {
|
|||
.call(ctx)
|
||||
.await
|
||||
.expect("argument validation should be a tool result");
|
||||
let CallToolResponse::Complete(result) = result else {
|
||||
panic!("expected complete CallToolResult");
|
||||
};
|
||||
assert_eq!(result.is_error, Some(true));
|
||||
|
||||
let text = result
|
||||
|
|
@ -696,7 +698,7 @@ mod tests {
|
|||
let service = DummyService;
|
||||
let mut router = ToolRouter::new().with_route(ToolRoute::new_dyn(
|
||||
crate::model::Tool::new("test_tool", "a test tool", Arc::new(Default::default())),
|
||||
|_ctx| Box::pin(async { Ok(CallToolResult::default()) }),
|
||||
|_ctx| Box::pin(async { Ok(CallToolResult::default().into()) }),
|
||||
));
|
||||
router.disable_route("test_tool");
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ pub use super::{
|
|||
use crate::{
|
||||
RoleServer,
|
||||
handler::server::wrapper::Parameters,
|
||||
model::{CallToolRequestParams, CallToolResult, IntoContents, JsonObject},
|
||||
model::{
|
||||
CallToolRequestParams, CallToolResponse, CallToolResult, InputRequiredResult, IntoContents,
|
||||
JsonObject,
|
||||
},
|
||||
service::{MaybeBoxFuture, MaybeSend, MaybeSendFuture, RequestContext},
|
||||
};
|
||||
|
||||
|
|
@ -77,36 +80,46 @@ impl<S> AsRequestContext for ToolCallContext<'_, S> {
|
|||
}
|
||||
|
||||
pub trait IntoCallToolResult {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResult, crate::ErrorData>;
|
||||
fn into_call_tool_result(self) -> Result<CallToolResponse, crate::ErrorData>;
|
||||
}
|
||||
|
||||
impl<T: IntoContents> IntoCallToolResult for T {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResult, crate::ErrorData> {
|
||||
Ok(CallToolResult::success(self.into_contents()))
|
||||
fn into_call_tool_result(self) -> Result<CallToolResponse, crate::ErrorData> {
|
||||
Ok(CallToolResult::success(self.into_contents()).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoCallToolResult for CallToolResult {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResult, crate::ErrorData> {
|
||||
Ok(self)
|
||||
fn into_call_tool_result(self) -> Result<CallToolResponse, crate::ErrorData> {
|
||||
Ok(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoCallToolResult for InputRequiredResult {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResponse, crate::ErrorData> {
|
||||
Ok(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoCallToolResult for crate::ErrorData {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResult, crate::ErrorData> {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResponse, crate::ErrorData> {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IntoCallToolResult, E: IntoCallToolResult> IntoCallToolResult for Result<T, E> {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResult, crate::ErrorData> {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResponse, crate::ErrorData> {
|
||||
match self {
|
||||
Ok(value) => value.into_call_tool_result(),
|
||||
Err(error) => match error.into_call_tool_result() {
|
||||
Ok(mut result) => {
|
||||
Ok(CallToolResponse::Complete(mut result)) => {
|
||||
result.is_error = Some(true);
|
||||
Ok(result)
|
||||
Ok(result.into())
|
||||
}
|
||||
Ok(CallToolResponse::InputRequired(_)) => Err(crate::ErrorData::internal_error(
|
||||
"InputRequiredResult cannot be returned from a tool error branch",
|
||||
None,
|
||||
)),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
}
|
||||
|
|
@ -124,7 +137,7 @@ pin_project_lite::pin_project! {
|
|||
},
|
||||
Ready {
|
||||
#[pin]
|
||||
result: Ready<Result<CallToolResult, crate::ErrorData>>,
|
||||
result: Ready<Result<CallToolResponse, crate::ErrorData>>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +147,7 @@ where
|
|||
F: Future<Output = R>,
|
||||
R: IntoCallToolResult,
|
||||
{
|
||||
type Output = Result<CallToolResult, crate::ErrorData>;
|
||||
type Output = Result<CallToolResponse, crate::ErrorData>;
|
||||
|
||||
fn poll(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
|
|
@ -153,20 +166,21 @@ pub trait CallToolHandler<S, A> {
|
|||
fn call(
|
||||
self,
|
||||
context: ToolCallContext<'_, S>,
|
||||
) -> MaybeBoxFuture<'_, Result<CallToolResult, crate::ErrorData>>;
|
||||
) -> MaybeBoxFuture<'_, Result<CallToolResponse, crate::ErrorData>>;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "local"))]
|
||||
pub type DynCallToolHandler<S> = dyn for<'s> Fn(ToolCallContext<'s, S>) -> BoxFuture<'s, Result<CallToolResult, crate::ErrorData>>
|
||||
pub type DynCallToolHandler<S> = dyn for<'s> Fn(ToolCallContext<'s, S>) -> BoxFuture<'s, Result<CallToolResponse, crate::ErrorData>>
|
||||
+ Send
|
||||
+ Sync;
|
||||
|
||||
#[cfg(feature = "local")]
|
||||
pub type DynCallToolHandler<S> =
|
||||
dyn for<'s> Fn(
|
||||
ToolCallContext<'s, S>,
|
||||
)
|
||||
-> futures::future::LocalBoxFuture<'s, Result<CallToolResult, crate::ErrorData>>;
|
||||
pub type DynCallToolHandler<S> = dyn for<'s> Fn(
|
||||
ToolCallContext<'s, S>,
|
||||
) -> futures::future::LocalBoxFuture<
|
||||
's,
|
||||
Result<CallToolResponse, crate::ErrorData>,
|
||||
>;
|
||||
|
||||
// Tool-specific extractor for tool name
|
||||
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
|
||||
|
|
@ -205,7 +219,10 @@ impl<S> FromContextPart<ToolCallContext<'_, S>> for JsonObject {
|
|||
}
|
||||
|
||||
impl<'s, S> ToolCallContext<'s, S> {
|
||||
pub fn invoke<H, A>(self, h: H) -> MaybeBoxFuture<'s, Result<CallToolResult, crate::ErrorData>>
|
||||
pub fn invoke<H, A>(
|
||||
self,
|
||||
h: H,
|
||||
) -> MaybeBoxFuture<'s, Result<CallToolResponse, crate::ErrorData>>
|
||||
where
|
||||
H: CallToolHandler<S, A>,
|
||||
{
|
||||
|
|
@ -248,7 +265,7 @@ macro_rules! impl_for {
|
|||
fn call(
|
||||
self,
|
||||
mut context: ToolCallContext<'_, S>,
|
||||
) -> MaybeBoxFuture<'_, Result<CallToolResult, crate::ErrorData>>{
|
||||
) -> MaybeBoxFuture<'_, Result<CallToolResponse, crate::ErrorData>>{
|
||||
$(
|
||||
let result = $Tn::from_context_part(&mut context);
|
||||
let $Tn = match result {
|
||||
|
|
@ -279,7 +296,7 @@ macro_rules! impl_for {
|
|||
fn call(
|
||||
self,
|
||||
mut context: ToolCallContext<S>,
|
||||
) -> MaybeBoxFuture<'static, Result<CallToolResult, crate::ErrorData>>{
|
||||
) -> MaybeBoxFuture<'static, Result<CallToolResponse, crate::ErrorData>>{
|
||||
$(
|
||||
let result = $Tn::from_context_part(&mut context);
|
||||
let $Tn = match result {
|
||||
|
|
@ -308,7 +325,7 @@ macro_rules! impl_for {
|
|||
fn call(
|
||||
self,
|
||||
mut context: ToolCallContext<S>,
|
||||
) -> MaybeBoxFuture<'static, Result<CallToolResult, crate::ErrorData>> {
|
||||
) -> MaybeBoxFuture<'static, Result<CallToolResponse, crate::ErrorData>> {
|
||||
$(
|
||||
let result = $Tn::from_context_part(&mut context);
|
||||
let $Tn = match result {
|
||||
|
|
@ -333,7 +350,7 @@ macro_rules! impl_for {
|
|||
fn call(
|
||||
self,
|
||||
mut context: ToolCallContext<S>,
|
||||
) -> MaybeBoxFuture<'static, Result<CallToolResult, crate::ErrorData>> {
|
||||
) -> MaybeBoxFuture<'static, Result<CallToolResponse, crate::ErrorData>> {
|
||||
$(
|
||||
let result = $Tn::from_context_part(&mut context);
|
||||
let $Tn = match result {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ use std::borrow::Cow;
|
|||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{handler::server::tool::IntoCallToolResult, model::CallToolResult};
|
||||
use crate::{
|
||||
handler::server::tool::IntoCallToolResult,
|
||||
model::{CallToolResponse, CallToolResult},
|
||||
};
|
||||
|
||||
/// Json wrapper for structured output
|
||||
///
|
||||
|
|
@ -27,7 +30,7 @@ impl<T: JsonSchema> JsonSchema for Json<T> {
|
|||
|
||||
// Implementation for Json<T> to create structured content
|
||||
impl<T: Serialize + JsonSchema + 'static> IntoCallToolResult for Json<T> {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResult, crate::ErrorData> {
|
||||
fn into_call_tool_result(self) -> Result<CallToolResponse, crate::ErrorData> {
|
||||
let value = serde_json::to_value(self.0).map_err(|e| {
|
||||
crate::ErrorData::internal_error(
|
||||
format!("Failed to serialize structured content: {}", e),
|
||||
|
|
@ -35,6 +38,6 @@ impl<T: Serialize + JsonSchema + 'static> IntoCallToolResult for Json<T> {
|
|||
)
|
||||
})?;
|
||||
|
||||
Ok(CallToolResult::structured(value))
|
||||
Ok(CallToolResult::structured(value).into())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue