@@ -14,7 +14,13 @@ import {
1414} from './items' ;
1515import logger , { Logger } from './logger' ;
1616import { ModelResponse , ModelSettings } from './model' ;
17- import { ComputerTool , FunctionTool , Tool , FunctionToolResult } from './tool' ;
17+ import {
18+ ComputerTool ,
19+ FunctionTool ,
20+ Tool ,
21+ FunctionToolResult ,
22+ HostedMCPTool ,
23+ } from './tool' ;
1824import { AgentInputItem , UnknownContext } from './types' ;
1925import { Runner } from './run' ;
2026import { RunContext } from './runContext' ;
@@ -31,6 +37,7 @@ import * as protocol from './types/protocol';
3137import { Computer } from './computer' ;
3238import { RunState } from './runState' ;
3339import { isZodObject } from './utils' ;
40+ import * as ProviderData from './types/providerData' ;
3441
3542type ToolRunHandoff = {
3643 toolCall : protocol . FunctionCallItem ;
@@ -47,11 +54,17 @@ type ToolRunComputer = {
4754 computer : ComputerTool ;
4855} ;
4956
57+ type ToolRunMCPApprovalRequest = {
58+ requestItem : RunToolApprovalItem ;
59+ mcpTool : HostedMCPTool ;
60+ } ;
61+
5062export type ProcessedResponse < TContext = UnknownContext > = {
5163 newItems : RunItem [ ] ;
5264 handoffs : ToolRunHandoff [ ] ;
5365 functions : ToolRunFunction < TContext > [ ] ;
5466 computerActions : ToolRunComputer [ ] ;
67+ mcpApprovalRequests : ToolRunMCPApprovalRequest [ ] ;
5568 toolsUsed : string [ ] ;
5669 hasToolsOrApprovalsToRun ( ) : boolean ;
5770} ;
@@ -69,21 +82,78 @@ export function processModelResponse<TContext>(
6982 const runHandoffs : ToolRunHandoff [ ] = [ ] ;
7083 const runFunctions : ToolRunFunction < TContext > [ ] = [ ] ;
7184 const runComputerActions : ToolRunComputer [ ] = [ ] ;
85+ const runMCPApprovalRequests : ToolRunMCPApprovalRequest [ ] = [ ] ;
7286 const toolsUsed : string [ ] = [ ] ;
7387 const handoffMap = new Map ( handoffs . map ( ( h ) => [ h . toolName , h ] ) ) ;
7488 const functionMap = new Map (
7589 tools . filter ( ( t ) => t . type === 'function' ) . map ( ( t ) => [ t . name , t ] ) ,
7690 ) ;
7791 const computerTool = tools . find ( ( t ) => t . type === 'computer' ) ;
92+ const mcpToolMap = new Map (
93+ tools
94+ . filter ( ( t ) => t . type === 'hosted_tool' && t . providerData ?. type === 'mcp' )
95+ . map ( ( t ) => t as HostedMCPTool )
96+ . map ( ( t ) => [ t . providerData . serverLabel , t ] ) ,
97+ ) ;
7898
7999 for ( const output of modelResponse . output ) {
80100 if ( output . type === 'message' ) {
81101 if ( output . role === 'assistant' ) {
82102 items . push ( new RunMessageOutputItem ( output , agent ) ) ;
83103 }
84104 } else if ( output . type === 'hosted_tool_call' ) {
85- items . push ( new RunToolCallItem ( output , agent ) ) ;
86- toolsUsed . push ( output . name ) ;
105+ if (
106+ output . providerData ?. type === 'mcp_approval_request' ||
107+ output . name === 'mcp_approval_request'
108+ ) {
109+ // Hosted remote MCP server support
110+ const providerData =
111+ output . providerData as ProviderData . HostedMCPApprovalRequest ;
112+ const mcpServerLabel = providerData . serverLabel ;
113+ const mcpServerTool = mcpToolMap . get ( mcpServerLabel ) ;
114+ if ( mcpServerTool !== undefined ) {
115+ const toolName = JSON . stringify ( {
116+ server : providerData . serverLabel ,
117+ name : providerData . name ,
118+ } ) ;
119+ // Do this approval later
120+ runMCPApprovalRequests . push ( {
121+ requestItem : new RunToolApprovalItem (
122+ {
123+ type : 'function_call' ,
124+ name : toolName ,
125+ callId : providerData . id ,
126+ arguments : providerData . arguments || '' ,
127+ status : 'in_progress' ,
128+ providerData,
129+ } ,
130+ agent ,
131+ ) ,
132+ mcpTool : mcpServerTool ,
133+ } ) ;
134+ items . push ( new RunToolCallItem ( output , agent ) ) ;
135+ toolsUsed . push ( toolName ) ;
136+ } else {
137+ const message = `MCP server (${ mcpServerLabel } ) not found in Agent (${ agent . name } )` ;
138+ addErrorToCurrentSpan ( {
139+ message,
140+ data : { mcp_server_label : mcpServerLabel } ,
141+ } ) ;
142+ throw new ModelBehaviorError ( message ) ;
143+ }
144+ } else {
145+ // the rest of the hosted
146+ items . push ( new RunToolCallItem ( output , agent ) ) ;
147+ const toolName = output . providerData ?. serverLabel
148+ ? // hosted MCP tool
149+ JSON . stringify ( {
150+ server : output . providerData . serverLabel ,
151+ name : output . name ,
152+ } )
153+ : // other hosted tools
154+ output . name ;
155+ toolsUsed . push ( toolName ) ;
156+ }
87157 } else if ( output . type === 'reasoning' ) {
88158 items . push ( new RunReasoningItem ( output , agent ) ) ;
89159 } else if ( output . type === 'computer_call' ) {
@@ -147,6 +217,7 @@ export function processModelResponse<TContext>(
147217 handoffs : runHandoffs ,
148218 functions : runFunctions ,
149219 computerActions : runComputerActions ,
220+ mcpApprovalRequests : runMCPApprovalRequests ,
150221 toolsUsed : toolsUsed ,
151222 hasToolsOrApprovalsToRun ( ) : boolean {
152223 return (
@@ -344,6 +415,40 @@ export async function executeToolsAndSideEffects<TContext>(
344415 newItems = newItems . concat ( functionResults . map ( ( r ) => r . runItem ) ) ;
345416 newItems = newItems . concat ( computerResults ) ;
346417
418+ // run hosted MCP approval requests
419+ if ( processedResponse . mcpApprovalRequests . length > 0 ) {
420+ for ( const approvalRequest of processedResponse . mcpApprovalRequests ) {
421+ const toolData = approvalRequest . mcpTool
422+ . providerData as ProviderData . HostedMCPTool < TContext > ;
423+ if ( ! toolData . onApproval ) {
424+ throw new UserError (
425+ `Hosted remote MCP server tool (${ toolData . serverLabel } ) does not have an onApproval function` ,
426+ ) ;
427+ }
428+ const approvalResult = await toolData . onApproval (
429+ state . _context ,
430+ approvalRequest . requestItem ,
431+ ) ;
432+ const requestData = approvalRequest . requestItem . rawItem
433+ . providerData as ProviderData . HostedMCPApprovalRequest ;
434+ const approvalResponseData : ProviderData . HostedMCPApprovalResponse = {
435+ approve : approvalResult . approve ,
436+ approvalRequestId : requestData . id ,
437+ reason : approvalResult . reason ,
438+ } ;
439+ newItems . push (
440+ new RunToolCallItem (
441+ {
442+ type : 'hosted_tool_call' ,
443+ name : 'mcp_approval_response' ,
444+ providerData : approvalResponseData ,
445+ } ,
446+ agent as Agent < unknown , 'text' > ,
447+ ) ,
448+ ) ;
449+ }
450+ }
451+
347452 // process handoffs
348453 if ( processedResponse . handoffs . length > 0 ) {
349454 return await executeHandoffCalls (
0 commit comments