OpenAI Codex · Code Mode

모델이 보는 도구 목록은 샘플 한 번으로 계산됩니다

같은 대화, 같은 설정인데도 다음 샘플에는 MCP 이름, 협업 입구, 또는 tool_search가 더 붙을 수 있어요. 바뀌는 건 이번 요청이 광고해도 되는 handler입니다.

강의 목표읽고 나면 세 가지를 말할 수 있어요. 첫째, 도구 목록은 샘플 한 번에 얼고, MCP가 중간에 떨어져도 이미 보낸 표는 안 바뀝니다. 둘째, 계획은 신분으로 출처를 자르며, 등록됐다고 보이는 건 아니에요. 셋째, 검색을 켜면 비싼 MCP schema는 지연 발견으로 물러나고 tool_search만 남습니다.
먼저 해보기 · 스위치를 돌려, 이번 라운드 메뉴가 어떻게 바뀌는지 보기
같은 세션: 조건이 바뀌면 모델이 이번 라운드에 보는 표가 다시 계산됩니다
조건
왼쪽이 이번 라운드 입력이에요. 재생을 눌러 소스 순서대로 걷거나, 직접 스위치를 돌려도 됩니다.
모델에 보내는 메뉴0개 보임0자 설명
이번 라운드는 얼었어요. 끊겨도 이 표는 안 바뀝니다
등록됐지만 안 보임0
논리 궤적 · 애니메이션 한 걸음이 소스 어디에 대응하는지
  1. 이번 step의 MCP 바인딩을 해석mcp.rs L310
  2. MCP 목록을 모아 계획 함수에 넘김turn.rs L1494
  3. 신분으로 전체 출처를 탈지 정함spec_plan.rs L889
  4. shell, 리소스, 유틸, 협업을 등록spec_plan.rs L930
  5. MCP를 붙이고 노출 정책을 씌움spec_plan.rs L148
  6. deferred가 있을 때만 tool_search를 걺spec_plan.rs L335
  7. is_direct인 spec만 모델에 보냄spec_plan.rs L484
  8. StepContext.tool_router에 얼림step_context.rs L44
  9. build_prompt가 보이는 표를 읽음turn.rs L1320
재생을 누르세요. 같은 세션에서 스위치를 몇 개 돌리면 이번 라운드 메뉴가 어떻게 늘고 주는지를 봐요.
메뉴는 어디서 오나환경이 있고 ShellTool과 UnifiedExec가 켜져 있으면, 먼저 shell 두 점이 올라와요. MCP가 연결되면 리소스 입구와 정규화된 외부 이름이 붙습니다.
보이는 것과 등록된 것검색을 켜면 비싼 MCP schema는 회색 구역으로 물러나고, 초기 표는 tool_search로 바뀌어요. 심사원은 출처 묶음 전체를 건너뛰고, Managed가 아니면 표는 비어 있습니다.
끊김이 바꾸는 라운드샘플 도중에 끊겨도 이미 보낸 메뉴는 안 움직여요. 다음 라운드가 빈 바인딩으로 다시 계산해야 그 이름들이 사라집니다.
수업용 시연: 스위치 조합과 설명 길이는 수업용 설정이고, 계획 순서는 build_tool_router에 맞춰 있어요. 논리 궤적 오른쪽 행 번호는 openai/codex 저장소 commit 4f39251a01에 대응합니다.
아이디어 1 · 샘플 한 번에 얼리기
어떤 문제를 푸는가

방금 MCP filesystem을 붙였는데, 모델은 이번 라운드를 아직 달리고 있어요. 사용자 대화 한 턴 단위로 도구 표를 얼리면, 새로 붙은 서버는 다음 사용자 메시지를 기다려야 메뉴에 들어갑니다. 도구를 부를 때마다 얼리면, 같은 샘플 안의 병렬 호출 둘이 서로 다른 표를 볼 수 있어요.

광고한 표와 실행하는 표가 다르거나, 실행 중에 표가 바뀌는 것이 도구 표가 가장 자주 뒤집히는 방식이에요.

아이디어는 무엇인가

Codex는 이번 샘플의 모델, 승인, 환경, MCP 바인딩, 이미 계산된 tool_router를 함께 StepContext에 넣어요. 주석은 request-scoped라고 적습니다. 샘플 요청 사이에는 바뀌어도, 한 샘플 안에서는 안 바뀌어요. tool_router는 this exact sampling request의 계획입니다.

