Skip to main content

prompt

Learn how to register a new prompt for your MCP server.

Prompts are another important MCP primitive that allows you to expose pre-written prompt templates to users. Unlike tools which are autonomously invoked by the LLM, prompts are explicitly selected by users to help structure their requests.

Prompts can include dynamic arguments that users can fill in, making them flexible templates for common workflows. They're particularly useful for guiding users towards best practices or providing structured starting points for complex tasks.

Basic API

You can register a prompt by invoking the prompt method on the server instance. The first argument is a configuration object and the second a handler that will be invoked whenever that prompt is requested by the MCP client.

		server.prompt(
	{
		name: 'your-prompt',
		description: 'A description for the user',
		title: 'Your Prompt',
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'text',
						text: 'Write a comprehensive test suite for the selected code',
					},
				},
			],
		};
	},
);
	

name and description are the only required properties (you can also specify a title for a human readable title but that's optional) of the configuration object. The return value of the handler must be an object with a messages property which is an array of one or more messages. Each message has a role (either "user" or "assistant") and content that can be text, images, audio, or embedded resources (you can refer to the MCP spec to know all possible content types).

Accepting arguments

Prompts become much more powerful when they can accept dynamic arguments from users. To accept arguments, you need to specify the schema of your expected input.

If you defined your adapter, accepting arguments is as simple as passing the schema property:

		server.prompt(
	{
		name: 'code-review',
		description: 'Generate a code review prompt for a specific file',
		title: 'Code Review',
		schema: v.object({
			filePath: v.string(),
			focusArea: v.optional(v.string()),
		}),
	},
	({ filePath, focusArea }) => {
		const focusText = focusArea
			? ` with special attention to ${focusArea}`
			: '';
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'text',
						text: `Please review the code in ${filePath}${focusText}. Provide constructive feedback on code quality, potential bugs, and improvements.`,
					},
				},
			],
		};
	},
);
	

Multi-message Prompts

Prompts can return multiple messages to create more complex conversation templates. This is useful for few-shot prompting or providing context through a conversation structure:

		server.prompt(
	{
		name: 'api-design-review',
		description: 'Get help designing a REST API with examples',
		title: 'API Design Review',
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'text',
						text: 'I need to design a REST API for a user management system',
					},
				},
				{
					role: 'assistant',
					content: {
						type: 'text',
						text: 'I can help you design that API. What operations do you need to support?',
					},
				},
				{
					role: 'user',
					content: {
						type: 'text',
						text: 'I need CRUD operations for users, plus authentication',
					},
				},
			],
		};
	},
);
	

Content Types

While text is the most common content type, prompts support various content types for multi-modal interactions:

Text Content

Standard text messages (shown in examples above):

		{
	type: 'text',
	text: 'Your text content here',
}
	

Image Content

Include visual context in prompts:

		server.prompt(
	{
		name: 'analyze-ui',
		description: 'Analyze a UI screenshot',
		title: 'UI Analysis',
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'image',
						data: 'base64-encoded-image-data',
						mimeType: 'image/png',
					},
				},
			],
		};
	},
);
	

Embedded Resources

Reference server-side resources directly in prompt messages:

		server.prompt(
	{
		name: 'review-with-docs',
		description: 'Code review with documentation context',
		title: 'Documented Code Review',
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'resource',
						resource: {
							uri: 'file:///docs/api-guidelines.md',
							mimeType: 'text/markdown',
							text: 'API Guidelines content...',
						},
					},
				},
			],
		};
	},
);
	

Audio Content

Include audio context in prompts:

		server.prompt(
	{
		name: 'transcribe-audio',
		description: 'Transcribe and analyze audio content',
		title: 'Audio Transcription',
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'audio',
						data: 'base64-encoded-audio-data',
						mimeType: 'audio/wav',
					},
				},
			],
		};
	},
);
	

Completions

One of the unique features of prompts is the ability to provide auto-completion suggestions for arguments. This helps users fill in the prompt arguments more quickly and with fewer errors.

You can specify completions for each argument using the complete property in the configuration object:

		server.prompt(
	{
		name: 'code-review',
		description: 'Generate a code review prompt for a specific file',
		title: 'Code Review',
		schema: v.object({
			filePath: v.string(),
			focusArea: v.string(),
		}),
		complete: {
			filePath: async (query, context) => {
				// Return completion suggestions based on the query
				const files = await listProjectFiles();
				return {
					completion: {
						values: files
							.filter((f) => f.includes(query))
							.map((file) => file),
					},
				};
			},
			focusArea: (query) => {
				return {
					completion: {
						values: [
							'performance',
							'security',
							'maintainability',
							'error handling',
							'testing',
						].filter((area) => area.includes(query.toLowerCase())),
					},
				};
			},
		},
	},
	({ filePath, focusArea }) => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'text',
						text: `Please review the code in ${filePath} with special attention to ${focusArea}.`,
					},
				},
			],
		};
	},
);
	

Each completion function receives the current query string and a context object containing the other arguments that have been filled in, allowing you to provide context-aware suggestions.

enabled function

One pattern that is quite common in every software is having a different feature-set based on some flag or the status of some user. You could technically create a new instance of the McpServer for each request and conditionally add a prompt but to facilitate the process tmcp exposes an enabled property on the configuration object. The property is a function that returns a boolean and, as you might have guessed, allows you to include a specific prompt in the list of prompts conditionally. Within the function you have access to the context so you can make decisions based on the client capabilities, the client info or even just reading a feature flag in the db to do A/B testing or to allow your admin to turn on or off a prompt without a re-deploy.

		server.prompt(
	{
		name: 'advanced-refactoring',
		description: 'Advanced code refactoring suggestions',
		title: 'Advanced Refactoring',
		enabled() {
			return server.ctx.sessionInfo?.clientInfo?.name !== 'basic-client';
		},
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'text',
						text: 'Analyze the selected code and suggest advanced refactoring techniques',
					},
				},
			],
		};
	},
);
	

Dynamic Properties with Getters

Sometimes you need properties that are computed dynamically at list-time rather than registration-time. For example, you might want to serve different descriptions based on which client is connected.

tmcp preserves JavaScript getters on the configuration object, allowing you to define properties that are evaluated each time the prompt is listed:

		server.prompt(
	{
		name: 'code-review',
		get description() {
			const client = server.ctx.sessionInfo?.clientInfo?.name;
			if (client === 'claude-code') {
				return 'Review code for bugs, security issues, and style - optimized for IDE integration';
			}
			return 'Review code for quality and best practices';
		},
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'text',
						text: 'Please review this code for quality and best practices',
					},
				},
			],
		};
	},
);
	

Icons

To allow the users to understand what an MCP server is about at a glance the MCP spec allows you to include a set of icons for each prompt. Obviously tmcp allows you to specify those too using the icons property of the configuration object.

		server.prompt(
	{
		name: 'code-review',
		description: 'Generate a code review prompt',
		title: 'Code Review',
		icons: [
			{
				src: 'https://dantemcp.com/review.png',
			},
			{
				src: 'data:image/png;base64,...',
			},
		],
	},
	() => {
		return {
			messages: [
				{
					role: 'user',
					content: {
						type: 'text',
						text: 'Please review this code for quality and best practices',
					},
				},
			],
		};
	},
);