재사용 가능한 프롬프트 템플릿과 워크플로우 생성하기
프롬프트는 서버가 사용자와 LLM에게 쉽게 제공할 수 있는 재사용 가능한 프롬프트 템플릿과 워크플로우를 정의할 수 있게 합니다. 이를 통해 일반적인 LLM 상호작용을 표준화하고 공유할 수 있는 강력한 방법을 제공합니다.
프롬프트는 사용자 제어(user-controlled)가 되도록 설계되었습니다. 이는 사용자가 명시적으로 선택하여 사용할 수 있도록 서버에서 클라이언트로 노출된다는 의미입니다.
개요
MCP의 프롬프트는 다음과 같은 기능을 가진 사전 정의된 템플릿입니다:
- 동적 인자 허용
- 리소스의 컨텍스트 포함
- 여러 상호작용 연결
- 특정 워크플로우 안내
- UI 요소로 표시(슬래시 명령어와 같은)
프롬프트 구조
각 프롬프트는 다음과 같이 정의됩니다:
{
name: string; // 프롬프트의 고유 식별자
description?: string; // 사람이 읽을 수 있는 설명
arguments?: [ // 선택적 인자 목록
{
name: string; // 인자 식별자
description?: string; // 인자 설명
required?: boolean; // 인자가 필수인지 여부
}
]
}
프롬프트 검색
클라이언트는 prompts/list
엔드포인트를 통해 사용 가능한 프롬프트를 검색할 수 있습니다:
// 요청
{
method: "prompts/list"
}
// 응답
{
prompts: [
{
name: "analyze-code",
description: "코드의 잠재적 개선 사항 분석",
arguments: [
{
name: "language",
description: "프로그래밍 언어",
required: true
}
]
}
]
}
프롬프트 사용
프롬프트를 사용하려면 클라이언트가 prompts/get
요청을 합니다:
// 요청
{
method: "prompts/get",
params: {
name: "analyze-code",
arguments: {
language: "python"
}
}
}
// 응답
{
description: "Python 코드의 잠재적 개선 사항 분석",
messages: [
{
role: "user",
content: {
type: "text",
text: "다음 Python 코드의 잠재적 개선 사항을 분석해 주세요:\n\n```python\ndef calculate_sum(numbers):\n total = 0\n for num in numbers:\n total = total + num\n return total\n\nresult = calculate_sum([1, 2, 3, 4, 5])\nprint(result)\n```"
}
}
]
}
동적 프롬프트
프롬프트는 동적일 수 있으며 다음을 포함할 수 있습니다:
내장 리소스 컨텍스트
{
"name": "analyze-project",
"description": "프로젝트 로그와 코드 분석",
"arguments": [
{
"name": "timeframe",
"description": "로그를 분석할 시간 범위",
"required": true
},
{
"name": "fileUri",
"description": "검토할 코드 파일의 URI",
"required": true
}
]
}
prompts/get
요청을 처리할 때:
{
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "이 시스템 로그와 코드 파일을 분석하여 문제를 찾아보세요:"
}
},
{
"role": "user",
"content": {
"type": "resource",
"resource": {
"uri": "logs://recent?timeframe=1h",
"text": "[2024-03-14 15:32:11] ERROR: Connection timeout in network.py:127\n[2024-03-14 15:32:15] WARN: Retrying connection (attempt 2/3)\n[2024-03-14 15:32:20] ERROR: Max retries exceeded",
"mimeType": "text/plain"
}
}
},
{
"role": "user",
"content": {
"type": "resource",
"resource": {
"uri": "file:///path/to/code.py",
"text": "def connect_to_service(timeout=30):\n retries = 3\n for attempt in range(retries):\n try:\n return establish_connection(timeout)\n except TimeoutError:\n if attempt == retries - 1:\n raise\n time.sleep(5)\n\ndef establish_connection(timeout):\n # Connection implementation\n pass",
"mimeType": "text/x-python"
}
}
}
]
}
다단계 워크플로우
const debugWorkflow = {
name: "debug-error",
async getMessages(error: string) {
return [
{
role: "user",
content: {
type: "text",
text: `내가 보고 있는 오류는 다음과 같습니다: ${error}`
}
},
{
role: "assistant",
content: {
type: "text",
text: "이 오류를 분석하는 데 도움을 드리겠습니다. 지금까지 어떤 시도를 해보셨나요?"
}
},
{
role: "user",
content: {
type: "text",
text: "서비스를 재시작해 보았지만 오류가 계속됩니다."
}
}
];
}
};
구현 예시
다음은 MCP 서버에서 프롬프트를 구현하는 전체 예시입니다:
- TypeScript
- Python
import { Server } from "@modelcontextprotocol/sdk/server";
import {
ListPromptsRequestSchema,
GetPromptRequestSchema
} from "@modelcontextprotocol/sdk/types";
const PROMPTS = {
"git-commit": {
name: "git-commit",
description: "Git 커밋 메시지 생성",
arguments: [
{
name: "changes",
description: "Git diff 또는 변경 사항 설명",
required: true
}
]
},
"explain-code": {
name: "explain-code",
description: "코드 작동 방식 설명",
arguments: [
{
name: "code",
description: "설명할 코드",
required: true
},
{
name: "language",
description: "프로그래밍 언어",
required: false
}
]
}
};
const server = new Server({
name: "example-prompts-server",
version: "1.0.0"
}, {
capabilities: {
prompts: {}
}
});
// 사용 가능한 프롬프트 나열
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: Object.values(PROMPTS)
};
});
// 특정 프롬프트 가져오기
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const prompt = PROMPTS[request.params.name];
if (!prompt) {
throw new Error(`프롬프트를 찾을 수 없습니다: ${request.params.name}`);
}
if (request.params.name === "git-commit") {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `다음 변경 사항에 대한 간결하면서도 설명적인 커밋 메시지를 생성해 주세요:\n\n${request.params.arguments?.changes}`
}
}
]
};
}
if (request.params.name === "explain-code") {
const language = request.params.arguments?.language || "Unknown";
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `이 ${language} 코드가 어떻게 작동하는지 설명해 주세요:\n\n${request.params.arguments?.code}`
}
}
]
};
}
throw new Error("프롬프트 구현을 찾을 수 없습니다");
});
from mcp.server import Server
import mcp.types as types
# 사용 가능한 프롬프트 정의
PROMPTS = {
"git-commit": types.Prompt(
name="git-commit",
description="Git 커밋 메시지 생성",
arguments=[
types.PromptArgument(
name="changes",
description="Git diff 또는 변경 사항 설명",
required=True
)
],
),
"explain-code": types.Prompt(
name="explain-code",
description="코드 작동 방식 설명",
arguments=[
types.PromptArgument(
name="code",
description="설명할 코드",
required=True
),
types.PromptArgument(
name="language",
description="프로그래밍 언어",
required=False
)
],
)
}
# 서버 초기화
app = Server("example-prompts-server")
@app.list_prompts()
async def list_prompts() -> list[types.Prompt]:
return list(PROMPTS.values())
@app.get_prompt()
async def get_prompt(
name: str, arguments: dict[str, str] | None = None
) -> types.GetPromptResult:
if name not in PROMPTS:
raise ValueError(f"프롬프트를 찾을 수 없습니다: {name}")
if name == "git-commit":
changes = arguments.get("changes") if arguments else ""
return types.GetPromptResult(
messages=[
types.PromptMessage(
role="user",
content=types.TextContent(
type="text",
text=f"다음 변경 사항에 대한 간결하면서도 설명적인 커밋 메시지를 "
f"생성해 주세요:\n\n{changes}"
)
)
]
)
if name == "explain-code":
code = arguments.get("code") if arguments else ""
language = arguments.get("language", "Unknown") if arguments else "Unknown"
return types.GetPromptResult(
messages=[
types.PromptMessage(
role="user",
content=types.TextContent(
type="text",
text=f"이 {language} 코드가 어떻게 작동하는지 설명해 주세요:\n\n{code}"
)
)
]
)
raise ValueError("프롬프트 구현을 찾을 수 없습니다")
모범 사례
프롬프트를 구현할 때:
- 명확하고 설명적인 프롬프트 이름 사용
- 프롬프트와 인자에 대한 상세한 설명 제공
- 모든 필수 인자 검증
- 누락된 인자를 우아하게 처리
- 프롬프트 템플릿의 버전 관리 고려
- 적절한 경우 동적 콘텐츠 캐싱
- 오류 처리 구현
- 예상 인자 형식 문서화
- 프롬프트 조합 가능성 고려
- 다양한 입력으로 프롬프트 테스트
UI 통합
프롬프트는 클라이언트 UI에 다음과 같이 표시될 수 있습니다:
- 슬래시 명령어
- 빠른 작업
- 컨텍스트 메뉴 항목
- 명령 팔레트 항목
- 안내형 워크플로우
- 대화형 양식
업데이트 및 변경
서버는 프롬프트 변경에 대해 클라이언트에 알릴 수 있습니다:
- 서버 기능:
prompts.listChanged
- 알림:
notifications/prompts/list_changed
- 클라이언트가 프롬프트 목록을 다시 가져옴
보안 고려사항
프롬프트를 구현할 때:
- 모든 인자 검증
- 사용자 입력 정제
- 속도 제한 고려
- 접근 제어 구현
- 프롬프트 사용 감사
- 민감한 데이터 적절하게 처리
- 생성된 콘텐츠 검증
- 타임아웃 구현
- 프롬프트 인젝션 위험 고려
- 보안 요구사항 문서화
반응형