프롬프트

프롬프트 (Prompts)

프롬프트(prompt) 는 연결된 클라이언트가 이름으로 호출하는 메시지 템플릿이에요. 클라이언트는 프롬프트를 사람에게 직접 노출해요 — 슬래시 명령, 메뉴 항목 같은 것이죠. 반면 도구 는 모델이 고릅니다.

프롬프트 등록하기

registerPrompt 는 이름, 설정, 그리고 메시지를 돌려주는 콜백을 받아요. argsSchema 는 인자를 설명하는 Zod 객체 스키마입니다.

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' as const,
                content: { type: 'text' as const, text: `Review this code:\n\n${code}` }
            }
        ]
    })
);

prompts/list 가 이제 필수 인자 code 하나가 있는 review-code 를 광고해요.

::: tip .describe() 는 변환을 살아남아요. prompts/listcode 인자의 description 으로 The code to review 를 싣죠 — 클라이언트가 입력 필드 옆에 보여 주는 내용이에요. :::

v1에서 오셨나요?

registerPromptprompt() 를 대체해요 — codemod 를 실행한 뒤 업그레이드 가이드를 보세요.

이 페이지의 모든 호출은 위 서버에 연결된 메모리 안의 Client 에서 와요. 서버 테스트하기 가 그 연결을 보여 주고, 누군가 프롬프트를 고르면 MCP 호스트도 똑같이 합니다. getPrompt 로 가져와 볼게요.

const result = await client.getPrompt({ name: 'review-code', arguments: { code: 'let x = 1' } });
console.log(result.messages);

콜백의 메시지가 인자가 채워진 채로 돌아옵니다.

[
  {
    role: 'user',
    content: { type: 'text', text: 'Review this code:\n\nlet x = 1' }
  }
]

스키마로 인자 검증하기

필수 인자를 빼 보겠습니다.

import type { ProtocolError } from '@modelcontextprotocol/client';

try {
    await client.getPrompt({ name: 'review-code', arguments: {} });
} catch (error) {
    const { code, message } = error as ProtocolError;
    console.log(code, message);
}

SDK는 콜백이 실행되기 전에 요청을 거부해요.

-32602 Invalid arguments for prompt review-code: code: Invalid input: expected string, received undefined

실패한 프롬프트 검증은 프로토콜 오류예요 — getPrompt 는 코드 -32602(Invalid params)를 가진 ProtocolError 로 거부합니다. 반면 도구 인자 거부는 isError: true 결과로 돌아와요.

SDK는 이 하나의 스키마에서 prompts/list 가 광고하는 인자 목록을 만들고, 콜백이 실행되기 전에 prompts/get 인자를 검증하며, 콜백의 인자 타입을 추론합니다.

메시지 만들기

콜백은 { messages } 를 돌려줘요. 각 메시지는 role'user' 또는 'assistant' — 과 content 블록 하나를 이름으로 가집니다. user 메시지 뒤에 assistant 메시지를 붙이면 응답이 어떻게 시작할지를 미리 심어 놓을 수 있어요.

server.registerPrompt(
    'explain-error',
    {
        description: 'Explain a compiler error and suggest the smallest fix',
        argsSchema: z.object({ error: z.string() })
    },
    ({ error }) => ({
        messages: [
            {
                role: 'user' as const,
                content: { type: 'text' as const, text: `Explain this compiler error:\n\n${error}` }
            },
            {
                role: 'assistant' as const,
                content: { type: 'text' as const, text: 'The one-line cause:' }
            }
        ]
    })
);

호스트는 메시지를 순서대로 모델에 넘기므로, 마지막 assistant 메시지가 모델 응답의 시작점이 돼요. content 는 도구 결과와 같은 조합을 받습니다 — text, image, audio, resource_link, resource 가 그것이에요.

메시지에 이미지 추가하기

image 블록은 base64 datamimeType 을 싣고, 그것으로 무엇을 할지 말해 주는 text 블록과 짝을 이룹니다.

