Expose reusable, user-invoked prompt templates from an MCP server (with typed arguments, multi-message conversations, and embedded resource content) using the current TypeScript SDK API.
domain: github.com/modelcontextprotocol/typescript-sdk docs/servers/prompts.md · 10 steps · contributed by mcsoft-factory-desk
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗
Documented steps
Install as in the earlier routes: `npm install @modelcontextprotocol/server zod && npm pkg set type=module`.
Register a prompt with `registerPrompt(name, config, callback)`, where `config.argsSchema` is a Zod object schema describing the arguments: ```ts
import { McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
const server = new McpServer({ name: 'review', version: '1.0.0' });
server.registerPrompt(
'review-code',
{
title: 'Code Review',
description: 'Review code for best practices and potential issues',
argsSchema: z.object({ code: z.string().describe('The code to review') })
},
({ code }) => ({
messages: [{ role: 'user', content: { type: 'text', text: `Review this code:\n\n${code}` } }]
})
);
```
`.describe()` on a Zod field survives into the wire-level `prompts/list` entry as that argument's `description`; a field with no default is required, matching what a client shows in its prompt-picker UI.
The callback returns `{ messages: [...] }`; each message has a `role` (`'user'` or `'assistant'`) and one `content` block (`text`, `image`, `audio`, `resource_link`, or `resource`). Return multiple messages, ending with an `assistant` message, to pre-seed the start of the model's reply, e.g. an `explain-error` prompt that ends with `{ role: 'assistant', content: { type: 'text', text: 'The one-line cause:' } }`.
Embed a previously registered resource's contents directly in a message so the client skips a second `resources/read` round trip: `content: { type: 'resource', resource: { uri: 'doc://style-guide', mimeType: 'text/markdown', text: styleGuide } }` — the `uri` still points at the registered resource.
Add per-argument autocompletion by wrapping a field with `completable()` from `@modelcontextprotocol/server`: `language: completable(z.string(), value => ['typescript','python','rust','go'].filter(l => l.startsWith(value)))`; the client's `completion/complete` request runs your function and returns matching suggestions.
Know the validation contract: a missing/invalid required argument causes `prompts/get` itself to reject with protocol error code `-32602` ('Invalid params') before your callback runs — this is different from a tool's `isError: true` result, because no model is in the loop to see and retry from a normal result.
Fetch/test a prompt: `await client.getPrompt({ name: 'review-code', arguments: { code: 'let x = 1' } })`, or interactively via `npx @modelcontextprotocol/inspector npx tsx src/index.ts` → Prompts tab → fill the form → Get.
Python-SDK equivalent for reference: `@mcp.prompt()` on a function makes it a prompt; returning a `str` becomes one user message, returning `list[Message]` built from `UserMessage`/`AssistantMessage` (imported from `mcp.server.mcpserver.prompts.base`) seeds a multi-turn conversation; `Annotated[str, Field(description=...)]` documents each argument the same way it does for tools.
`registerPrompt` replaced the v1 TypeScript SDK's `prompt()` method — existing v1 servers need the SDK's codemod plus the upgrade guide (docs/migration/upgrade-to-v2.md) to move to v2's API.
Prompt arguments are a flat list of named strings advertised in `prompts/list` (no JSON Schema, unlike tools) — Zod's `argsSchema` is only used server-side to validate and type the handler's input, not sent to the client as a schema.
A failed argument validation makes the whole `prompts/get` call reject with a protocol-level `-32602` error (TypeScript) — there is no per-prompt error result a model can inspect and retry, unlike a tool call. In the Python SDK the analogous failure surfaces as an internal `MCPError` (code -32603) with the real reason only in the server log.
The Python SDK has two distinct import paths — `from mcp.server import MCPServer` for building servers and `from mcp import Client` for the client half — there is no single `from mcp import MCPServer`.
`completable()` only adds autocompletion to the specific Zod field it wraps; unwrapped `argsSchema` fields get no `completion/complete` suggestions even though the capability is advertised for the prompt as a whole.
Give your agent this knowledge — and 17,400+ more routes
One MCP install gives any agent live access to the full route map across 6,000+ domains, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp
Need this verified for your stack — or a route we don't have yet?