콘텐츠로 이동

모델 컨텍스트 프로토콜 (MCP)

Model Context Protocol (MCP)은 애플리케이션이 LLM에 도구와 컨텍스트를 제공하는 방식을 표준화한 오픈 프로토콜입니다. MCP 문서에서 인용:

MCP는 애플리케이션이 LLM에 컨텍스트를 제공하는 방식을 표준화한 오픈 프로토콜입니다. MCP를 AI 애플리케이션을 위한 USB‑C 포트라고 생각해 보세요. USB‑C가 다양한 주변기기와 액세서리를 기기에 표준 방식으로 연결하듯, MCP는 AI 모델을 서로 다른 데이터 소스와 도구에 표준 방식으로 연결합니다.

이 SDK가 지원하는 MCP 서버 유형은 세 가지입니다:

  1. Hosted MCP server toolsOpenAI Responses API가 도구로 사용하는 원격 MCP 서버
  2. Streamable HTTP MCP serversStreamable HTTP transport를 구현한 로컬 또는 원격 서버
  3. Stdio MCP servers – 표준 입출력을 통해 액세스하는 서버(가장 간단한 옵션)

사용 사례에 따라 서버 유형을 선택하세요:

필요한 것권장 옵션
기본 OpenAI responses 모델로 공용 원격 서버 호출1. Hosted MCP tools
공용 원격 서버를 사용하지만 도구 호출은 로컬에서 트리거2. Streamable HTTP
로컬에서 실행 중인 Streamable HTTP 서버 사용2. Streamable HTTP
OpenAI Responses 이외의 모델과 모든 Streamable HTTP 서버 사용2. Streamable HTTP
표준 I/O 프로토콜만 지원하는 로컬 MCP 서버 사용3. Stdio

호스티드 툴은 전체 왕복 과정을 모델 내부로 밀어 넣습니다. 코드가 MCP 서버를 호출하는 대신 OpenAI Responses API가 원격 도구 엔드포인트를 호출하고 결과를 모델로 스트리밍합니다.

다음은 호스티드 MCP 툴을 사용하는 가장 간단한 예시입니다. 원격 MCP 서버의 레이블과 URL을 hostedMcpTool 유틸리티 함수에 전달할 수 있으며, 이는 호스티드 MCP 서버 도구를 만드는 데 유용합니다.

hostedAgent.ts
import { Agent, hostedMcpTool } from '@openai/agents';
export const agent = new Agent({
name: 'MCP Assistant',
instructions: 'You must always use the MCP tools to answer questions.',
tools: [
hostedMcpTool({
serverLabel: 'gitmcp',
serverUrl: 'https://gitmcp.io/openai/codex',
}),
],
});

그런 다음 run 함수(또는 직접 커스터마이즈한 Runner 인스턴스의 run 메서드)로 에이전트를 실행할 수 있습니다:

Run with hosted MCP tools
import { run } from '@openai/agents';
import { agent } from './hostedAgent';
async function main() {
const result = await run(
agent,
'Which language is the repo I pointed in the MCP tool settings written in?',
);
console.log(result.finalOutput);
}
main().catch(console.error);

증분 MCP 결과를 스트리밍하려면 Agent를 실행할 때 stream: true를 전달하세요:

Run with hosted MCP tools (streaming)
import { run } from '@openai/agents';
import { agent } from './hostedAgent';
async function main() {
const result = await run(
agent,
'Which language is the repo I pointed in the MCP tool settings written in?',
{ stream: true },
);
for await (const event of result) {
if (
event.type === 'raw_model_stream_event' &&
event.data.type === 'model' &&
event.data.event.type !== 'response.mcp_call_arguments.delta' &&
event.data.event.type !== 'response.output_text.delta'
) {
console.log(`Got event of type ${JSON.stringify(event.data)}`);
}
}
console.log(`Done streaming; final result: ${result.finalOutput}`);
}
main().catch(console.error);

민감한 작업의 경우 개별 도구 호출에 대해 사람의 승인을 요구할 수 있습니다. requireApproval: 'always' 또는 도구 이름을 'never'/'always'로 매핑하는 세분화된 객체를 전달하세요.

도구 호출의 안전성을 프로그램적으로 판단할 수 있다면 onApproval 콜백을 사용해 승인 또는 거부할 수 있습니다. 사람의 승인이 필요하다면 로컬 함수 도구와 마찬가지로 interruptions를 사용하는 동일한 휴먼 인 더 루프 (HITL) 접근을 사용할 수 있습니다.

Human in the loop with hosted MCP tools
import { Agent, run, hostedMcpTool, RunToolApprovalItem } from '@openai/agents';
async function main(): Promise<void> {
const agent = new Agent({
name: 'MCP Assistant',
instructions: 'You must always use the MCP tools to answer questions.',
tools: [
hostedMcpTool({
serverLabel: 'gitmcp',
serverUrl: 'https://gitmcp.io/openai/codex',
// 'always' | 'never' | { never, always }
requireApproval: {
never: {
toolNames: ['search_codex_code', 'fetch_codex_documentation'],
},
always: {
toolNames: ['fetch_generic_url_content'],
},
},
}),
],
});
let result = await run(agent, 'Which language is this repo written in?');
while (result.interruptions && result.interruptions.length) {
for (const interruption of result.interruptions) {
// Human in the loop here
const approval = await confirm(interruption);
if (approval) {
result.state.approve(interruption);
} else {
result.state.reject(interruption);
}
}
result = await run(agent, result.state);
}
console.log(result.finalOutput);
}
import { stdin, stdout } from 'node:process';
import * as readline from 'node:readline/promises';
async function confirm(item: RunToolApprovalItem): Promise<boolean> {
const rl = readline.createInterface({ input: stdin, output: stdout });
const name = item.rawItem.name;
const params = item.rawItem.providerData?.arguments;
const answer = await rl.question(
`Approve running tool (mcp: ${name}, params: ${params})? (y/n) `,
);
rl.close();
return answer.toLowerCase().trim() === 'y';
}
main().catch(console.error);

