Context
기계 번역
이 페이지는 영어 문서를 자동으로 번역한 것이며, 영어 페이지가 기준이 되는 정식 버전입니다. 어색하거나 잘못된 부분이 있다면 번역 페이지에서 제보하는 방법을 확인하세요.
도구의 인자는 모델이 채웁니다. 그 밖의 모든 것(지금 처리 중인 요청, 도구가 속한 서버, 클라이언트에 되돌려 말을 건넬 수단)은 단 하나의 객체, Context에서 옵니다.
직접 생성하지도, 설정하지도 않습니다. 달라고 하기만 하면 됩니다.
Context 받기
아무 도구에나 Context로 어노테이션한 매개변수를 추가하세요.
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
@mcp.tool()
def search_books(query: str, ctx: Context) -> str:
"""Search the catalog by title or author."""
return f"[request {ctx.request_id}] Found 3 books matching {query!r}."
- SDK는 요청마다 새
Context를 만들어 전달합니다. - 매개변수 이름은 중요하지 않습니다.
ctx,context,c무엇이든 SDK는 어노테이션으로 찾아냅니다. - 리소스와 프롬프트도 같은 방식으로 선언할 수 있습니다.
ctx.request_id는 함수가 바로 지금 처리하고 있는 요청의 ID입니다.
Info
FastAPI를 써 봤다면 익숙한 방식입니다. 프레임워크 고유의 타입(FastAPI에서는 Request, 여기서는 Context)으로 매개변수를 선언하면 프레임워크가 값을 채워 줍니다. 등록할 것도, 설정할 것도 없습니다. 타입 어노테이션이 메커니즘의 전부입니다.
모델에게 보이지 않는 매개변수
꼭 새겨 둘 부분입니다. 다음은 tools/list가 보고하는 search_books의 입력 스키마입니다.
{
"type": "object",
"properties": {
"query": {"title": "Query", "type": "string"}
},
"required": ["query"],
"title": "search_booksArguments"
}
속성은 하나뿐입니다. ctx는 인자가 아닙니다. 스키마에 나타나지 않고, 모델은 그 존재를 전혀 듣지 못하며, 어떤 클라이언트도 값을 채울 수 없습니다. 개발자와 SDK 사이의 약속일 뿐, 와이어 위에서는 보이지 않습니다.
직접 해 보기
MCP Inspector로 서버를 실행하세요.
uv run mcp dev server.py
search_books 폼에는 query 필드 하나만 있습니다. dune으로 호출해 보세요.
[request 3] Found 3 books matching 'dune'.
숫자는 이 호출이 우연히 몇 번째 요청이었는지에 따라 정해집니다. 도구를 다시 호출하면 숫자가 바뀝니다. 요청마다 고유한 Context를 받기 때문입니다.
Context가 제공하는 것
주입되는 객체는 작습니다. request_id 외에 다음이 있습니다.
await ctx.read_resource(uri): 도구 안에서 서버 자신의 리소스를 읽습니다. 다음 절에서 다룹니다.await ctx.report_progress(progress, total, message): 오래 걸리는 호출 중에 호출자에게 진행 상황을 스트리밍합니다. 자세한 내용은 진행 상황에서 확인하세요.await ctx.elicit(message, schema)와await ctx.elicit_url(...): 도구를 잠시 멈추고 사용자에게 질문합니다. 엘리시테이션(elicitation)에서 다룹니다.ctx.session: 이 클라이언트와 나누는 대화의 서버 쪽 끝입니다. 클라이언트로 보내는 알림이 여기에 있으며, 마지막 절에서 사용합니다.ctx.headers: 트랜스포트가 실어 온 요청 헤더이며, stdio에서는None입니다. 사용자 정의 헤더는(ctx.headers or {}).get("x-...")로 읽습니다. 헤더는 클라이언트가 제공하는 입력이므로 로캘이나 기능 플래그에는 괜찮지만, 신원으로는 절대 쓰면 안 됩니다.ctx.request_context: 요청별 원시 레코드입니다. 주로 찾게 될 필드는lifespan_context로, 시작 코드가 yield한 객체입니다(Lifespan 참고).
로깅은 일부러 이 목록에 넣지 않았습니다. 서버는 다른 Python 프로그램과 마찬가지로 Python의 logging 모듈로 로그를 남깁니다. 그 이유는 짧은 페이지 로깅에서 설명합니다.
Tip
주입은 등록한 함수에만 일어납니다. 도구가 호출하는 헬퍼 함수는 자체 Context를 받지 않으므로 ctx를 일반 인자로 넘겨주세요. 다른 곳에서 가져다 쓸 수 있는 전역 "현재 컨텍스트" 같은 것은 없습니다.
서버 자신의 리소스 읽기
서버의 리소스는 클라이언트만을 위한 것이 아닙니다. 도구도 읽을 수 있습니다.
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
@mcp.resource("catalog://genres")
def genres() -> str:
"""The genres the catalog is organised into."""
return "fiction, non-fiction, poetry"
@mcp.tool()
async def describe_catalog(ctx: Context) -> str:
"""Describe how the catalog is organised."""
[contents] = await ctx.read_resource("catalog://genres")
return f"The catalog is organised into: {contents.content}"
ctx.read_resource는 resources/read를 처리하는 것과 같은 레지스트리를 통해 URI를 해석하므로, 도구는 클라이언트가 받는 것과 똑같은 결과를 받습니다. 콘텐츠 블록마다 하나씩 담긴 ReadResourceContents의 이터러블입니다. 이 URI에는 하나가 있습니다.
contents.content # 'fiction, non-fiction, poetry'
contents.mime_type # 'text/plain'
content는genres()가 반환한 값 그대로입니다. 진실의 원천은 하나입니다. 클라이언트는 리소스를 둘러보고, 도구는 리소스를 사용하며, 누구도 문자열을 복사하지 않습니다.describe_catalog의 유일한 매개변수는Context이므로 입력 스키마에는 속성이 아예 없습니다. 모델이 호출할 때 넘기는 인자는{}입니다.
목록이 바뀌었음을 클라이언트에 알리기
서버가 제공하는 것은 임포트 시점에 고정되지 않습니다. 런타임에 도구를 등록한 다음 클라이언트에 알리세요.
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
def recommend_book(genre: str) -> str:
"""Recommend a book in the given genre."""
return f"In {genre}, try 'Dune'."
@mcp.tool()
async def enable_recommendations(ctx: Context) -> str:
"""Switch on the recommendation tool."""
mcp.add_tool(recommend_book)
await ctx.session.send_tool_list_changed()
return "Recommendations are now available."
mcp.add_tool(recommend_book)은 평범한 함수를 도구로 등록합니다. 이름, 설명, 스키마는@mcp.tool()을 썼을 때와 똑같이 도출됩니다.await ctx.session.send_tool_list_changed()는notifications/tools/list_changed를 보냅니다. 이를 받은 클라이언트는tools/list를 다시 호출하고recommend_book을 보게 됩니다.
형제 메서드로는 send_resource_list_changed(), send_prompt_list_changed(), 그리고 특정 리소스 하나의 변경을 알리는 send_resource_updated(uri)가 있습니다.
2026-07-28 연결에서 클라이언트는 직접 연 subscriptions/listen 스트림에서만 변경 알림을 받으므로, 위의 send_* 메서드는 그 스트림에 닿지 않습니다. Context의 발행 메서드는 구독 중인 모든 스트림에 한 번에 전달합니다. await ctx.notify_tools_changed(), await ctx.notify_prompts_changed(), await ctx.notify_resources_changed(), await ctx.notify_resource_updated(uri)입니다. 여러 복제본으로 확장하는 방법까지 포함한 자세한 내용은 구독에서 확인하세요.
Check
누군가 enable_recommendations를 실행하기 전까지는 약속한 도구가 존재하지 않습니다. 그래도 호출하면 모델이 읽을 수 있는 오류가 결과로 돌아옵니다.
Unknown tool: recommend_book
enable_recommendations를 실행하면 똑같은 호출이 성공합니다. 도구 목록은 진짜로 동적입니다. tools/list는 바로 지금 등록되어 있는 것을 반영합니다.
요약
- (도구, 리소스, 프롬프트에서) 매개변수에
Context어노테이션을 달면 SDK가 주입합니다. 이름은 마음대로 정하면 됩니다. - 모델에게는 보이지 않습니다. 입력 스키마에는 언제나 실제 인자만 들어갑니다.
ctx.request_id는 요청을 식별하고,ctx.request_context.lifespan_context는 시작 코드가 yield한 객체입니다.await ctx.read_resource(uri)로 도구가 서버 자신의 리소스를 읽을 수 있습니다.ctx.session은 클라이언트로 되돌아가는 채널입니다.send_tool_list_changed()와 형제 메서드는 바뀐 목록을 다시 가져오라고 클라이언트에 알립니다.- 진행 상황 보고와 엘리시테이션도
Context에서 시작하며, 각각 별도 페이지가 있습니다.
모델은 전혀 보지 못하고 직접 작성한 함수가 채우는 매개변수는 의존성입니다.