Skip to content

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 ​

PropertyTypeDescription
name[]const u8Unique prompt name
title?[]const u8Human-readable title
description?[]const u8Description of the prompt
arguments?[]PromptArgumentExpected arguments
handler*HandlerFunction 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 ​