Hosted MCP는 OpenAI 커넥터도 지원합니다. serverUrl을 제공하는 대신 커넥터의 connectorIdauthorization 토큰을 전달하세요. 그러면 Responses API가 인증을 처리하고 호스티드 MCP 인터페이스를 통해 커넥터의 도구를 노출합니다.

Connector-backed hosted MCP tool
import { Agent, hostedMcpTool } from '@openai/agents';
const authorization = process.env.GOOGLE_CALENDAR_AUTHORIZATION!;
export const connectorAgent = new Agent({
name: 'Calendar Assistant',
instructions:
"You are a helpful assistant that can answer questions about the user's calendar.",
tools: [
hostedMcpTool({
serverLabel: 'google_calendar',
connectorId: 'connector_googlecalendar',
authorization,
requireApproval: 'never',
}),
],
});

이 예시에서 GOOGLE_CALENDAR_AUTHORIZATION 환경 변수에는 Google OAuth Playground에서 얻은 OAuth 토큰이 들어 있으며, 커넥터 기반 서버가 Calendar API를 호출할 수 있도록 승인합니다. 스트리밍도 함께 보여 주는 실행 가능한 샘플은 examples/connectors를 참고하세요.

완전히 동작하는 샘플(Hosted tools/Streamable HTTP/stdio + Streaming, HITL, onApproval)은 GitHub 리포지토리의 examples/mcp에 있습니다.

에이전트가 로컬 또는 원격의 Streamable HTTP MCP 서버와 직접 통신하는 경우, 서버 url, name 및 선택 설정을 지정하여 MCPServerStreamableHttp를 인스턴스화하세요:

Run with Streamable HTTP MCP servers
import { Agent, run, MCPServerStreamableHttp } from '@openai/agents';
async function main() {
const mcpServer = new MCPServerStreamableHttp({
url: 'https://gitmcp.io/openai/codex',
name: 'GitMCP Documentation Server',
});
const agent = new Agent({
name: 'GitMCP Assistant',
instructions: 'Use the tools to respond to user requests.',
mcpServers: [mcpServer],
});
try {
await mcpServer.connect();
const result = await run(agent, 'Which language is this repo written in?');
console.log(result.finalOutput);
} finally {
await mcpServer.close();
}
}
main().catch(console.error);

생성자는 또한 authProvider, requestInit, fetch, reconnectionOptions, sessionId와 같은 추가 MCP TypeScript‑SDK 옵션을 허용합니다. 자세한 내용은 MCP TypeScript SDK 리포지토리와 문서를 참고하세요.

표준 I/O만 노출하는 서버의 경우 fullCommandMCPServerStdio를 인스턴스화하세요:

Run with Stdio MCP servers
import { Agent, run, MCPServerStdio } from '@openai/agents';
import * as path from 'node:path';
async function main() {
const samplesDir = path.join(__dirname, 'sample_files');
const mcpServer = new MCPServerStdio({
name: 'Filesystem MCP Server, via npx',
fullCommand: `npx -y @modelcontextprotocol/server-filesystem ${samplesDir}`,
});
await mcpServer.connect();
try {
const agent = new Agent({
name: 'FS MCP Assistant',
instructions:
'Use the tools to read the filesystem and answer questions based on those files. If you are unable to find any files, you can say so instead of assuming they exist.',
mcpServers: [mcpServer],
});
const result = await run(agent, 'Read the files and list them.');
console.log(result.finalOutput);
} finally {
await mcpServer.close();
}
}
main().catch(console.error);

Streamable HTTPStdio 서버의 경우, Agent가 실행될 때마다 사용 가능한 도구를 확인하기 위해 list_tools()를 호출할 수 있습니다. 이 왕복은 지연 시간을 증가시킬 수 있으므로(특히 원격 서버의 경우), MCPServerStdio 또는 MCPServerStreamableHttpcacheToolsList: true를 전달하여 메모리에 결과를 캐시할 수 있습니다.

도구 목록이 변경되지 않는다고 확신할 때만 활성화하세요. 나중에 캐시를 무효화하려면 서버 인스턴스에서 invalidateToolsCache()를 호출하세요.

createMCPToolStaticFilter를 통한 정적 필터 또는 사용자 정의 함수를 전달하여 각 서버에서 노출되는 도구를 제한할 수 있습니다. 다음은 두 가지 접근을 함께 보여 주는 예시입니다:

Tool filtering
import {
MCPServerStdio,
MCPServerStreamableHttp,
createMCPToolStaticFilter,
MCPToolFilterContext,
} from '@openai/agents';
interface ToolFilterContext {
allowAll: boolean;
}
const server = new MCPServerStdio({
fullCommand: 'my-server',
toolFilter: createMCPToolStaticFilter({
allowed: ['safe_tool'],
blocked: ['danger_tool'],
}),
});
const dynamicServer = new MCPServerStreamableHttp({
url: 'http://localhost:3000',
toolFilter: async ({ runContext }: MCPToolFilterContext, tool) =>
(runContext.context as ToolFilterContext).allowAll || tool.name !== 'admin',
});