MCP Prompts
Prompts are reusable message templates that clients can retrieve from the server and inject directly into a conversation. Unlike tools (which the AI calls autonomously), prompts are user-initiated: the client fetches the template, fills in arguments, and inserts the resulting messages.
Registering a prompt
Call .prompt(name, description, handler) on McpServer:
use rust_web_server::mcp::{McpServer, PromptMessage, extract_arg};
let mcp = McpServer::new("my-server", "1.0") .prompt( "summarize", "Summarize the given text", |args| { let text = extract_arg(args, "text") .unwrap_or_else(|| "some text".to_string()); Ok(vec![PromptMessage::user(format!("Please summarize: {text}"))]) }, );The handler signature is:
Fn(&str) -> Result<Vec<PromptMessage>, String>The &str argument is the raw arguments JSON object sent by the client (e.g. {"text":"hello"}). Return Err(String) to surface an error to the client.
PromptMessage
Build individual messages with the two constructor methods:
PromptMessage::user("content") // role: "user"PromptMessage::assistant("content") // role: "assistant"A handler can return any mix of user and assistant messages. The MCP client inserts them into the conversation in order.
Extracting arguments with extract_arg
extract_arg(args_json, "param_name") does a lightweight key lookup on the raw JSON string without pulling in a JSON library:
use rust_web_server::mcp::extract_arg;
let args = r#"{"language":"rust","code":"fn main(){}"}"#;let lang = extract_arg(args, "language"); // Some("rust")let missing = extract_arg(args, "other"); // NoneReturn a default or an error when the argument is absent:
let lang = extract_arg(args, "language") .ok_or_else(|| "missing required argument: language".to_string())?;Declaring argument metadata with prompt_with_args
Use .prompt_with_args to attach typed argument definitions. These are returned in prompts/list so clients can render a form:
use rust_web_server::mcp::{McpServer, PromptArgDef, PromptMessage, extract_arg};
let mcp = McpServer::new("my-server", "1.0") .prompt_with_args( "code_review", "Request a code review for a snippet", vec![ PromptArgDef::required("language", "Programming language of the snippet"), PromptArgDef::required("code", "Source code to review"), ], |args| { let language = extract_arg(args, "language") .unwrap_or_else(|| "unknown".to_string()); let code = extract_arg(args, "code") .unwrap_or_else(|| "(no code provided)".to_string()); Ok(vec![PromptMessage::user(format!( "Please review the following {language} code and point out any bugs, \ style issues, or improvements:\n\n```{language}\n{code}\n```" ))]) }, );PromptArgDef::required(name, description) marks the argument as required. Use PromptArgDef::optional(name, description) for optional ones.
JSON-RPC methods
prompts/list
The client sends:
{"jsonrpc":"2.0","id":1,"method":"prompts/list"}The server responds with every registered prompt including its argument definitions:
{ "jsonrpc": "2.0", "result": { "prompts": [ { "name": "code_review", "description": "Request a code review for a snippet", "arguments": [ {"name":"language","description":"Programming language of the snippet","required":true}, {"name":"code", "description":"Source code to review", "required":true} ] } ] }, "id": 1}prompts/get
The client sends the prompt name and the filled-in arguments:
{ "jsonrpc": "2.0", "id": 2, "method": "prompts/get", "params": { "name": "code_review", "arguments": { "language": "rust", "code": "fn add(a: i32, b: i32) -> i32 { a + b }" } }}The server calls the handler with the serialised arguments object and responds:
{ "jsonrpc": "2.0", "result": { "description": "Request a code review for a snippet", "messages": [ { "role": "user", "content": { "type": "text", "text": "Please review the following rust code ..." } } ] }, "id": 2}Complete example: code-review prompt
use rust_web_server::server::Server;use rust_web_server::mcp::{McpServer, PromptArgDef, PromptMessage, extract_arg};
# #[cfg(not(feature = "http2"))]# fn main() {let mcp = McpServer::new("code-tools", "1.0") .prompt_with_args( "code_review", "Generate a code-review request message", vec![ PromptArgDef::required("language", "Programming language (e.g. rust, python)"), PromptArgDef::required("code", "Source code to review"), PromptArgDef::optional("focus", "Optional focus area, e.g. performance or safety"), ], |args| { let language = extract_arg(args, "language") .ok_or_else(|| "argument 'language' is required".to_string())?; let code = extract_arg(args, "code") .ok_or_else(|| "argument 'code' is required".to_string())?; let focus_clause = match extract_arg(args, "focus") { Some(f) => format!(" Pay particular attention to {f}."), None => String::new(), };
Ok(vec![PromptMessage::user(format!( "Please review the following {language} code for correctness, \ style, and potential improvements.{focus_clause}\n\n\ ```{language}\n{code}\n```" ))]) }, );
let (listener, pool) = Server::setup().unwrap();Server::run(listener, pool, mcp);# }