feat!: align model types with MCP 2025-11-25 spec (#927)
* feat!: align model types with MCP 2025-11-25 spec * fix: complete 2025-11-25 model spec conformance
This commit is contained in:
parent
42a1069833
commit
77932141e3
9 changed files with 4321 additions and 3886 deletions
|
|
@ -11,8 +11,8 @@ use anyhow::{Result, anyhow};
|
|||
use rmcp::{
|
||||
ServiceExt,
|
||||
model::{
|
||||
CallToolRequestParams, CallToolResult, ClientRequest, GetTaskInfoParams,
|
||||
GetTaskResultParams, JsonObject, Request, ServerResult, TaskStatus,
|
||||
CallToolRequestParams, CallToolResult, ClientRequest, GetTaskParams, GetTaskPayloadParams,
|
||||
Request, ServerResult, TaskMetadata, TaskStatus,
|
||||
},
|
||||
object,
|
||||
transport::{ConfigureCommandExt, TokioChildProcess},
|
||||
|
|
@ -53,14 +53,14 @@ async fn main() -> Result<()> {
|
|||
.await?;
|
||||
tracing::info!("quick_echo -> {echo:#?}");
|
||||
|
||||
// 2) Task call. `slow_sum` is task_support = required, so we MUST attach a
|
||||
// `task` object. An empty object is fine — clients can stash arbitrary
|
||||
// metadata here that the server-side `OperationDescriptor` will keep.
|
||||
// 2) Task call. `slow_sum` is task_support = required, so we MUST attach
|
||||
// `task` metadata. An empty `TaskMetadata` is fine; use `.with_ttl(...)`
|
||||
// to set a retention window.
|
||||
let create = client
|
||||
.send_request(ClientRequest::CallToolRequest(Request::new(
|
||||
CallToolRequestParams::new("slow_sum")
|
||||
.with_arguments(object!({ "a": 40, "b": 2 }))
|
||||
.with_task(JsonObject::new()),
|
||||
.with_task(TaskMetadata::new()),
|
||||
)))
|
||||
.await?;
|
||||
let ServerResult::CreateTaskResult(create) = create else {
|
||||
|
|
@ -77,11 +77,8 @@ async fn main() -> Result<()> {
|
|||
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
|
||||
|
||||
let info = client
|
||||
.send_request(ClientRequest::GetTaskInfoRequest(Request::new(
|
||||
GetTaskInfoParams {
|
||||
meta: None,
|
||||
task_id: task_id.clone(),
|
||||
},
|
||||
.send_request(ClientRequest::GetTaskRequest(Request::new(
|
||||
GetTaskParams::new(task_id.clone()),
|
||||
)))
|
||||
.await?;
|
||||
let ServerResult::GetTaskResult(info) = info else {
|
||||
|
|
@ -108,11 +105,8 @@ async fn main() -> Result<()> {
|
|||
// here. (For a non-tool task the same value would surface as
|
||||
// `ServerResult::CustomResult` and need manual `serde_json::from_value`.)
|
||||
let payload = client
|
||||
.send_request(ClientRequest::GetTaskResultRequest(Request::new(
|
||||
GetTaskResultParams {
|
||||
meta: None,
|
||||
task_id: task_id.clone(),
|
||||
},
|
||||
.send_request(ClientRequest::GetTaskPayloadRequest(Request::new(
|
||||
GetTaskPayloadParams::new(task_id.clone()),
|
||||
)))
|
||||
.await?;
|
||||
let call_result: CallToolResult = match payload {
|
||||
|
|
|
|||
|
|
@ -94,14 +94,14 @@ impl Counter {
|
|||
}
|
||||
|
||||
fn _create_resource_text(&self, uri: &str, name: &str) -> Resource {
|
||||
RawResource::new(uri, name.to_string()).no_annotation()
|
||||
Resource::new(uri, name.to_string())
|
||||
}
|
||||
|
||||
#[tool(description = "Increment the counter by 1")]
|
||||
async fn increment(&self) -> Result<CallToolResult, McpError> {
|
||||
let mut counter = self.counter.lock().await;
|
||||
*counter += 1;
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
counter.to_string(),
|
||||
)]))
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ impl Counter {
|
|||
async fn decrement(&self) -> Result<CallToolResult, McpError> {
|
||||
let mut counter = self.counter.lock().await;
|
||||
*counter -= 1;
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
counter.to_string(),
|
||||
)]))
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ impl Counter {
|
|||
#[tool(description = "Get the current counter value")]
|
||||
async fn get_value(&self) -> Result<CallToolResult, McpError> {
|
||||
let counter = self.counter.lock().await;
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
counter.to_string(),
|
||||
)]))
|
||||
}
|
||||
|
|
@ -129,19 +129,19 @@ impl Counter {
|
|||
)]
|
||||
async fn long_task(&self) -> Result<CallToolResult, McpError> {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
"Long task completed",
|
||||
)]))
|
||||
}
|
||||
|
||||
#[tool(description = "Say hello to the client")]
|
||||
fn say_hello(&self) -> Result<CallToolResult, McpError> {
|
||||
Ok(CallToolResult::success(vec![Content::text("hello")]))
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text("hello")]))
|
||||
}
|
||||
|
||||
#[tool(description = "Repeat what you say")]
|
||||
fn echo(&self, Parameters(object): Parameters<JsonObject>) -> Result<CallToolResult, McpError> {
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
serde_json::Value::Object(object).to_string(),
|
||||
)]))
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ impl Counter {
|
|||
&self,
|
||||
Parameters(StructRequest { a, b }): Parameters<StructRequest>,
|
||||
) -> Result<CallToolResult, McpError> {
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
(a + b).to_string(),
|
||||
)]))
|
||||
}
|
||||
|
|
@ -166,8 +166,8 @@ impl Counter {
|
|||
.map(|v| v.to_str().unwrap_or("(non-ascii)").to_owned());
|
||||
|
||||
match session_id {
|
||||
Some(id) => Ok(CallToolResult::success(vec![Content::text(id)])),
|
||||
None => Ok(CallToolResult::success(vec![Content::text(
|
||||
Some(id) => Ok(CallToolResult::success(vec![ContentBlock::text(id)])),
|
||||
None => Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
"no session (not running over streamable HTTP?)",
|
||||
)])),
|
||||
}
|
||||
|
|
@ -190,10 +190,7 @@ impl Counter {
|
|||
"This is an example prompt with your message here: '{}'",
|
||||
args.message
|
||||
);
|
||||
Ok(vec![PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
prompt,
|
||||
)])
|
||||
Ok(vec![PromptMessage::new_text(Role::User, prompt)])
|
||||
}
|
||||
|
||||
/// Analyze the current counter value and suggest next steps
|
||||
|
|
@ -209,11 +206,11 @@ impl Counter {
|
|||
|
||||
let messages = vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
"I'll analyze the counter situation and suggest the best approach.",
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!(
|
||||
"Current counter value: {}\nGoal value: {}\nDifference: {}\nStrategy preference: {}\n\nPlease analyze the situation and suggest the best approach to reach the goal.",
|
||||
current_value, args.goal, difference, strategy
|
||||
|
|
@ -406,12 +403,7 @@ mod tests {
|
|||
});
|
||||
|
||||
let client_service = client.serve(client_transport).await?;
|
||||
let mut task_meta = serde_json::Map::new();
|
||||
task_meta.insert(
|
||||
"source".into(),
|
||||
serde_json::Value::String("integration-test".into()),
|
||||
);
|
||||
let params = CallToolRequestParams::new("long_task").with_task(task_meta);
|
||||
let params = CallToolRequestParams::new("long_task").with_task(TaskMetadata::new());
|
||||
let response = client_service
|
||||
.send_request(ClientRequest::CallToolRequest(Request::new(params.clone())))
|
||||
.await?;
|
||||
|
|
|
|||
|
|
@ -97,12 +97,12 @@ impl ProgressDemo {
|
|||
let chunk_str = String::from_utf8_lossy(&chunk);
|
||||
counter += 1;
|
||||
// create progress notification param
|
||||
let progress_param = ProgressNotificationParam {
|
||||
progress_token: ProgressToken(progress_token.clone()),
|
||||
progress: counter as f64,
|
||||
total: Some(5.0),
|
||||
message: Some(chunk_str.to_string()),
|
||||
};
|
||||
let progress_param = ProgressNotificationParam::new(
|
||||
ProgressToken(progress_token.clone()),
|
||||
counter as f64,
|
||||
)
|
||||
.with_total(5.0)
|
||||
.with_message(chunk_str.to_string());
|
||||
|
||||
match ctx.peer.notify_progress(progress_param).await {
|
||||
Ok(_) => {
|
||||
|
|
@ -122,7 +122,7 @@ impl ProgressDemo {
|
|||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
|
||||
Ok(CallToolResult::success(vec![Content::text(format!(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(format!(
|
||||
"Processed {} records successfully",
|
||||
counter
|
||||
))]))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use std::sync::Arc;
|
|||
use rmcp::{
|
||||
ErrorData as McpError, ServerHandler,
|
||||
handler::server::{router::tool::ToolRouter, wrapper::Parameters},
|
||||
model::{CallToolResult, Content},
|
||||
model::{CallToolResult, ContentBlock},
|
||||
schemars, task_handler,
|
||||
task_manager::OperationProcessor,
|
||||
tool, tool_handler, tool_router,
|
||||
|
|
@ -70,7 +70,7 @@ impl TaskDemo {
|
|||
Parameters(SumArgs { a, b }): Parameters<SumArgs>,
|
||||
) -> Result<CallToolResult, McpError> {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
(a + b).to_string(),
|
||||
)]))
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ impl TaskDemo {
|
|||
&self,
|
||||
Parameters(EchoArgs { message }): Parameters<EchoArgs>,
|
||||
) -> Result<CallToolResult, McpError> {
|
||||
Ok(CallToolResult::success(vec![Content::text(message)]))
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(message)]))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -203,11 +203,11 @@ impl SqlQueryServer {
|
|||
let messages = if args.operation.is_empty() {
|
||||
vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
"I need help building a SQL query. Where should I start?",
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
"I'll help you build a SQL query step by step. First, what type of operation do you want to perform? \
|
||||
Choose from: SELECT (to read data), INSERT (to add data), UPDATE (to modify data), or DELETE (to remove data).",
|
||||
),
|
||||
|
|
@ -215,11 +215,11 @@ impl SqlQueryServer {
|
|||
} else if args.table.is_empty() {
|
||||
vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!("I want to {} data. What's next?", args.operation),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"Great! For a {} operation, I need to know which table you want to work with. \
|
||||
What's the name of your database table?",
|
||||
|
|
@ -277,11 +277,11 @@ impl SqlQueryServer {
|
|||
|
||||
vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
"Generate the SQL query based on my parameters and explain what it does.",
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"Here's your SQL query:\n\n```sql\n{}\n```\n\nThis query will {} the {} table.",
|
||||
query,
|
||||
|
|
@ -405,11 +405,8 @@ impl ServerHandler for SqlQueryServer {
|
|||
|
||||
let suggestions = self.fuzzy_match(&request.argument.value, &candidates);
|
||||
|
||||
let completion = CompletionInfo {
|
||||
values: suggestions,
|
||||
total: None,
|
||||
has_more: Some(false),
|
||||
};
|
||||
let completion = CompletionInfo::with_pagination(suggestions, None, false)
|
||||
.map_err(|e| McpError::internal_error(e, None))?;
|
||||
|
||||
Ok(CompleteResult::new(completion))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ impl ElicitationEnumFormServer {
|
|||
#[tool(description = "Get current enum selection form")]
|
||||
async fn get_enum_form(&self) -> Result<CallToolResult, McpError> {
|
||||
let guard = self.selection.lock().await;
|
||||
Ok(CallToolResult::success(vec![Content::text(format!(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(format!(
|
||||
"{}",
|
||||
*guard
|
||||
))]))
|
||||
|
|
@ -133,13 +133,13 @@ impl ElicitationEnumFormServer {
|
|||
Ok(Some(form)) => {
|
||||
let mut guard = self.selection.lock().await;
|
||||
*guard = form;
|
||||
Ok(CallToolResult::success(vec![Content::text(format!(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(format!(
|
||||
"Updated Selection:\n{}",
|
||||
*guard
|
||||
))]))
|
||||
}
|
||||
Ok(None) => {
|
||||
return Ok(CallToolResult::success(vec![Content::text(
|
||||
return Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
"Elicitation cancelled by user.",
|
||||
)]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl ElicitationServer {
|
|||
}
|
||||
};
|
||||
|
||||
Ok(CallToolResult::success(vec![Content::text(format!(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(format!(
|
||||
"{} {}!",
|
||||
request.greeting, user_name
|
||||
))]))
|
||||
|
|
@ -103,7 +103,7 @@ impl ElicitationServer {
|
|||
#[tool(description = "Reset stored user name")]
|
||||
async fn reset_name(&self) -> Result<CallToolResult, McpError> {
|
||||
*self.user_name.lock().await = None;
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
"User name reset. Next greeting will ask for name again.".to_string(),
|
||||
)]))
|
||||
}
|
||||
|
|
@ -133,20 +133,23 @@ impl ElicitationServer {
|
|||
// Mock notifying completion
|
||||
let _ = context
|
||||
.peer
|
||||
.notify_url_elicitation_completed(ElicitationResponseNotificationParam {
|
||||
elicitation_id: "elicit_123".to_string(),
|
||||
})
|
||||
.notify_url_elicitation_completed(ElicitationResponseNotificationParam::new(
|
||||
"elicit_123",
|
||||
))
|
||||
.await;
|
||||
Ok(CallToolResult::success(vec![Content::text(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
"Elicitation via URL successful".to_string(),
|
||||
)]))
|
||||
}
|
||||
ElicitationAction::Cancel => Ok(CallToolResult::success(vec![Content::text(
|
||||
ElicitationAction::Cancel => Ok(CallToolResult::success(vec![ContentBlock::text(
|
||||
"Elicitation via URL cancelled by user".to_string(),
|
||||
)])),
|
||||
ElicitationAction::Decline => Ok(CallToolResult::error(vec![Content::text(
|
||||
ElicitationAction::Decline => Ok(CallToolResult::error(vec![ContentBlock::text(
|
||||
"Elicitation via URL declined by user".to_string(),
|
||||
)])),
|
||||
_ => Ok(CallToolResult::error(vec![ContentBlock::text(
|
||||
"Unknown elicitation action".to_string(),
|
||||
)])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,12 +121,9 @@ impl PromptServer {
|
|||
)]
|
||||
async fn greeting(&self) -> Vec<PromptMessage> {
|
||||
vec![
|
||||
PromptMessage::new_text(Role::User, "Hello! I'd like to start our conversation."),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
"Hello! I'd like to start our conversation.",
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
"Hello! I'm here to help. What would you like to discuss today?",
|
||||
),
|
||||
]
|
||||
|
|
@ -148,14 +145,14 @@ impl PromptServer {
|
|||
|
||||
let messages = vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"You are an expert {} code reviewer. The user's expertise level is {}.",
|
||||
args.language, prefs.expertise_level
|
||||
),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!(
|
||||
"Please review the {} code at '{}'. Focus on: {}",
|
||||
args.language,
|
||||
|
|
@ -164,7 +161,7 @@ impl PromptServer {
|
|||
),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"I'll review your {} code focusing on {}. Let me analyze the code at '{}'...",
|
||||
args.language,
|
||||
|
|
@ -203,14 +200,14 @@ impl PromptServer {
|
|||
|
||||
Ok(vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!(
|
||||
"I have {} data that needs {} analysis. Context: {}",
|
||||
args.data_type, args.analysis_type, context
|
||||
),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"I'll help you analyze your {} data using {} techniques. Based on your context, \
|
||||
I'll focus on providing actionable insights.",
|
||||
|
|
@ -233,7 +230,7 @@ impl PromptServer {
|
|||
|
||||
let mut messages = vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"You are a writing assistant helping create {} content for {}. \
|
||||
Use a {} tone.",
|
||||
|
|
@ -241,7 +238,7 @@ impl PromptServer {
|
|||
),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!(
|
||||
"I need help writing {} for {}. Key points to cover: {}",
|
||||
args.content_type,
|
||||
|
|
@ -250,7 +247,7 @@ impl PromptServer {
|
|||
),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
"I'll help you create that content. Let me structure it based on your key points.",
|
||||
),
|
||||
];
|
||||
|
|
@ -258,11 +255,11 @@ impl PromptServer {
|
|||
// Add a message for each key point
|
||||
for (i, point) in args.key_points.iter().enumerate() {
|
||||
messages.push(PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!("For point {}: {}, what would you suggest?", i + 1, point),
|
||||
));
|
||||
messages.push(PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!("For '{}', I recommend...", point),
|
||||
));
|
||||
}
|
||||
|
|
@ -291,14 +288,14 @@ impl PromptServer {
|
|||
|
||||
let mut messages = vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"You are a debugging expert for {}. Help diagnose and fix issues.",
|
||||
args.stack.join(", ")
|
||||
),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!(
|
||||
"I'm encountering this error: {}\nStack: {}",
|
||||
args.error_message,
|
||||
|
|
@ -311,18 +308,18 @@ impl PromptServer {
|
|||
if let Some(tried) = args.tried_solutions {
|
||||
if !tried.is_empty() {
|
||||
messages.push(PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
format!("I've already tried: {}", tried.join(", ")),
|
||||
));
|
||||
messages.push(PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
"I see you've already attempted some solutions. Let me suggest different approaches.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
messages.push(PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
"Let's debug this systematically. First, let me understand the error context better.",
|
||||
));
|
||||
|
||||
|
|
@ -343,18 +340,18 @@ impl PromptServer {
|
|||
|
||||
Ok(vec![
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"Create a learning path for someone at {} level who prefers {} language explanations.",
|
||||
prefs.expertise_level, prefs.preferred_language
|
||||
),
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::User,
|
||||
Role::User,
|
||||
"What should I learn next to improve my programming skills?",
|
||||
),
|
||||
PromptMessage::new_text(
|
||||
PromptMessageRole::Assistant,
|
||||
Role::Assistant,
|
||||
format!(
|
||||
"Based on your {} expertise level, I recommend the following learning path...",
|
||||
prefs.expertise_level
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ impl ServerHandler for SamplingDemoServer {
|
|||
)
|
||||
})?;
|
||||
tracing::debug!("Response: {:?}", response);
|
||||
Ok(CallToolResult::success(vec![Content::text(format!(
|
||||
Ok(CallToolResult::success(vec![ContentBlock::text(format!(
|
||||
"Question: {}\nAnswer: {}",
|
||||
question,
|
||||
response
|
||||
|
|
|
|||
Loading…
Reference in a new issue