11import type * as acp from "@agentclientprotocol/sdk" ;
2+ import fs from "node:fs" ;
23import path from "node:path" ;
34import { afterEach , beforeEach , expect , it } from "vitest" ;
45import { ApprovalOptionId } from "../../../ApprovalOptionId" ;
@@ -14,12 +15,15 @@ import {
1415const MCP_SERVER_NAME = "integration-mcp" ;
1516const MCP_ECHO_MESSAGE = "mcp approval e2e" ;
1617
17- function createMcpServer ( ) : acp . McpServerStdio {
18+ function createMcpServer ( invocationMarkerPath : string ) : acp . McpServerStdio {
1819 return {
1920 name : MCP_SERVER_NAME ,
2021 command : process . execPath ,
21- args : [ path . join ( process . cwd ( ) , "node_modules/mcp-hello-world/build/stdio.js" ) ] ,
22- env : [ ] ,
22+ args : [ path . join ( process . cwd ( ) , "src/__tests__/CodexACPAgent/e2e/fixtures/invocation-aware-mcp-server.mjs" ) ] ,
23+ env : [ {
24+ name : "MCP_TOOL_INVOCATION_MARKER_PATH" ,
25+ value : invocationMarkerPath ,
26+ } ] ,
2327 } ;
2428}
2529
@@ -33,36 +37,39 @@ function createMcpPermissionResponder(optionId: ApprovalOptionId): PermissionRes
3337
3438describeE2E ( "E2E MCP approval tests" , ( ) => {
3539 let fixture : SpawnedAgentFixture ;
36- let sessionId : string ;
3740
3841 beforeEach ( async ( ) => {
3942 fixture = await createAuthenticatedFixture ( ) ;
40- sessionId = ( await fixture . createSession ( [ createMcpServer ( ) ] ) ) . sessionId ;
4143 } ) ;
4244
4345 afterEach ( async ( ) => {
4446 await fixture . dispose ( ) ;
4547 } ) ;
4648
47- function expectMcpToolPermissionRequest ( ) : void {
49+ function expectMcpToolPermissionRequest ( sessionId : string ) : void {
4850 const requests = fixture . readPermissionRequests ( sessionId , "execute" ) ;
4951 expect ( requests . length ) . toBe ( 1 ) ;
5052 expect ( isMcpPermissionRequest ( requests [ 0 ] ! ) ) . toBe ( true ) ;
5153 }
5254
5355 it ( "executes an approved MCP tool call" , async ( ) => {
5456 fixture . setPermissionResponder ( createMcpPermissionResponder ( ApprovalOptionId . AllowOnce ) ) ;
57+ const invocationMarkerPath = path . join ( fixture . workspaceDir , `mcp-tool-invocation-${ crypto . randomUUID ( ) } .txt` ) ;
58+ const sessionId = ( await fixture . createSession ( [ createMcpServer ( invocationMarkerPath ) ] ) ) . sessionId ;
5559
5660 await fixture . expectPromptText (
5761 sessionId ,
5862 `Use the ${ MCP_SERVER_NAME } MCP echo tool with message "${ MCP_ECHO_MESSAGE } ". Reply with exactly the tool result and no extra text.` ,
5963 ( text ) => expect ( text ) . toContain ( `You said: ${ MCP_ECHO_MESSAGE } ` ) ,
6064 ) ;
61- expectMcpToolPermissionRequest ( ) ;
65+ expect ( fs . readFileSync ( invocationMarkerPath , "utf8" ) ) . toBe ( MCP_ECHO_MESSAGE ) ;
66+ expectMcpToolPermissionRequest ( sessionId ) ;
6267 } ) ;
6368
6469 it ( "ends turn when MCP tool call is rejected" , async ( ) => {
6570 fixture . setPermissionResponder ( createMcpPermissionResponder ( ApprovalOptionId . RejectOnce ) ) ;
71+ const invocationMarkerPath = path . join ( fixture . workspaceDir , `mcp-tool-invocation-${ crypto . randomUUID ( ) } .txt` ) ;
72+ const sessionId = ( await fixture . createSession ( [ createMcpServer ( invocationMarkerPath ) ] ) ) . sessionId ;
6673
6774 expectEndTurn ( await fixture . connection . prompt ( {
6875 sessionId,
@@ -71,6 +78,7 @@ describeE2E("E2E MCP approval tests", () => {
7178 text : `Use the ${ MCP_SERVER_NAME } MCP echo tool with message "${ MCP_ECHO_MESSAGE } ". Stop if the tool call is rejected.` ,
7279 } ] ,
7380 } ) ) ;
74- expectMcpToolPermissionRequest ( ) ;
81+ expect ( fs . existsSync ( invocationMarkerPath ) ) . toBe ( false ) ;
82+ expectMcpToolPermissionRequest ( sessionId ) ;
7583 } ) ;
7684} ) ;
0 commit comments