---
url: /mcp.zig/guide/prompts.md
description: >-
  Define and use MCP prompts — reusable templates for structuring AI
  interactions and workflows.
---

# Prompts

Prompts are reusable templates that help structure interactions with AI models.

## Defining a Prompt

```zig
try server.addPrompt(.{
    .name = "summarize",
    .description = "Summarize a piece of text",
    .handler = summarizeHandler,
});
```

## Prompt Properties

| Property      | Type                | Description                   |
| ------------- | ------------------- | ----------------------------- |
| `name`        | `[]const u8`        | Unique prompt name            |
| `title`       | `?[]const u8`       | Human-readable title          |
| `description` | `?[]const u8`       | Description of the prompt     |
| `arguments`   | `?[]PromptArgument` | Expected arguments            |
| `handler`     | `*Handler`          | Function to generate messages |

## Handler Functions

```zig
fn promptHandler(
    _: ?*anyopaque,
    _: std.Io,
    allocator: std.mem.Allocator,
    args: ?std.json.Value,
) PromptError![]const PromptMessage;
```

### Example Handler

```zig
fn codeReviewHandler(
    _: ?*anyopaque,
    _: std.Io,
    allocator: std.mem.Allocator,
    args: ?std.json.Value,
) mcp.prompts.PromptError![]const mcp.prompts.PromptMessage {
    const code = mcp.prompts.getStringArg(args, "code") orelse {
        return error.InvalidArguments;
    };

    const language = mcp.prompts.getStringArg(args, "language") orelse "unknown";

    const system_prompt = try std.fmt.allocPrint(
        allocator,
        "You are a code reviewer. Review the following {s} code for best practices, bugs, and improvements.",
        .{language},
    );

    return &.{
        mcp.prompts.userMessage(system_prompt),
        mcp.prompts.userMessage(code),
    };
}
```

## Prompt Arguments

Define expected arguments:

```zig
try server.addPrompt(.{
    .name = "analyze",
    .description = "Analyze text for sentiment",
    .arguments = &.{
        .{ .name = "text", .description = "Text to analyze", .required = true },
        .{ .name = "language", .description = "Language of the text", .required = false },
    },
    .handler = analyzeHandler,
});
```

## Message Types

### User Message

```zig
mcp.prompts.userMessage("Analyze this text for me")
```

### Assistant Message

```zig
mcp.prompts.assistantMessage("I'll analyze the text...")
```

Only `user` and `assistant` roles are supported by `mcp.types.Role`.

## Using PromptBuilder

```zig
var builder = mcp.prompts.PromptBuilder.init("my_prompt");
defer builder.deinit(allocator);

_ = try builder.addArgument(allocator, "input", "The input text", true);
_ = try builder.addArgument(allocator, "style", "Output style", false);

const prompt = try builder
    .description("A helpful prompt")
    .handler(myHandler)
    .buildOwned(allocator);

try server.addPrompt(prompt);
```

`build()` borrows the builder's argument list, so the builder must outlive the
prompt. Use `buildOwned(allocator)` when the builder will be deinited before the
prompt is used.

## Complete Example

```zig
const std = @import("std");
const mcp = @import("mcp");

pub fn main(init: std.process.Init) void {
    run(init.io, init.gpa) catch |err| {
        mcp.reportError(err);
    };
}

fn run(io: std.Io, allocator: std.mem.Allocator) !void {
    var server: mcp.Server = .init(allocator, .{
        .name = "prompt-server",
        .version = "1.0.0",
    });
    defer server.deinit();

    // Simple prompt
    try server.addPrompt(.{
        .name = "explain",
        .description = "Explain a concept simply",
        .arguments = &.{
            .{ .name = "concept", .description = "The concept to explain", .required = true },
            .{ .name = "level", .description = "Expertise level (beginner/advanced)", .required = false },
        },
        .handler = explainHandler,
    });

    // Code generation prompt
    try server.addPrompt(.{
        .name = "generate_code",
        .description = "Generate code for a task",
        .arguments = &.{
            .{ .name = "task", .description = "What the code should do", .required = true },
            .{ .name = "language", .description = "Programming language", .required = true },
        },
        .handler = generateCodeHandler,
    });

    try server.run(io, allocator, .stdio);
}

fn explainHandler(
    _: ?*anyopaque,
    _: std.Io,
    allocator: std.mem.Allocator,
    args: ?std.json.Value,
) mcp.prompts.PromptError![]const mcp.prompts.PromptMessage {
    const concept = mcp.prompts.getStringArg(args, "concept") orelse {
        return error.InvalidArguments;
    };

    const level = mcp.prompts.getStringArg(args, "level") orelse "beginner";

    const prompt_text = try std.fmt.allocPrint(
        allocator,
        "Please explain '{s}' at a {s} level. Use simple examples and analogies.",
        .{ concept, level },
    );

    return &.{
        mcp.prompts.userMessage(prompt_text),
    };
}

fn generateCodeHandler(
    _: ?*anyopaque,
    _: std.Io,
    allocator: std.mem.Allocator,
    args: ?std.json.Value,
) mcp.prompts.PromptError![]const mcp.prompts.PromptMessage {
    const task = mcp.prompts.getStringArg(args, "task") orelse {
        return error.InvalidArguments;
    };

    const language = mcp.prompts.getStringArg(args, "language") orelse {
        return error.InvalidArguments;
    };

    const system = try std.fmt.allocPrint(
        allocator,
        "You are an expert {s} programmer. Generate clean, well-documented code.",
        .{language},
    );

    const user = try std.fmt.allocPrint(
        allocator,
        "Write {s} code to: {s}",
        .{ language, task },
    );

    return &.{
        mcp.prompts.userMessage(system),
        mcp.prompts.userMessage(user),
    };
}
```

## Next Steps

* [Transport Guide](/guide/transport) - Configure communication
* [Error Handling](/guide/error-handling) - Handle errors gracefully
* [Examples](/examples/) - See complete examples
