Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/rmcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@ name = "test_custom_request"
required-features = ["server", "client"]
path = "tests/test_custom_request.rs"

[[test]]
name = "test_task_client_receiver"
required-features = ["server", "client"]
path = "tests/test_task_client_receiver.rs"

[[test]]
name = "test_prompt_macros"
required-features = ["server", "client"]
Expand Down
110 changes: 110 additions & 0 deletions crates/rmcp/src/handler/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ impl<H: ClientHandler> Service<RoleClient> for H {
.create_elicitation(request.params, context)
.await
.map(ClientResult::CreateElicitationResult),
ServerRequest::ListTasksRequest(request) => self
.list_tasks(request.params, context)
.await
.map(ClientResult::ListTasksResult),
ServerRequest::GetTaskInfoRequest(request) => self
.get_task_info(request.params, context)
.await
.map(ClientResult::GetTaskResult),
ServerRequest::GetTaskResultRequest(request) => self
.get_task_result(request.params, context)
.await
.map(ClientResult::GetTaskPayloadResult),
ServerRequest::CancelTaskRequest(request) => self
.cancel_task(request.params, context)
.await
.map(ClientResult::CancelTaskResult),
ServerRequest::CustomRequest(request) => self
.on_custom_request(request, context)
.await
Expand Down Expand Up @@ -191,6 +207,68 @@ pub trait ClientHandler: Sized + Send + Sync + 'static {
)))
}

/// Handle a `tasks/list` request from a server. Only relevant when the
/// client is also a task *receiver* (e.g. it accepted a task-augmented
/// `sampling/createMessage` or `elicitation/create` request).
///
/// # Default Behavior
/// Returns `-32601` (Method not found). Clients that advertise
/// `capabilities.tasks.list` must override this.
fn list_tasks(
&self,
request: Option<PaginatedRequestParams>,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<ListTasksResult, McpError>> + MaybeSendFuture + '_ {
let _ = (request, context);
std::future::ready(Err(McpError::method_not_found::<ListTasksMethod>()))
}

/// Handle a `tasks/get` request from a server. Only relevant when the
/// client is also a task *receiver* (e.g. it accepted a task-augmented
/// `sampling/createMessage` or `elicitation/create` request).
///
/// # Default Behavior
/// Returns `-32601` (Method not found). Clients that advertise
/// `capabilities.tasks.requests.sampling.createMessage` or
/// `capabilities.tasks.requests.elicitation.create` must override this.
fn get_task_info(
&self,
request: GetTaskInfoParams,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<GetTaskResult, McpError>> + MaybeSendFuture + '_ {
let _ = (request, context);
std::future::ready(Err(McpError::method_not_found::<GetTaskInfoMethod>()))
}

/// Handle a `tasks/result` request from a server. Only relevant when
/// the client is also a task *receiver*.
///
/// # Default Behavior
/// Returns `-32601` (Method not found).
fn get_task_result(
&self,
request: GetTaskResultParams,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<GetTaskPayloadResult, McpError>> + MaybeSendFuture + '_ {
let _ = (request, context);
std::future::ready(Err(McpError::method_not_found::<GetTaskResultMethod>()))
}

/// Handle a `tasks/cancel` request from a server. Only relevant when
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tasks/cancel is not in the SEP as I see it https://modelcontextprotocol.io/seps/1686-tasks

tasks/delete I think is perhaps what is meant?

https://modelcontextprotocol.io/seps/1686-tasks#3-6-deleting-tasks

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 6d45614.