server.registerPrompt(
    'describe-image',
    {
        description: 'Describe an image for alt text',
        argsSchema: z.object({ imageBase64: z.string().describe('Base64-encoded PNG') })
    },
    ({ imageBase64 }) => ({
        messages: [
            {
                role: 'user' as const,
                content: { type: 'image' as const, data: imageBase64, mimeType: 'image/png' }
            },
            {
                role: 'user' as const,
                content: { type: 'text' as const, text: 'Write one sentence of alt text for this image.' }
            }
        ]
    })
);

prompts/get 은 이미지 블록을 첫 메시지로, 바이트를 그대로 둔 채 반환합니다.

{
  role: 'user',
  content: {
    type: 'image',
    data: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
    mimeType: 'image/png'
  }
}

audio 는 같은 모양을 받아요 — base64 datamimeType 을 더한 것이죠.

메시지에 리소스 내장하기

type: 'resource' 는 리소스의 내용을 메시지 안에 넣습니다. 리소스를 평소처럼 등록하고 — 리소스 참고 — 같은 uri, mimeType, text 를 프롬프트에 내장하면 돼요.

const styleGuide = '- Prefer const over let.\n- No single-letter identifiers.';

server.registerResource('style-guide', 'doc://style-guide', { mimeType: 'text/markdown' }, async uri => ({
    contents: [{ uri: uri.href, mimeType: 'text/markdown', text: styleGuide }]
}));

server.registerPrompt(
    'review-against-style',
    {
        description: 'Review code against the team style guide',
        argsSchema: z.object({ code: z.string() })
    },
    ({ code }) => ({
        messages: [
            {
                role: 'user' as const,
                content: {
                    type: 'resource' as const,
                    resource: { uri: 'doc://style-guide', mimeType: 'text/markdown', text: styleGuide }
                }
            },
            {
                role: 'user' as const,
                content: { type: 'text' as const, text: `Review this code against the style guide:\n\n${code}` }
            }
        ]
    })
);

prompts/get 은 스타일 가이드를 첫 메시지로 인라인 반환하므로, 클라이언트는 두 번째 resources/read 왕복을 하지 않아요.

{
  role: 'user',
  content: {
    type: 'resource',
    resource: {
      uri: 'doc://style-guide',
      mimeType: 'text/markdown',
      text: '- Prefer const over let.\n- No single-letter identifiers.'
    }
  }
}

uri 는 클라이언트에게 내장된 복사본이 어떤 등록된 리소스에서 왔는지 알려 줍니다.

인자 자동완성 제공하기

인자를 completable() 로 감싸면 클라이언트가 폼을 채우는 동안 값을 제안해 줍니다.

import { completable } from '@modelcontextprotocol/server';

server.registerPrompt(
    'translate',
    {
        description: 'Translate a snippet into another language',
        argsSchema: z.object({
            language: completable(z.string(), value =>
                ['typescript', 'python', 'rust', 'go'].filter(language => language.startsWith(value))
            ),
            code: z.string()
        })
    },
    ({ language, code }) => ({
        messages: [{ role: 'user' as const, content: { type: 'text' as const, text: `Translate to ${language}:\n\n${code}` } }]
    })
);

클라이언트는 지금까지 입력한 문자와 함께 completion/complete 를 보내고, SDK는 여러분의 함수를 실행해 매칭되는 값을 돌려줍니다. 완성 이 요청 흐름과 컨텍스트 인식 제안을 다루어요.

요약

  • registerPrompt(name, config, callback) 로 프롬프트를 등록하고, 클라이언트는 prompts/list 로 그것을 발견합니다.
  • argsSchema 는 Zod 객체 하나로, 광고되는 인자 목록·인자 검증·콜백의 인자 타입을 모두 담당해요.
  • 스키마에 어긋나는 인자는 prompts/get-32602 프로토콜 오류로 거부하고, 콜백은 실행되지 않아요.
  • 콜백은 { messages } 를 돌려주고, 각 메시지는 rolecontent 블록 하나를 이름으로 가집니다.
  • 메시지는 image(base64 data + mimeType)를 싣거나 type: 'resource' 로 등록된 리소스의 내용을 내장할 수 있어요.
  • completable() 이 인자별 자동완성을 더해 줍니다.