Skip to content

feat: add hosted mcp tool support #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions examples/hosted-mcp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Hosted Model Context Protocol Example

This example demonstrates how to use [OpenAI Hosted MCP](https://platform.openai.com/docs/guides/tools-remote-mcp) servers with the OpenAI Agents SDK.

The example shows two different scenarios:

- `simple.ts` - A basic example of connecting to a hosted MCP server with no approval required.
- `approvals.ts` - An example showing how to use an approvals workflow with a hosted MCP server.

Run the examples from the repository root:

### Simple

```bash
pnpm -F hosted-mcp start:simple
```

### Approvals

```bash
pnpm -F hosted-mcp start:approvals
```
79 changes: 79 additions & 0 deletions examples/hosted-mcp/approvals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Agent, run, hostedMCPTool } from '@openai/agents';
import * as readline from 'readline';

/**
* This example demonstrates how to use the hosted MCP support in the OpenAI Responses API, with
* approval callbacks.
*/

// Create readline interface for user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

function approvalCallback(toolName: string): Promise<boolean> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I understand how this is currently being used

return new Promise((resolve) => {
rl.question(
`Approve running the tool \`${toolName}\`? (y/n) `,
(answer) => {
const approved = answer.toLowerCase() === 'y';
if (!approved) {
console.log('User denied');
}
resolve(approved);
},
);
});
}

async function main(verbose: boolean, stream: boolean) {
const agent = new Agent({
name: 'Assistant',
tools: [
hostedMCPTool({
serverLabel: 'gitmcp',
serverUrl: 'https://gitmcp.io/openai/codex',
requireApproval: 'always',
}),
],
});

let result: any;

if (stream) {
result = await run(agent, 'Which language is this repo written in?', {
stream: true,
});

for await (const event of result.toStream()) {
if (event.type === 'run_item_stream_event') {
console.log(`Got event of type ${event.item.constructor.name}`);
}
}
console.log(`Done streaming; final result: ${result.finalOutput}`);
} else {
result = await run(agent, 'Which language is this repo written in?');
console.log(result.finalOutput);
}

if (verbose) {
for (const item of result.newItems) {
console.log(item);
}
}

// Close readline interface
rl.close();
}

// Parse command line arguments
const args = process.argv.slice(2);
const verbose = args.includes('--verbose');
const stream = args.includes('--stream');

main(verbose, stream).catch((error) => {
console.error(error);
rl.close();
process.exit(1);
});
13 changes: 13 additions & 0 deletions examples/hosted-mcp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"private": true,
"name": "hosted-mcp",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.0",
"@openai/agents": "workspace:*"
},
"scripts": {
"build-check": "tsc --noEmit",
"start:simple": "tsx simple.ts",
"start:approvals": "tsx approvals.ts"
}
}
56 changes: 56 additions & 0 deletions examples/hosted-mcp/simple.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Agent, run, hostedMCPTool } from '@openai/agents';

/**
* This example demonstrates how to use the hosted MCP support in the OpenAI Responses API, with
* approvals not required for any tools. You should only use this for trusted MCP servers.
*/

async function main(verbose: boolean, stream: boolean) {
const agent = new Agent({
name: 'Assistant',
tools: [
hostedMCPTool({
serverLabel: 'deepwiki',
serverUrl: 'https://mcp.deepwiki.com/mcp',
requireApproval: 'never',
}),
],
});

let result: any;
if (stream) {
result = await run(
agent,
'What transport protocols are supported in the 2025-03-26 version of the MCP spec?',
{
stream: true,
},
);
for await (const event of result.toStream()) {
if (event.type === 'run_item_stream_event') {
console.log(`Got event of type ${event.item.constructor.name}`);
} else if (event.type === 'run_item_stream_event') {
}
}
console.log(`Done streaming; final result: ${result.finalOutput}`);
} else {
result = await run(
agent,
'What transport protocols are supported in the 2025-03-26 version of the MCP spec?',
);
console.log(result.finalOutput);
// As of the **2025-03-26 version** of the **MCP (Mesh Configuration Protocol) specification**, the following **transport protocols are supported**:...
}

if (verbose) {
for (const item of result.newItems) {
console.log(item);
}
}
}