Renamed across the board: method string is now tasks/delete, types are DeleteTaskMethod / DeleteTaskParams / DeleteTaskRequest / DeleteTaskResult, and the trait methods on ClientHandler / ServerHandler are delete_task. The terminal cancelled task status stays (it's named that way in the SEP).

A couple of related fixes that fell out of the rename:

  • DeleteTaskResult now carries only _meta, matching the §3.6 wire response (the old CancelTaskResult flattened a Task in, which wasn't in the spec).
  • Gave DeleteTaskResult the same always-fail Deserialize impl used for GetTaskPayloadResult so its near-empty shape doesn't shadow EmptyResult / CustomResult in the untagged ClientResult / ServerResult enums. On the wire, delete responses now fall through to EmptyResult.
  • TaskManager got a new delete_task helper that aborts a running task AND removes any stored completed result — the actual delete semantics. The #[task_handler] macro now uses it.

/// the client is also a task *receiver*.
///
/// # Default Behavior
/// Returns `-32601` (Method not found). Clients that advertise
/// `capabilities.tasks.cancel` must override this.
fn cancel_task(
&self,
request: CancelTaskParams,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<CancelTaskResult, McpError>> + MaybeSendFuture + '_ {
let _ = (request, context);
std::future::ready(Err(McpError::method_not_found::<CancelTaskMethod>()))
}

fn on_cancelled(
&self,
params: CancelledNotificationParam,
Expand Down Expand Up @@ -310,6 +388,38 @@ macro_rules! impl_client_handler_for_wrapper {
(**self).on_custom_request(request, context)
}

fn list_tasks(
&self,
request: Option<PaginatedRequestParams>,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<ListTasksResult, McpError>> + MaybeSendFuture + '_ {
(**self).list_tasks(request, context)
}

fn get_task_info(
&self,
request: GetTaskInfoParams,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<GetTaskResult, McpError>> + MaybeSendFuture + '_ {
(**self).get_task_info(request, context)
}

fn get_task_result(
&self,
request: GetTaskResultParams,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<GetTaskPayloadResult, McpError>> + MaybeSendFuture + '_ {
(**self).get_task_result(request, context)
}

fn cancel_task(
&self,
request: CancelTaskParams,
context: RequestContext<RoleClient>,
) -> impl Future<Output = Result<CancelTaskResult, McpError>> + MaybeSendFuture + '_ {
(**self).cancel_task(request, context)
}

fn on_cancelled(
&self,
params: CancelledNotificationParam,
Expand Down
24 changes: 24 additions & 0 deletions crates/rmcp/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3323,6 +3323,10 @@ ts_union!(
box CreateMessageResult
| ListRootsResult
| CreateElicitationResult
| ListTasksResult
| GetTaskResult
| GetTaskPayloadResult
| CancelTaskResult
| EmptyResult
| CustomResult;
);
Expand All @@ -3341,9 +3345,29 @@ ts_union!(
| CreateMessageRequest
| ListRootsRequest
| CreateElicitationRequest
| GetTaskInfoRequest
| ListTasksRequest
| GetTaskResultRequest
| CancelTaskRequest
| CustomRequest;
);

impl ServerRequest {
pub fn method(&self) -> &str {
match &self {
ServerRequest::PingRequest(r) => r.method.as_str(),
ServerRequest::CreateMessageRequest(r) => r.method.as_str(),
ServerRequest::ListRootsRequest(r) => r.method.as_str(),
ServerRequest::CreateElicitationRequest(r) => r.method.as_str(),
ServerRequest::GetTaskInfoRequest(r) => r.method.as_str(),
ServerRequest::ListTasksRequest(r) => r.method.as_str(),
ServerRequest::GetTaskResultRequest(r) => r.method.as_str(),
ServerRequest::CancelTaskRequest(r) => r.method.as_str(),
ServerRequest::CustomRequest(r) => r.method.as_str(),
}
}
}

ts_union!(
export type ServerNotification =
| CancelledNotification
Expand Down
4 changes: 4 additions & 0 deletions crates/rmcp/src/model/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ variant_extension! {
ListRootsRequest
CreateElicitationRequest
CustomRequest
GetTaskInfoRequest
ListTasksRequest
GetTaskResultRequest
CancelTaskRequest
}
}

Expand Down
Loading