MCP
MCP (Model Context Protocol)
에이전트에 외부 도구를 연결할 때 가장 흔히 쓰는 표준이 바로 MCP예요. 이 페이지에서는 Agents SDK가 지원하는 여러 MCP 전송(transport) 방식과, 각각 어떤 상황에 고르면 좋은지, 서버별 공통 설정까지 정리해서 설명해 드릴게요.
출처: 문서
본문
MCP(Model Context Protocol)는 애플리케이션이 언어 모델에 도구와 컨텍스트를 노출하는 방식을 표준화해요. 공식 문서에서는 이렇게 설명해요:
MCP는 애플리케이션이 LLM에 컨텍스트를 제공하는 방식을 표준화하는 오픈 프로토콜입니다. MCP를 AI 애플리케이션을 위한 USB-C 포트라고 생각하면 돼요. USB-C가 기기를 다양한 주변기기와 액세서리에 연결하는 표준 방식을 제공하듯, MCP는 AI 모델을 다양한 데이터 소스와 도구에 연결하는 표준 방식을 제공합니다.
Agents Python SDK는 여러 MCP 전송 방식을 이해해요. 덕분에 기존 MCP 서버를 재사용하거나, 직접 만들어서 파일시스템·HTTP·커넥터 기반 도구를 에이전트에 노출할 수 있어요.
MCP 서버에 연결하기 전에 반드시 신뢰를 확인하세요. MCP 도구는 모델 컨텍스트의 데이터를 노출할 수 있고, 여러분이 제공한 자격 증명으로 작업을 수행할 수 있어요. 신뢰하는 서버에만 연결하고, 최소 권한 자격 증명을 쓰고, 액세스 토큰은 URL이 아니라 authorization 필드나 헤더에 두고, 민감한 작업에는 승인을 요구하세요. 자세한 내용은 OpenAI MCP 보안 가이드를 참고하세요.
MCP 통합 방식 고르기
MCP 서버를 에이전트에 연결하기 전에, 도구 호출이 어디에서 실행될지 그리고 어떤 전송 방식에 도달할 수 있는지를 먼저 정해야 해요. 아래 표는 Python SDK가 지원하는 옵션을 정리한 거예요.
| 필요한 것 | 권장 옵션 |
|---|---|
| OpenAI의 Responses API가 공개적으로 도달 가능한 MCP 서버를 모델 대신 호출 | HostedMCPTool를 통한 호스팅 MCP 서버 도구 |
| 로컬 또는 원격으로 실행하는 Streamable HTTP 서버 연결 | MCPServerStreamableHttp를 통한 Streamable HTTP MCP 서버 |
| Server-Sent Events로 HTTP를 구현한 서버 | MCPServerSse를 통한 HTTP+SSE MCP 서버 |
| 로컬 프로세스를 실행하고 stdin/stdout으로 통신 | MCPServerStdio를 통한 stdio MCP 서버 |
아래에서 각 옵션을 어떻게 구성하는지, 그리고 어떤 전송 방식을 언제 선호하면 좋은지 하나씩 살펴볼게요.
MCP Python SDK v1과 v2
Agents SDK는 mcp Python 패키지의 두 주요 버전을 모두 지원해요. 의존성 범위는 mcp>=1.19.0,<3이에요. 설치된 mcp 패키지 버전은 서버와 협상하는 MCP 프로토콜 버전과는 별개예요. Agents SDK는 설치된 패키지의 major 버전을 감지해서 stdio, SSE, Streamable HTTP 연결을 자동으로 맞추므로, 일반적인 서버 구성에서는 버전을 바꿔줄 필요가 없어요.
MCP Python SDK v2가 설치되면 Agents SDK는 구성된 로컬 전송 주변에 mode="auto"인 v2 mcp.Client를 만들어요. 클라이언트는 먼저 설치된 MCP SDK가 지원하는 최신 프로토콜 버전으로 server/discover 프로브를 보내요. 최신 서버는 프로브에 응답하고, 클라이언트는 그 결과를 채택해요. server/discover를 지원하지 않는 오래된 서버라면 클라이언트는 레거시 initialize 핸드셰이크로 폴백해서 거기서 협상된 프로토콜 버전을 사용해요. 따라서 MCP Python SDK v2를 설치한다고 해서 모든 연결이 최신 MCP 프로토콜 버전을 쓰게 되는 건 아니에요. 자세한 내용은 MCP Python SDK의 프로토콜 버전 협상 가이드를 참고하세요.
대부분의 애플리케이션은 의존성 해석기가 호환 버전을 고르도록 두는 게 좋아요. 애플리케이션이 특정 major 버전에 머물러야 한다면 openai-agents와 함께 명시적 제약을 추가하면 돼요:
# MCP Python SDK v1
pip install "mcp>=1.19.0,<2"
# MCP Python SDK v2
pip install "mcp>=2,<3"
HTTP 전송 커스터마이제이션은 설치된 MCP 패키지가 소유한 HTTP 스택을 사용해야 해요:
| 커스터마이제이션 | MCP Python SDK v1 | MCP Python SDK v2 |
|---|---|---|
params["auth"] |
httpx.Auth |
httpx2.Auth |
params["httpx_client_factory"] 반환값 |
httpx.AsyncClient |
httpx2.AsyncClient |
MCPServerStreamableHttp의 params["ignore_initialized_notification_failure"] = True |
지원됨 | 미지원. 연결 전에 거부됨 |
가능하면 아래 Streamable HTTP 예시처럼 Authorization 헤더를 쓰세요. Authorization 헤더는 두 패키지 버전 모두에서 그대로 동작해요. 애플리케이션이 params["auth"]나 params["httpx_client_factory"]를 제공할 때는 그 값들이 설치된 mcp 패키지 major 버전의 HTTP 타입을 사용해야 해요. MCPServerStreamableHttp의 params["ignore_initialized_notification_failure"] = True를 설정한다면, 업그레이드 전에 mcp<2를 유지하거나 해당 옵션을 꺼야 해요.
이런 로컬 mcp 의존성 요구사항은 HostedMCPTool에는 적용되지 않아요. 왜냐하면 원격 MCP 연결 자체를 OpenAI Responses API가 소유하기 때문이에요.
에이전트 수준 MCP 구성
전송 방식을 고르는 것 외에도, Agent.mcp_config로 MCP 도구가 준비되는 방식을 조정할 수 있어요.
from agents import Agent
agent = Agent(
name="Assistant",
mcp_servers=[server],
mcp_config={
# MCP 도구 스키마를 strict JSON schema로 변환하려 시도합니다.
"convert_schemas_to_strict": True,
# None이면 MCP 도구 실패가 모델에 보이는 오류 텍스트를
# 반환하는 대신 예외로 발생합니다.
"failure_error_function": None,
# 로컬 MCP 도구 이름 앞에 서버 이름을 붙입니다.
"include_server_in_tool_names": True,
},
)
참고 사항이에요.
convert_schemas_to_strict는 최선을 다하는(best-effort) 방식이에요. 스키마를 변환할 수 없으면 원래 스키마를 사용해요.failure_error_function은 MCP 도구 호출 실패가 모델에 어떻게 표면화되는지를 제어해요.failure_error_function을 설정하지 않으면 SDK는 기본 도구 오류 포매터를 사용해요.- 서버 수준의
failure_error_function은 해당 서버에 대해Agent.mcp_config["failure_error_function"]를 덮어써요. include_server_in_tool_names은 선택(opt-in) 항목이에요. 켜면 각 로컬 MCP 도구가 결정적인 서버-접두사 이름으로 모델에 노출돼서, 여러 MCP 서버가 같은 이름의 도구를 게시할 때 충돌을 피하는 데 도움이 돼요. 생성된 이름은 ASCII 안전하고,FunctionTool인스턴스의 이름 길이 제한 안에 있으며, 같은 에이전트의 로컬FunctionTool인스턴스나 활성화된 handoff의 구성된 이름과 충돌하지 않아요. SDK는 여전히 원래 서버에서 원래 MCP 도구 이름을 호출해요.
전송 공통 패턴
전송을 선택하고 나면 대부분의 통합은 같은 후속 결정을 필요로 해요:
- 도구의 일부만 노출하는 방법 (도구 필터링)
- 서버가 재사용 가능한 프롬프트도 제공하는지 (프롬프트)
list_tools()를 캐시할지 (캐싱)- MCP 활동이 트레이스에 어떻게 나타나는지 (트레이싱)
로컬 MCP 서버(MCPServerStdio, MCPServerSse, MCPServerStreamableHttp)에서는 승인 정책과 호출별 _meta 페이로드도 공통 개념이에요. Streamable HTTP 절이 가장 완전한 예시를 보여주고, 같은 패턴이 다른 로컬 전송에도 적용돼요.
1. 호스팅 MCP 서버 도구
호스팅 도구는 전체 도구 왕복(round-trip)을 OpenAI 인프라로 옮겨요. 코드가 도구를 나열하고 호출하는 대신, HostedMCPTool이 서버 라벨(및 선택적 커넥터 메타데이터)을 Responses API에 전달해요. 그러면 모델이 원격 서버의 도구를 나열하고, 여러분의 Python 프로세스로 되돌아오는 추가 콜백 없이 호출해요. 호스팅 도구는 현재 Responses API의 호스팅 MCP 통합을 지원하는 OpenAI 모델에서 동작해요.
기본 호스팅 MCP 도구
에이전트의 tools 목록에 HostedMCPTool을 추가하면 호스팅 도구가 만들어져요. tool_config 딕셔너리는 REST API에 보낼 JSON과 동일해요:
import asyncio
from agents import Agent, HostedMCPTool, Runner
async def main() -> None:
agent = Agent(
name="Assistant",
instructions="Use the DeepWiki hosted MCP server to inspect openai/openai-agents-python.",
tools=[
HostedMCPTool(
tool_config={
"type": "mcp",
"server_label": "deepwiki",
"server_url": "https://mcp.deepwiki.com/mcp",
"require_approval": "never",
}
)
],
)
result = await Runner.run(
agent,
"Which language is the repository openai/openai-agents-python written in?",
)
print(result.final_output)
asyncio.run(main())
호스팅 서버는 자동으로 도구를 노출해요. mcp_servers에 추가할 필요가 없어요.
호스팅 도구 검색이 호스팅 MCP 서버를 지연(lazily) 로드하길 원한다면 tool_config["defer_loading"] = True로 설정하고 에이전트에 ToolSearchTool을 추가하세요. 이것은 OpenAI Responses 모델에서만 지원돼요. 완전한 도구 검색 설정과 제약은 도구 문서를 참고하세요.
호스팅 MCP 결과 스트리밍
호스팅 도구는 function tool과 정확히 같은 방식으로 결과 스트리밍을 지원해요. Runner.run_streamed를 사용해서 모델이 아직 작업하는 동안 증분 MCP 출력을 소비하면 돼요:
result = Runner.run_streamed(agent, "Summarise this repository's top languages")
async for event in result.stream_events():
if event.type == "run_item_stream_event":
print(f"Received: {event.item}")
print(result.final_output)
선택적 승인 흐름
서버가 민감한 작업을 수행할 수 있다면 각 도구 실행 전에 사람 또는 프로그래밍 방식의 승인을 요구할 수 있어요. tool_config에서 require_approval을 단일 정책("always", "never")으로, 또는 도구 이름을 정책에 매핑하는 딕셔너리로 구성하세요. 결정을 Python 안에서 내리려면 on_approval_request 콜백을 제공하면 돼요.
from agents import MCPToolApprovalFunctionResult, MCPToolApprovalRequest
SAFE_TOOLS = {"read_wiki_structure", "read_wiki_contents", "ask_question"}
def approve_tool(request: MCPToolApprovalRequest) -> MCPToolApprovalFunctionResult:
if request.data.name in SAFE_TOOLS:
return {"approve": True}
return {"approve": False, "reason": "Escalate to a human reviewer"}
agent = Agent(
name="Assistant",
tools=[
HostedMCPTool(
tool_config={
"type": "mcp",
"server_label": "deepwiki",
"server_url": "https://mcp.deepwiki.com/mcp",
"require_approval": "always",
},
on_approval_request=approve_tool,
)
],
)
콜백은 동기 또는 비동기일 수 있고, 모델이 계속 실행하기 위해 승인 데이터가 필요할 때마다 호출돼요.
커넥터 기반 호스팅 서버
호스팅 MCP는 OpenAI 커넥터도 지원해요. server_url 대신 connector_id와 액세스 토큰을 제공하면 돼요. Responses API가 인증을 처리하고, 호스팅 서버가 커넥터의 도구를 노출해요.
import os
HostedMCPTool(
tool_config={
"type": "mcp",
"server_label": "google_calendar",
"connector_id": "connector_googlecalendar",
"authorization": os.environ["GOOGLE_CALENDAR_AUTHORIZATION"],
"require_approval": "never",
}
)
완전히 동작하는 호스팅 도구 샘플(스트리밍, 승인, 커넥터 포함)은 examples/hosted_mcp에 있어요.
2. Streamable HTTP MCP 서버
네트워크 연결을 직접 관리하고 싶다면 MCPServerStreamableHttp를 사용해요. Streamable HTTP 서버는 전송을 직접 제어하거나, 지연을 낮게 유지하면서 자체 인프라 안에서 서버를 실행하고 싶을 때 이상적이에요.
import asyncio
import os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
from agents.model_settings import ModelSettings
async def main() -> None:
token = os.environ["MCP_SERVER_TOKEN"]
async with MCPServerStreamableHttp(
name="Streamable HTTP Python Server",
params={
"url": "http://localhost:8000/mcp",
"headers": {"Authorization": f"Bearer {token}"},
"timeout": 10,
},
cache_tools_list=True,
max_retry_attempts=3,
) as server:
agent = Agent(
name="Assistant",
instructions="Use the MCP tools to answer the questions.",
mcp_servers=[server],
model_settings=ModelSettings(tool_choice="required"),
)
result = await Runner.run(agent, "Add 7 and 22.")
print(result.final_output)
asyncio.run(main())
생성자는 추가 옵션을 받아요:
client_session_timeout_seconds는 MCP ClientSession 읽기 타임아웃을 제어해요.datetime.timedelta로 표현 가능한 양의 유한 값으로 최소 1마이크로초 이상이면 유한 타임아웃을 설정하고,None과0은 비활성화해요. 다른 값은 서버가 생성될 때 거부돼요.use_structured_content는tool_result.structured_content를 텍스트 출력보다 선호할지 토글해요.max_retry_attempts와retry_backoff_seconds_base는list_tools()와call_tool()에 자동 재시도를 추가해요.tool_filter는 도구의 일부만 노출하게 해줘요 (도구 필터링 참고).require_approval은 로컬 MCP 도구에 human-in-the-loop 승인 정책을 활성화해요.failure_error_function은 모델에 보이는 MCP 도구 실패 메시지를 커스터마이즈해요.None으로 설정하면 대신 오류를 발생시켜요.tool_meta_resolver는call_tool()전에 호출별 MCP_meta페이로드를 주입해요.
로컬 MCP 서버의 승인 정책
MCPServerStdio, MCPServerSse, MCPServerStreamableHttp는 모두 require_approval을 받아요.
지원되는 형태:
- 모든 도구에 대해
"always"또는"never". True는 모든 도구에 승인을 요구하고,False는 어떤 도구에도 요구하지 않아요 ("always","never"와 각각 동일).- 도구별 매핑, 예를 들어
{"delete_file": "always", "read_file": "never"}. - 그룹 객체:
{"always": {"tool_names": [...]}, "never": {"tool_names": [...]}}.
async with MCPServerStreamableHttp(
name="Filesystem MCP",
params={"url": "http://localhost:8000/mcp"},
require_approval={"always": {"tool_names": ["delete_file"]}},
) as server:
...
완전한 일시정지/재개 흐름은 Human-in-the-loop와 examples/mcp/get_all_mcp_tools_example/main.py를 참고하세요.
tool_meta_resolver로 호출별 메타데이터
MCP 서버가 _meta에서 요청 메타데이터(예: 테넌트 ID나 트레이스 컨텍스트)를 기대한다면 tool_meta_resolver를 사용하면 돼요. 아래 예시는 Runner.run(...)에 context로 dict를 전달한다고 가정해요.
from agents.mcp import MCPServerStreamableHttp, MCPToolMetaContext
def resolve_meta(context: MCPToolMetaContext) -> dict[str, str] | None:
run_context_data = context.run_context.context or {}
tenant_id = run_context_data.get("tenant_id")
if tenant_id is None:
return None
return {"tenant_id": str(tenant_id), "source": "agents-sdk"}
server = MCPServerStreamableHttp(
name="Metadata-aware MCP",
params={"url": "http://localhost:8000/mcp"},
tool_meta_resolver=resolve_meta,
)
런 컨텍스트가 Pydantic 모델, dataclass, 또는 커스텀 클래스라면 대신 속성 접근으로 테넌트 ID를 읽으면 돼요.
MCP 도구 출력: 텍스트, 이미지, 그리고 기타 콘텐츠
MCP 결과가 콘텐츠 블록을 사용하면 SDK는 텍스트 콘텐츠를 텍스트 출력으로 전달하고, 이미지 콘텐츠를 도구 출력의 이미지 타입 항목으로 매핑해요. 오디오와 리소스 블록 같은 다른 MCP 콘텐츠 블록 타입의 경우 SDK는 블록의 유효한 JSON 직렬화를 값으로 하는 텍스트 출력을 전달해요. 여러 콘텐츠 블록을 담은 응답은 출력 항목 목록으로 전달돼요. use_structured_content=True가 비어 있지 않고 오류가 아닌 structuredContent 페이로드를 선택하면 그 구조화된 페이로드가 콘텐츠 블록보다 우선해요. 구조화된 콘텐츠가 없거나 비어 있으면 콘텐츠 블록으로 폴백해요.
3. HTTP + SSE MCP 서버
경고: MCP 프로젝트는 Server-Sent Events 전송을 폐기(Deprecate)했어요. 새 통합에서는 Streamable HTTP나 stdio를 선호하고, SSE는 레거시 서버에만 유지하세요.
MCP 서버가 HTTP + SSE 전송을 구현한다면 MCPServerSse를 인스턴스화하면 돼요. 전송 방식 외에는 API가 Streamable HTTP 서버와 동일해요.
from agents import Agent, Runner
from agents.model_settings import ModelSettings
from agents.mcp import MCPServerSse
workspace_id = "demo-workspace"
async with MCPServerSse(
name="SSE Python Server",
params={
"url": "http://localhost:8000/sse",
"headers": {"X-Workspace": workspace_id},
},
cache_tools_list=True,
) as server:
agent = Agent(
name="Assistant",
mcp_servers=[server],
model_settings=ModelSettings(tool_choice="required"),
)
result = await Runner.run(agent, "What's the weather in Tokyo?")
print(result.final_output)
4. stdio MCP 서버
로컬 하위 프로세스로 실행되는 MCP 서버에는 MCPServerStdio를 사용해요. SDK가 프로세스를 띄우고, 파이프를 열어두며, 컨텍스트 매니저가 종료될 때 자동으로 닫아요. 이 옵션은 빠른 개념 증명(proof of concept)이나 서버가 명령줄 진입점만 노출할 때 유용해요.
from pathlib import Path
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
current_dir = Path(__file__).parent
samples_dir = current_dir / "sample_files"
async with MCPServerStdio(
name="Filesystem Server via npx",
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", str(samples_dir)],
},
) as server:
agent = Agent(
name="Assistant",
instructions="Use the files in the sample directory to answer questions.",
mcp_servers=[server],
)
result = await Runner.run(agent, "List the files available to you.")
print(result.final_output)
5. MCP 서버 매니저
MCP 서버가 여러 개 있을 때 MCPServerManager를 사용해서 서버들을 미리 연결하고, 성공적으로 연결된 서버의 부분집합만 에이전트에 노출할 수 있어요. 생성자 옵션과 재연결 동작은 MCPServerManager API 레퍼런스를 참고하세요.
from agents import Agent, Runner
from agents.mcp import MCPServerManager, MCPServerStreamableHttp
servers = [
MCPServerStreamableHttp(name="calendar", params={"url": "http://localhost:8000/mcp"}),
MCPServerStreamableHttp(name="docs", params={"url": "http://localhost:8001/mcp"}),
]
async with MCPServerManager(servers) as manager:
agent = Agent(
name="Assistant",
instructions="Use MCP tools when they help.",
mcp_servers=manager.active_servers,
)
result = await Runner.run(agent, "Which MCP tools are available?")
print(result.final_output)
주요 동작들이에요:
active_servers는drop_failed_servers=True(기본값)일 때 성공적으로 연결된 서버만 포함해요.- 입력 iterable이 같은 서버 객체를 반복하면 매니저는 그 서버를 한 번만 소유해요.
all_servers와active_servers에 항목이 하나만 들어가고, 그 서버에 대한 연결과 정리는 한 번만 실행돼요. - 실패는
failed_servers와errors에 기록돼요. strict=True로 설정하면 첫 연결 실패 시 오류를 발생시켜요.reconnect(failed_only=True)로 실패한 서버를 재시도하거나,reconnect(failed_only=False)로 모든 서버를 다시 시작해요.connect_all(),reconnect(),cleanup_all()호출은 직렬화돼요. 하나의 수명주기 작업이 이미 실행 중이면 다른 수명주기 작업은 동시에 같은 서버를 연결/정리하는 대신 완료될 때까지 기다려요.connect_timeout_seconds,cleanup_timeout_seconds,connect_in_parallel로 수명주기 동작을 조정해요. 두 수명주기 타임아웃 모두 기본 10초예요. 양의 유한 초 또는None(비활성화)을 받고, 생성과 할당 시 모두 검증돼요. 0은 즉시 데드라인을 만들기 때문에 거부돼요.
공통 서버 기능
아래 절들은 MCP 서버 전송에 걸쳐 적용돼요 (정확한 API 표면은 서버 클래스에 따라 달라요).
도구 필터링
각 MCP 서버는 에이전트가 필요한 함수만 노출할 수 있도록 도구 필터를 지원해요. 필터링은 생성 시점에, 또는 실행마다 동적으로 일어날 수 있어요.
정적 도구 필터링
create_static_tool_filter를 사용해서 간단한 allow/block 목록을 구성할 수 있어요:
from pathlib import Path
from agents.mcp import MCPServerStdio, create_static_tool_filter
samples_dir = Path("/path/to/files")
filesystem_server = MCPServerStdio(
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", str(samples_dir)],
},
tool_filter=create_static_tool_filter(allowed_tool_names=["read_file", "write_file"]),
)
allowed_tool_names와 blocked_tool_names를 모두 제공하면 SDK는 먼저 allow-목록을 적용하고, 그 다음 남은 집합에서 차단된 도구를 제거해요.
동적 도구 필터링
더 정교한 로직을 원하면 ToolFilterContext를 받는 callable을 전달하면 돼요. callable은 동기 또는 비동기일 수 있고, 도구를 노출해야 하면 True를 반환해요.
from pathlib import Path
from agents.mcp import MCPServerStdio, ToolFilterContext
samples_dir = Path("/path/to/files")
async def context_aware_filter(context: ToolFilterContext, tool) -> bool:
if context.agent.name == "Code Reviewer" and tool.name.startswith("danger_"):
return False
return True
async with MCPServerStdio(
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", str(samples_dir)],
},
tool_filter=context_aware_filter,
) as server:
...
필터 컨텍스트는 활성 run_context, 도구를 요청하는 agent, 그리고 server_name을 노출해요.
도구 guardrail
로컬 MCP 서버 클래스는 tool_input_guardrails와 tool_output_guardrails를 받아요. SDK는 필터링 후 남은 모든 MCP 도구에 이 서버 전체 guardrail을 붙여요. 입력 guardrail은 MCP 서버 호출을 막고 대체 콘텐츠를 제공할 수 있고, 출력 guardrail은 SDK가 그 결과를 모델에 보내기 전에 변환된 MCP 결과를 검사해요. 이 guardrail들은 Tool guardrails에 설명된 것과 같은 함수-도구 실행 파이프라인, 승인 순서, 결과 추적, tripwire 예외를 사용해요.
import json
from agents import ToolGuardrailFunctionOutput
from agents.decorators import tool_input_guardrail
from agents.mcp import MCPServerStdio
@tool_input_guardrail
def block_secret_arguments(data):
arguments = json.loads(data.context.tool_arguments or "{}")
if "secret" in arguments:
return ToolGuardrailFunctionOutput.reject_content(
"Remove secrets before calling this MCP tool."
)
return ToolGuardrailFunctionOutput.allow()
filesystem_server = MCPServerStdio(
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
},
tool_input_guardrails=[block_secret_arguments],
)
이 구성은 MCPServerStdio, MCPServerSse, MCPServerStreamableHttp 같은 로컬 MCP 서버 객체가 노출하는 도구에만 적용돼요. Responses API가 호스팅 도구로 실행하는 HostedMCPTool에는 클라이언트 측 도구 guardrail을 추가하지 않아요.
프롬프트
MCP 서버는 에이전트 지시문을 동적으로 생성하는 프롬프트도 제공할 수 있어요. 프롬프트를 지원하는 서버는 두 메서드를 노출해요:
list_prompts()는 사용 가능한 프롬프트 템플릿을 열거해요.get_prompt(name, arguments)는 선택적으로 매개변수와 함께 구체적인 프롬프트를 가져와요.
from agents import Agent
prompt_result = await server.get_prompt(
"generate_code_review_instructions",
{"focus": "security vulnerabilities", "language": "python"},
)
instructions = prompt_result.messages[0].content.text
agent = Agent(
name="Code Reviewer",
instructions=instructions,
mcp_servers=[server],
)
페이지네이션
내장 로컬 MCP 서버 클래스는 도구와 프롬프트를 나열할 때 nextCursor를 자동으로 따라가요. list_tools()는 필터를 적용하거나 캐시를 채우기 전에 완전한 도구 목록을 모으고, list_prompts()는 nextCursor=None인 하나의 결합 결과를 반환해요. 이후 페이지가 실패하거나 서버가 커서를 반복하면, 부분 결과를 노출하거나 캐시하는 대신 오류를 발생시켜요.
리소스는 여전히 명시적으로 페이지네이션돼요. list_resources()나 list_resource_templates()에서 받은 nextCursor를 cursor 인자로 다시 전달해서 다음 페이지를 가져오면 돼요.
캐싱
모든 에이전트 실행은 각 MCP 서버에서 list_tools()를 호출해요. 원격 서버는 눈에 띄는 지연을 유발할 수 있으므로, 모든 MCP 서버 클래스는 cache_tools_list 옵션을 노출해요. 도구 정의가 자주 바뀌지 않는다고 확신할 때만 True로 설정하세요. 나중에 새 목록을 강제로 가져오려면 서버 인스턴스에서 invalidate_tools_cache()를 호출하면 돼요.
캐싱이 활성화되면 각 list_tools() 결과는 중첩된 입력 스키마를 포함한 캐시된 도구 정의의 분리된(복사된) 사본을 담아요. 동적 도구 필터 콜백도 분리된 사본을 검사해요. 따라서 반환된 도구나 필터가 받은 도구를 변경해도 서버의 캐시된 스키마나 이후 list_tools() 결과가 바뀌지 않아요.
트레이싱
트레이싱은 MCP 활동을 자동으로 캡처해요. 여기에는 다음이 포함돼요:
- 도구를 나열하기 위한 MCP 서버 호출.
- 도구 호출의 MCP 관련 정보.

더 알아보기 (Learn more)
- Model Context Protocol – 스펙과 설계 가이드.
- examples/mcp – 실행 가능한 stdio, SSE, Streamable HTTP 샘플.
- examples/hosted_mcp – 승인과 커넥터를 포함한 완전한 호스팅 MCP 데모.