const args = process.argv.slice(2);
const verbose = args.includes('--verbose') || false;
const stream = args.includes('--stream') || false;

main(verbose, stream).catch(console.error);
3 changes: 3 additions & 0 deletions examples/hosted-mcp/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "../../tsconfig.examples.json"
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -37,6 +37,8 @@
"examples:tools-computer-use": "pnpm -F tools start:computer-use",
"examples:tools-file-search": "pnpm -F tools start:file-search",
"examples:tools-web-search": "pnpm -F tools start:web-search",
"examples:hosted-mcp-simple": "pnpm -F hosted-mcp start:simple",
"examples:hosted-mcp-approvals": "pnpm -F hosted-mcp start:approvals",
"ci:publish": "pnpm publish -r --no-git-checks",
"prepare": "husky",
"clear:deps": "rm -rf node_modules && pnpm -r exec rm -rf node_modules",
1 change: 1 addition & 0 deletions packages/agents-openai/src/index.ts
Original file line number Diff line number Diff line change
@@ -17,4 +17,5 @@ export {
fileSearchTool,
codeInterpreterTool,
imageGenerationTool,
hostedMCPTool,
} from './tools';
25 changes: 25 additions & 0 deletions packages/agents-openai/src/openaiResponsesModel.ts
Original file line number Diff line number Diff line change
@@ -175,6 +175,18 @@ function converTool<_TContext = unknown>(
},
include: undefined,
};
} else if (tool.providerData?.type === 'mcp') {
return {
tool: {
type: 'mcp',
server_label: tool.providerData.serverLabel,
server_url: tool.providerData.serverUrl,
allowed_tools: tool.providerData.allowedTools,
headers: tool.providerData.headers,
require_approval: tool.providerData.requireApproval,
},
include: undefined,
};
}
}

@@ -456,6 +468,19 @@ function getInputItems(
return entry;
}

if (item.providerData?.type === 'mcp') {
const entry: OpenAI.Responses.ResponseInputItem.McpCall = {
type: 'mcp_call',
id: item.id!,
arguments: item.providerData?.arguments ?? {},
name: item.providerData?.name,
server_label: item.providerData?.serverLabel ?? '',
...item.providerData,
};

return entry;
}

throw new UserError(
`Unsupported built-in tool call type: ${JSON.stringify(item)}`,
);
44 changes: 44 additions & 0 deletions packages/agents-openai/src/tools.ts
Original file line number Diff line number Diff line change
@@ -188,3 +188,47 @@ export function imageGenerationTool(
},
};
}

/**
* The built-in MCP (Model Context Protocol) tool
*/
export type HostedMCPTool = {
type: 'mcp';
name?: 'mcp' | string;
serverLabel: string;
serverUrl: string;
allowedTools?:
| Array<string>
| OpenAI.Responses.Tool.Mcp.McpAllowedToolsFilter
| null;
headers?: Record<string, string> | null;
requireApproval?:
| OpenAI.Responses.Tool.Mcp.McpToolApprovalFilter
| 'always'
| 'never'
| string
| null;
};

/**
* Adds MCP (Model Context Protocol) server access to your agent
* @param options Configuration for the MCP server
* @returns an MCP tool definition
*/
export function hostedMCPTool(
options: Partial<Omit<HostedMCPTool, 'type'>> = {},
): HostedTool {
return {
type: 'hosted_tool',
name: options.name ?? 'mcp',
providerData: {
type: 'mcp',
name: options.name ?? 'mcp',
serverLabel: options.serverLabel,
serverUrl: options.serverUrl,
allowedTools: options.allowedTools,
headers: options.headers,
requireApproval: options.requireApproval,
},
};
}
11,942 changes: 5,293 additions & 6,649 deletions pnpm-lock.yaml

Large diffs are not rendered by default.