Prompts ======= Prompts are predefined interaction templates provided by the MCP server. They allow servers to guide the LLM's behavior by suggesting a conversation structure or specific context for the user. Unlike tools, which are intended for execution, prompts are intended for context setting and templated interactions. In `mcp-cpp-sdk`, prompts are registered with a name, description, and an optional set of arguments. Clients can discover these prompts and request them with specific arguments to get a list of messages to include in the conversation. Registering a Basic Prompt -------------------------- Prompts are registered with `add_prompt`, which is a template over the handler's input and output types: ``add_prompt(prompt, handler)``. Passing `nlohmann::json` for both is the untyped route, and suits simple cases where you don't need full type safety for the handler parameters or result. .. literalinclude:: ../../examples/servers/stdio/server_stdio.cpp :language: cpp :start-after: docs-begin: untyped-prompt :end-before: docs-end: untyped-prompt :dedent: 8 .. warning:: A prompt handler receives the **entire** ``GetPromptRequestParams``, not just the arguments. For a ``prompts/get`` request naming ``greet`` with argument ``who``, the handler is passed ``{"name": "greet", "arguments": {"who": "world"}}``, so the argument is read as ``params.value("arguments", json::object()).value("who", ...)``. Reading ``params.value("who", ...)`` directly compiles, raises no error, and silently yields the default value. This differs from tool handlers, which receive the tool arguments already unwrapped. A prompt carries a name its handler may need, so the whole parameter object is passed through. The handler returns a `nlohmann::json` object representing the `GetPromptResult`. Parameterized Prompts and Arguments ----------------------------------- For more complex scenarios, you can use the typed `add_prompt` overload which utilizes the protocol's internal structures. This approach provides better type safety and allows for more detailed metadata about prompt arguments. Prompt arguments are defined using the `PromptArgument` struct, where you can specify whether an argument is required and provide a detailed description. .. literalinclude:: ../../examples/servers/stdio/server_stdio.cpp :language: cpp :start-after: // Prompt: code_review (parameterized) :end-before: boost::asio::io_context io_ctx; :dedent: 8 In this example, the `code_review` prompt takes two required arguments: `language` and `code`. The handler extracts these from the `GetPromptRequestParams` and constructs a `GetPromptResult`. Structured Prompt Results ------------------------- The result of a prompt is a `GetPromptResult` object, which primarily contains a list of `PromptMessage` objects. Each message has a role (e.g., `user` or `assistant`) and content. Roles ~~~~~ Roles are defined by the `mcp::Role` enum. These roles are critical for the LLM to understand the conversation flow and distinguish between user input and previous assistant responses. - `Role::eUser`: Represents messages originating from the user. In most cases, prompt results consist primarily of user messages that set the stage for the LLM. - `Role::eAssistant`: Represents messages that were previously generated by the assistant. These are useful for providing few-shot examples or simulating a continuing conversation. Content Blocks ~~~~~~~~~~~~~~ The content of a message is a `ContentBlock`. While the most common type is `TextContent`, MCP supports other content types like images and resources. Text Content ^^^^^^^^^^^^ In `mcp-cpp-sdk`, you typically use `TextContent` for prompt responses. This is the standard way to provide instructions or context to the LLM. .. code-block:: cpp PromptMessage msg; msg.role = Role::eUser; TextContent text; text.text = "Review this code..."; msg.content = std::move(text); Image Content ^^^^^^^^^^^^^ For multimodal models, you can also include images in your prompts. This is done by providing base64 encoded image data and its MIME type. .. code-block:: cpp ImageContent image; image.data = "base64_encoded_image_data"; image.mimeType = "image/png"; msg.content = std::move(image); Resource Content ^^^^^^^^^^^^^^^^ Prompts can also reference resources directly. This allows you to include dynamic content from your server's resources in the prompt response. .. code-block:: cpp EmbeddedResource resource; resource.resource.uri = "mcp://system/config"; resource.resource.text = "System configuration data..."; msg.content = std::move(resource); Advanced Registration --------------------- The `add_prompt` method is a template that supports various handler signatures, including asynchronous handlers and handlers that receive a `mcp::Context`. Async Handlers ~~~~~~~~~~~~~~ Asynchronous handlers are essential for operations that might take time, such as fetching data from an external database or performing complex computations before returning the prompt content. .. code-block:: cpp server.add_prompt( metadata, [](GetPromptRequestParams params) -> mcp::Task { // Perform async operations here co_return result; }); Using Context ~~~~~~~~~~~~~ Handlers can also receive a `mcp::Context&` as their first argument. This provides access to logging, progress reporting, and cancellation checks. .. code-block:: cpp server.add_prompt( metadata, [](mcp::Context& ctx, GetPromptRequestParams params) -> mcp::Task { co_await ctx.log_info("Generating prompt for " + params.name); if (ctx.is_cancelled()) { throw std::runtime_error("Request cancelled"); } // ... logic ... co_return result; }); Prompt List Change Notifications -------------------------------- If your server's available prompts change dynamically, you should notify connected clients so they can refresh their cache. Use the `notify_prompts_list_changed` method: .. code-block:: cpp co_await server.notify_prompts_list_changed(); This sends a `notifications/prompts/list_changed` message to the client, prompting them to call `prompts/list` again if they need the updated list. Prompt Capabilities ------------------- To enable prompts, include them in your server capabilities during initialization. If the client does not see prompt capabilities, it may not attempt to list or get prompts. .. code-block:: cpp mcp::ServerCapabilities caps; caps.prompts = mcp::ServerCapabilities::PromptsCapability{ .listChanged = true // Enable list change notifications }; mcp::Server server(info, std::move(caps)); By setting `listChanged` to `true`, you inform the client that your server is capable of sending notifications when the prompt list changes, allowing for a more dynamic and responsive integration.