샘플이 도는 동안 모델이 보는 이름과 dispatch할 runtime은 모두 이 스냅샷을 읽어요. MCP 서버가 이번 샘플 도중에 떨어져도 이미 계산된 표는 안 바뀝니다. 다음 샘플은 mcp_runtime_for_step을 다시 타고, 바인딩은 재사용되거나 빈 바인딩으로 바뀔 수 있어요.출처:codex-rs/core/src/session/step_context.rs 17–47행;codex-rs/core/src/session/mcp.rs 348–357행

MCP 바인딩 이번 step의 목록 build_tool_router 신분으로 계획 StepContext router를 얼림 Prompt.tools 모델에 보냄 중간에 끊겨도 이 스냅샷은 안 바뀜 다음 샘플이 바인딩을 다시 해석하고, 빈 바인딩이면 MCP 이름을 안 걺
수업용 구조도: 동결은 샘플 경계에서 일어나요. 광고와 실행이 같은 router를 읽습니다.

그래서 동결 단위는 step이지 turn이 아니에요. 한 turn 안에 샘플이 여러 번 있을 수 있고, 매번 StepContext를 다시 만듭니다.출처:codex-rs/core/src/session/turn.rs 1318–1320행

왜 오래가는가

보이는 것과 실행 가능한 것이 스냅샷 하나를 공유하고, 다음 라운드가 새 연결을 흡수해요. 다른 언어로 다시 써도 최소 형태는 함수 하나입니다. 스위치, MCP 목록, 신분을 넣고, 보이는 표와 실행 표를 내놓으며, 요청이 시작할 때 한 번 계산하고 끝나면 얼립니다.

아이디어 2 · 신분으로 출처를 자르기
어떤 문제를 푸는가

승인 모델이 작업 모델의 MCP와 협업 도구 표 전체를 보면 spawn_agent를 하거나 외부 자원을 읽을 수 있어, 승인 자체가 우회됩니다. 전체를 등록한 뒤 걸러내면, 분기 하나만 빠져도 주면 안 되는 이름이 나갑니다.

아이디어는 무엇인가

계획 함수는 신분으로 어떤 출처를 탈지 정해요. Guardian 심사원 라벨은 정확히 guardian이어야 합니다. 권한 프로필이 Managed가 아니면 함수는 바로 돌아가고 레지스트리는 비어 있어요. Managed이고 환경이 있으면 최대 세 점입니다. exec_command, write_stdin, 선택 view_image. 일반 세션만 shell, MCP 리소스, 유틸, 협업 네 묶음을 타고, 그다음 MCP, 확장, 동적 도구를 붙입니다.출처:codex-rs/core/src/guardian/review.rs 212–220행;codex-rs/core/src/tools/spec_plan.rs 144–164행、889–934행

디스크 읽기에도 일등 입구가 없어요. handlers 디렉터리에 ReadFileHandler가 없습니다. 모델이 파일을 읽으려면 exec_command, MCP filesystem, 또는 view_image 안의 exec-server API를 탑니다.

왜 오래가는가

신분이 바뀌면 출처 묶음 전체를 안 타요. 기본으로 문을 닫는 곳은 심사원, 환경 없음, 기능 끔이고, 다른 언어에도 그대로 씁니다.

아이디어 3 · 등록됐다고 보이는 건 아니에요
어떤 문제를 푸는가

MCP 도구 schema는 비싸요. 전부 걸면 첫 요청의 토큰을 설명 텍스트가 먹습니다. 서버 둘이 모두 read_file을 주면, 이름을 가리지 않으면 충돌해요.

아이디어는 무엇인가

노출 상태가 레지스트리를 보이는 면 몇 갈래로 나눕니다. Direct는 초기 표에 들어가요. Deferred는 tool_search에만 남기고, Hidden은 dispatch에만 남깁니다. 검색이 켜져 있으면 MCP 도구는 기본 Deferred라 초기 가시 표에 안 들어가요.출처:codex-rs/tools/src/tool_executor.rs 51–80행;codex-rs/core/src/mcp_tool_exposure.rs 90–94행

finalize_tool_router는 두 가지가 동시에 성립할 때만 tool_search를 겁니다. 모델이 search tool을 지원하고, 레지스트리에 deferred이면서 search_info가 있는 도구가 하나라도 남아 있어야 해요. deferred가 없으면 표에 안 들어갑니다.출처:codex-rs/core/src/tools/spec_plan.rs 335–370행、578–580행

