CPN 한국어 자습서 · Introduction to Model Context Protocol
3 · Connecting with MCP clients
Defining prompts
서버가 마지막으로 노출하는 프리미티브는 프롬프트입니다. 잘 평가·검증해 둔 고품질 지시문을 /format 같은 슬래시 명령으로 재사용합니다. @mcp.prompt 데코레이터로 정의하면, 함수가 메시지 리스트를 돌려주고 그대로 Claude에 전달됩니다.
Stephen Grider · Anthropic 기술 스태프
MCP 서버에서 다룰 마지막 핵심 영역은 프롬프트입니다. 리소스 때처럼, 작은 기능 하나를 프로젝트에 붙여 가며 프롬프트가 무엇인지 이해해 보겠습니다. 추가할 기능은 슬래시 명령 지원입니다. 예를 들어 format 명령을 만들 겁니다.
사용자가 슬래시(/)를 입력하면 앱이 지원하는 명령 목록을 보여 줍니다. 지금은 format 하나뿐입니다. 슬래시만 치면 자동완성으로 format이 뜨고, format을 고르면 그 뒤에 문서 ID(report.pdf 같은 문서명)를 넣으라고 안내받습니다. 그 명령을 실행하면, 목표는 Claude가 그 문서를 Markdown 문법으로 다시 써 주게 하는 것입니다.
지금 MCP 서버 안의 문서 내용은 특별한 서식 없는 평문입니다. 이 평문을 Claude에 넣어 Markdown으로 재작성시키려는 것이죠. 그러면 "문서 서식을 정리해 드리겠습니다" 같은 응답이 나오고, Claude는 도구로 문서 내용을 읽은 뒤, 최종 응답에 Markdown으로 다시 쓴 문서 내용을 보여 줍니다.
여기서 짚을 흥미로운 점이 있습니다. 이 기능의 진짜 목표 — 문서를 Markdown으로 재서식 — 는 사실 우리(개발자)가 코드를 새로 짜지 않아도 되는 작업입니다. 사용자는 이미 CLI에서 "report.pdf를 Markdown 문법으로 다시 써 줘"라고 말할 수 있고, Claude는 충분히 잘 해냅니다. 문제없이 동작합니다.
그렇다면 이 기능으로 우리가 진짜 하는 일은 무엇일까요? 사용자에게 그냥 맡겨 "이걸 Markdown으로 바꿔 줘"라고 손수 치게 하면 결과가 그럭저럭 나올 수 있습니다. 하지만 이 시나리오에 맞게 정교하게 다듬은 강력한 프롬프트가 있다면 훨씬 더 좋은 결과를 얻을 수 있습니다.
MCP 서버 작성자인 우리가 자리에 앉아, 문서를 Markdown으로 변환하는 이 작업을 위한 아주 꼼꼼하고 훌륭한 프롬프트를 쓰고, 테스트하고, 평가하는 전 과정을 거쳐 둔다면, 사용자는 그 프롬프트를 그냥 가져다 쓰는 것만으로 더 만족스러운 결과를 얻습니다. 그렇습니다 — 사용자가 직접 이 워크플로를 다 수행할 수도 있지만, 우리가 준비한 좋은 프롬프트를 쓰면 더 낫다는 것이 핵심입니다.
이것이 MCP 서버 안 프롬프트 기능의 진짜 목적입니다. 우리 서버가 특화된 작업(여기서는 문서 관리 — 읽기·수정 등)에 맞춰, 미리 잘 평가·검증한 고품질 프롬프트를 한 묶음 정의해 두고, CLI 같은 어떤 클라이언트 앱에서든 가져다 쓰게 노출하는 것입니다. 물론 이 프롬프트를 CLI 코드베이스에 직접 하드코딩할 수도 있지만, 서버가 노출해 두면 사람들이 미리 개발하는 수고 없이 바로 쓸 수 있습니다.
프롬프트를 정의하는 문법은 도구·리소스와 매우 비슷합니다. prompt 데코레이터를 쓰고, name과 (선택적으로) description을 붙입니다. 그리고 클라이언트가 이 프롬프트를 요청하면, 실제 user·assistant 메시지로 된 메시지 리스트를 돌려보냅니다. 이 메시지를 그대로 Claude에 보내면 됩니다.
서버 파일에서 "문서를 Markdown으로 재작성" TODO 자리를 지우고, mcp.prompt 데코레이터에 name="format", description="Rewrites the contents of the document in Markdown format."을 넣습니다. 구현 함수 format_document는 인자로 doc_id를 받고, 도구 때처럼 Field에 "Id of the document to format" 설명을 달고 str 타입 주석을 붙입니다. 반환은 메시지 리스트입니다.
이 base를 위해 파일 맨 위, 기존 MCP 서버 import 바로 아래에 from mcp.server.fastmcp.prompts import base를 추가합니다. 그리고 함수 안에는 미리 써 둔, 잘 평가된 프롬프트를 붙여 넣습니다. 이 프롬프트는 Claude에게 문서 ID를 받아 — 암묵적으로 read_document 도구로 그 내용을 가져오고 — Markdown 문법으로 다시 쓴 뒤, edit_document 도구로 수정 내용을 서버에 저장하라고 요청합니다. 마지막으로 base.UserMessage에 이 프롬프트를 담아 리스트로 반환합니다.
저장한 뒤 인스펙터를 띄워 테스트합니다. 서버에 연결하고 Prompts 섹션에서 List Prompts를 누르면 format 하나가 보입니다. format을 클릭하고 문서 ID로 outlook.pdf를 넣은 뒤 Get Prompt를 누르면, 미리 구성된 메시지 리스트가 돌아옵니다. 텍스트 파트에 전체 프롬프트가 들어 있고, 문서 ID가 그 안에 보간된 것을 확인할 수 있습니다. 이제 이 메시지를 Claude에 보내면 됩니다.
다시 한 번 정리하면, MCP 서버에 정의하는 프롬프트의 핵심은 — 잘 테스트되고 잘 평가되어, 하나의 특정 용도에 정교하게 특화된 지시문이라는 점입니다.
이 장에서 배우는 것What you'll learn
약 7분프롬프트 = /format 같은 슬래시 명령으로 쓰는 재사용 지시문
핵심 가치: 서버 작성자가 평가·검증한 고품질 프롬프트를 사용자에게 제공
@mcp.prompt(name, description) — 도구·리소스와 같은 패턴
from mcp.server.fastmcp.prompts import base
함수는 [base.UserMessage(...)] 즉 메시지 리스트를 반환
인스펙터 Prompts → Get Prompt → doc_id 보간 확인
name과 (선택) description을 받는다.mcp.server.fastmcp.prompts.base의 user 메시지 객체. 프롬프트 함수가 돌려줄 메시지를 만든다.doc_id 등이 프롬프트 본문에 끼워 넣어지는 것.프롬프트는 MCP 서버가 노출하는 세 번째 프리미티브입니다. 작은 기능 하나 — /format 슬래시 명령 — 을 붙여 가며 이해해 봅니다. 슬래시를 치면 명령 목록이 뜨고(지금은 format 하나), format을 고른 뒤 문서 ID를 지정하면 그 문서를 Markdown으로 다시 써 줍니다.
이 작업 자체는 사용자가 손수 시킬 수도 있습니다. 프롬프트의 가치는 서버 작성자가 미리 평가해 둔 좋은 지시문을 한 번의 명령으로 재사용하게 해 준다는 데 있습니다.
사실 사용자는 이미 "report.pdf를 Markdown으로 바꿔 줘"라고 직접 시킬 수 있습니다. 프롬프트의 진짜 목적은, 서버 작성자가 평가·검증한 고품질 지시문을 누구나 한 번의 명령으로 가져다 쓰게 하는 것입니다.
둘 다 문서를 Markdown으로 바꿉니다. 차이는 지시문의 품질입니다. 사용자가 즉석에서 친 한 줄보다, 서버 작성자가 테스트·평가까지 거쳐 다듬은 프롬프트가 더 일관되고 좋은 결과를 냅니다.
둘 다 같은 일을 합니다. 차이는 지시문의 품질입니다 — 그래서 서버가 잘 다듬은 프롬프트를 미리 노출해 둡니다.
문법은 도구·리소스와 같습니다. @mcp.prompt에 name과 description을 주고, 함수는 메시지 리스트를 반환합니다. 메시지 객체를 만들려면 먼저 base를 import 합니다.
from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp.prompts import base # 프롬프트 메시지용 from pydantic import Field mcp = FastMCP("documents")
이제 format_document를 정의합니다. doc_id를 Field로 받고, 미리 평가해 둔 프롬프트 본문에 그 ID를 보간한 뒤, base.UserMessage로 감싸 리스트로 돌려줍니다. 프롬프트는 Claude에게 read_document로 내용을 읽고 → Markdown으로 재작성 → edit_document로 저장까지 하도록 안내합니다.
@mcp.prompt( name="format", description="Rewrites the contents of the document in Markdown format.", ) def format_document( doc_id: str = Field(description="Id of the document to format"), ) -> list[base.Message]: prompt = f""" Your goal is to reformat a document to be written with markdown syntax. The id of the document you need to reformat is: <document_id> {doc_id} </document_id> Add in headers, bullet points, tables, etc as necessary. Feel free to add in extra text, but don't change the meaning of the report. Use the 'edit_document' tool to edit the document. After the document has been edited, respond with the edited contents. """ return [base.UserMessage(prompt)] # 메시지 리스트 반환
서버를 다시 띄워 인스펙터로 테스트합니다. Prompts → List Prompts에 format이 보이고, doc_id에 outlook.pdf를 넣고 Get Prompt를 누르면 ID가 보간된 메시지 리스트가 돌아옵니다.
Prompts → List Prompts
format — Rewrites the contents of the document in Markdown format.
format → doc_id: outlook.pdf → Get Prompt
{
"messages": [
{ "role": "user",
"content": { "type": "text",
"text": "... The id of the document ... outlook.pdf ..." } }
]
}/format 같은 슬래시 명령으로 쓰는 재사용 지시문. 가치는 미리 평가된 고품질이라는 점.@mcp.prompt(name, description) — 도구·리소스와 같은 데코레이터 패턴.from mcp.server.fastmcp.prompts import base 후, 함수는 [base.UserMessage(prompt)] 즉 메시지 리스트를 반환.doc_id)는 프롬프트 본문에 보간되어 메시지로 돌아온다.Q1MCP 프롬프트를 사용자에게 제공하는 진짜 이유는?
사용자도 직접 시킬 수 있습니다. 다만 잘 다듬은 프롬프트를 쓰면 결과가 더 좋아서, 서버가 미리 노출해 둡니다.
Q2format_document 함수가 반환하는 것은?
프롬프트 함수는 user·assistant 메시지로 된 리스트를 반환하고, 그대로 Claude에 전달됩니다.
Q3base 객체는 어디서 import 하나요?
프롬프트 메시지 객체(base.UserMessage 등)는 mcp.server.fastmcp.prompts.base에 있습니다.
서버에 프롬프트를 정의했습니다. 이제 클라이언트가 그 프롬프트를 목록으로 받고(list_prompts), 인자를 넣어 가져오도록(get_prompt) 구현합니다. → 클라이언트의 프롬프트