Skip to content

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"); // None

Return 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);
# }