등록됨 dispatch 가능 Direct · 초기 표 Deferred · 먼저 검색하고 봄 Hidden · 실행에만 남김 Prompt.tools tool_search의 검색 면 모델은 못 보지만, 호출하면 맞힐 수 있음
수업용 대조: 같은 레지스트리를 바로 보임, 지연 발견, 실행만 가능 세 면으로 나눕니다.

MCP 서버 둘의 같은 이름 도구는 정규화 단계에서 가려요. 기본은 mcp__ 접두사고, sanitize 뒤에도 부딪히면 12자리 해시 접미사를 붙입니다. 외부 도구가 이미 쓰인 핵심 이름과 부딪히면 그냥 건너뛰어요. 저장소 루트 AGENTS.md는 아직 mcp_connection_manager.rs를 적지만, 지금 트리에는 그 파일이 없고 이름 가리기는 tools.rs에 있습니다.출처:codex-rs/codex-mcp/src/tools.rs 1–5행、113–151행;AGENTS.md 35행

등록돼도, 이번 라운드에 모델로 보냈다는 뜻은 아니에요.
왜 오래가는가

보이는 것, 검색 가능한 것, 실행 가능한 것은 집합 셋이에요. 토큰 예산이 빠듯하면 발견을 미루고, 핵심 이름은 지키며 외부가 길을 양보합니다. 이건 Rust에 매이지 않아요.

가로 비교 · 같은 문제의 다른 답

DeepSeek Harness: 플러그인이 조립기에 schema를 던짐

DSH에는 중앙 계획 함수가 없어요. 도구 팩마다 assemble 때 systemPrompt.tools()로 schema를 던지고, 조립기가 배포 설정의 toolOrder로 자리를 잡습니다. 이름이 안 불린 도구는 예약 표시 <unlisted-tools>에 이름 사전순으로 끼어요. 이 표시를 빼먹으면 assemble이 바로 실패합니다.

@deepseek-ai/dsh-tool-fs를 얹으면 모델이 일등 도구 read를 봐요. 설명은 텍스트를 이걸로 읽으라고 합니다. Codex는 디스크 읽기를 shell, MCP, 내부 API에 맡기고, 계획 함수에는 read_file 입구가 없어요.

양쪽 모두 소스 대조 완료 · 2026-08-22 · DSH · 도구 순서 중심 목록

Claude Code: 정적 기본 표 더하기 MCP, 내장이 우선

getAllBaseTools는 박아 둔 배열이고 FileReadTool은 일등 멤버예요. 요청 때 assembleToolPool이 먼저 deny 규칙을 걸러, 내장과 MCP를 이름순으로 각각 정렬한 뒤 이어 붙입니다. 내장이 앞이고, 이름이 부딪히면 내장이 이겨요. 주석은 이 순서가 prompt cache 때문이라고 적습니다. MCP를 내장 가운데 끼우면 뒤 cache key가 전부 죽어요.

Claude Code 기본 표는 파일 하나만 열면 셀 수 있어요. Codex 목록을 세려면 add_core_tool_sources를 끝까지 걸어야 합니다. 같은 계획이 신분과 예산으로 자를 수 있어요.

양쪽 모두 소스 대조 완료 · 2026-08-22
수업 실습
01

이번 라운드 메뉴에 뭐가 남나

먼저 MCP와 검색을 켜고, mcp__filesystem__read_file이 회색 구역에, tool_search가 메뉴에 있는지 확인하세요. 그다음 세 박자를 추론합니다. 검색은 켠 채 MCP가 전부 Hidden이 되고, 샘플 도중에 끊기고, 다음 샘플을 탑니다. 박자마다 가시 표, 회색 구역, tool_search가 있는지를 적으세요.

심화 한 질문: 신분을 Guardian 심사원으로 바꾸고, 권한은 먼저 Managed였다 다른 값으로 바꿉니다. 메뉴는 각각 무엇이고, 왜 도구를 몇 개 덜 거는 게 아닌가요.

Takeaway:계획 함수가 무엇을 광고할지 정하고, 레지스트리가 무엇을 dispatch할 수 있는지 정하며, 노출 상태가 직접·지연·숨김을 정해요. StepContext가 그것들을 샘플 경계에 얼립니다. 표에 read_file이 없어도 모델은 exec_command로 파일을 읽을 수 있어요.