fix(codex): bridge MCP elicitation through user input (#1008)

* fix(codex): bridge MCP elicitation through user input

* fix(codex): allow MCP elicitation in yolo mode

* fix(codex): preserve MCP form semantics

* fix(codex): accept implicit MCP form mode

* fix(codex): harden MCP elicitation prompts

* fix(codex): require valid MCP choice answers

* fix(codex): round-trip MCP array elicitation

* fix(web): require explicit MCP URL confirmation

* fix(codex): preserve MCP array item types

* fix(codex): support multi-select MCP elicitation

* fix(codex): allow MCP elicitation in read-only mode

* fix(codex): route MCP tool approvals through permissions
This commit is contained in:
SSU-WEI HUANG
2026-07-12 18:42:55 +08:00
committed by GitHub
parent 474db94136
commit d97b270ba8
15 changed files with 1006 additions and 91 deletions
+18 -14
View File
@@ -1129,8 +1129,8 @@ describe('codexRemoteLauncher', () => {
expect(session.thinking).toBe(false);
});
it('uses live permission mode for app-server MCP elicitation handlers', async () => {
const { session, setPermissionMode } = createSessionStub();
it('routes app-server MCP elicitation through the existing user-input transport', async () => {
const { session, codexMessages, rpcHandlers, setPermissionMode } = createSessionStub();
const exitReason = await codexRemoteLauncher(session as never);
@@ -1156,14 +1156,24 @@ describe('codexRemoteLauncher', () => {
}
};
await expect(handler?.(request)).resolves.toEqual({
action: 'cancel',
content: null,
_meta: null
setPermissionMode('yolo');
const response = handler?.(request);
await vi.waitFor(() => {
expect(codexMessages).toContainEqual(expect.objectContaining({
type: 'tool-call',
name: 'request_user_input'
}));
});
const requestMessage = codexMessages.find((message) => (
typeof message === 'object' && message !== null && 'name' in message && message.name === 'request_user_input'
)) as { callId: string };
await rpcHandlers.get('permission')?.({
id: requestMessage.callId,
approved: true,
answers: { approval: { answers: ['allow'] } }
});
setPermissionMode('yolo');
await expect(handler?.(request)).resolves.toEqual({
await expect(response).resolves.toEqual({
action: 'accept',
content: {
approval: 'allow'
@@ -1171,12 +1181,6 @@ describe('codexRemoteLauncher', () => {
_meta: null
});
setPermissionMode('default');
await expect(handler?.(request)).resolves.toEqual({
action: 'cancel',
content: null,
_meta: null
});
});
it('sends Codex plan collaboration mode when the app-server advertises it', async () => {