@@ -10,9 +10,10 @@ import {CodexApprovalHandler} from "./CodexApprovalHandler";
1010import { CodexAuthMethods , type CodexAuthRequest } from "./CodexAuthMethod" ;
1111import { CodexAcpClient , type SessionMetadata , type SessionMetadataWithThread } from "./CodexAcpClient" ;
1212import { ACPSessionConnection , type UpdateSessionEvent } from "./ACPSessionConnection" ;
13- import type { Account , CollabAgentToolCallStatus , Model , RateLimitSnapshot , Thread , ThreadItem , UserInput , ReasoningEffortOption } from "./app-server/v2" ;
13+ import type { Account , CollabAgentToolCallStatus , Model , Thread , ThreadItem , UserInput , ReasoningEffortOption } from "./app-server/v2" ;
1414import type { RateLimitsMap } from "./RateLimitsMap" ;
1515import type { InputModality , ReasoningEffort } from "./app-server" ;
16+ import type { McpStartupCompleteEvent } from "./app-server" ;
1617import { ModelId } from "./ModelId" ;
1718import { AgentMode } from "./AgentMode" ;
1819import type { TokenCount } from "./TokenCount" ;
@@ -127,7 +128,7 @@ export class CodexAcpServer implements acp.Agent {
127128
128129 async getOrCreateSession ( request : acp . NewSessionRequest | acp . ResumeSessionRequest ) : Promise < [ SessionId , SessionModelState , SessionModeState ] > {
129130 await this . checkAuthorization ( ) ;
130- const pendingMcpServers : Promise < Array < string > > = this . codexAcpClient . awaitMcpServers ( ) ;
131+ const pendingMcpStartup : Promise < McpStartupCompleteEvent > = this . codexAcpClient . awaitMcpServers ( ) ;
131132
132133 let sessionMetadata : SessionMetadata ;
133134 if ( "sessionId" in request ) {
@@ -141,7 +142,9 @@ export class CodexAcpServer implements acp.Agent {
141142 const accountResponse = await this . runWithProcessCheck ( ( ) => this . codexAcpClient . getAccount ( ) ) ;
142143 const { sessionId, currentModelId, models} = sessionMetadata ;
143144 logger . log ( `Waiting MCP servers to start...` )
144- const sessionMcpServers = await pendingMcpServers ;
145+ const mcpStartup = await pendingMcpStartup ;
146+ const sessionMcpServers = mcpStartup . ready ;
147+ await this . publishMcpStartupStatus ( sessionId , mcpStartup ) ;
145148 const currentModel = this . findCurrentModel ( models , currentModelId ) ;
146149 const sessionState : SessionState = {
147150 sessionId : sessionId ,
@@ -332,7 +335,7 @@ export class CodexAcpServer implements acp.Agent {
332335 thread : Thread ;
333336 } > {
334337 await this . checkAuthorization ( ) ;
335- const pendingMcpServers : Promise < Array < string > > = this . codexAcpClient . awaitMcpServers ( ) ;
338+ const pendingMcpStartup : Promise < McpStartupCompleteEvent > = this . codexAcpClient . awaitMcpServers ( ) ;
336339
337340 logger . log ( `Load existing session: ${ request . sessionId } ...` ) ;
338341 const sessionMetadata : SessionMetadataWithThread = await this . runWithProcessCheck ( ( ) =>
@@ -342,7 +345,9 @@ export class CodexAcpServer implements acp.Agent {
342345 const accountResponse = await this . runWithProcessCheck ( ( ) => this . codexAcpClient . getAccount ( ) ) ;
343346 const { sessionId, currentModelId, models, thread} = sessionMetadata ;
344347 logger . log ( "Waiting MCP servers to start..." ) ;
345- const sessionMcpServers = await pendingMcpServers ;
348+ const mcpStartup = await pendingMcpStartup ;
349+ const sessionMcpServers = mcpStartup . ready ;
350+ await this . publishMcpStartupStatus ( sessionId , mcpStartup ) ;
346351 const currentModel = this . findCurrentModel ( models , currentModelId ) ;
347352 const sessionState : SessionState = {
348353 sessionId : sessionId ,
@@ -700,6 +705,52 @@ export class CodexAcpServer implements acp.Agent {
700705 } ;
701706 }
702707
708+ private async publishMcpStartupStatus ( sessionId : string , mcpStartup : McpStartupCompleteEvent ) : Promise < void > {
709+ if ( mcpStartup . failed . length === 0 && mcpStartup . cancelled . length === 0 ) {
710+ return ;
711+ }
712+
713+ for ( const server of mcpStartup . failed ) {
714+ await this . connection . sessionUpdate ( {
715+ sessionId,
716+ update : this . createMcpStartupToolCallUpdate (
717+ server . server ,
718+ `[codex-acp forwarded startup error] MCP server \`${ server . server } \` failed to start: ${ server . error } `
719+ ) ,
720+ } ) ;
721+ }
722+ for ( const server of mcpStartup . cancelled ) {
723+ await this . connection . sessionUpdate ( {
724+ sessionId,
725+ update : this . createMcpStartupToolCallUpdate (
726+ server ,
727+ `[codex-acp forwarded startup error] MCP server \`${ server } \` startup was cancelled.`
728+ ) ,
729+ } ) ;
730+ }
731+ }
732+
733+ private createMcpStartupToolCallUpdate ( serverName : string , message : string ) : UpdateSessionEvent {
734+ return {
735+ sessionUpdate : "tool_call" ,
736+ toolCallId : this . getMcpStartupToolCallId ( serverName ) ,
737+ kind : "other" ,
738+ title : `mcp__${ serverName } __startup` ,
739+ status : "failed" ,
740+ content : [ {
741+ type : "content" ,
742+ content : {
743+ type : "text" ,
744+ text : message ,
745+ } ,
746+ } ] ,
747+ } ;
748+ }
749+
750+ private getMcpStartupToolCallId ( serverName : string ) : string {
751+ return `mcp_startup.${ encodeURIComponent ( serverName ) } ` ;
752+ }
753+
703754 private async runWithProcessCheck < T > ( operation : ( ) => Promise < T > ) : Promise < T > {
704755 try {
705756 return await operation ( ) ;
0 commit comments