fix(mcp): 조회 전용 프로필로 원본 문서를 덮어쓸 수 있다 — 세션 축 권한 경계 이탈 (#3629 후속) - #3723
Closed
kevin9327 wants to merge 1 commit into
Closed
fix(mcp): 조회 전용 프로필로 원본 문서를 덮어쓸 수 있다 — 세션 축 권한 경계 이탈 (#3629 후속)#3723kevin9327 wants to merge 1 commit into
kevin9327 wants to merge 1 commit into
Conversation
프로필의 세션 축이 bool 하나라, 조회 전용 직무가 세션을 쓰려면 편집·저장 4종까지 통째로 열렸다. 실측: --profile 아카이브검색(허용 도구 7종에 쓰기 도구 0개)으로 hwp_open → hwp_doc_save 를 이어 원본 문서를 덮어썼다(31232 → 18432 바이트). tools/list 는 19종을 냈고 capabilities --mcp --profile 은 7종을 선언해 선언과 서버도 어긋나 있었다. - AgentProfile.session: bool → session_tools: Option<&[&str]> (None=세션 없음, Some(&[])=필터 없음, Some(목록)=그 목록만 — tools 와 같은 규약) - SESSION_READ_TOOLS 상수: 문서를 바꾸지 않는 8종. render_page 는 새 산출물만 쓰므로 조회 축에 남긴다 - served_tools 와 handle_tool_call 이 **같은 판정 함수**(allows_session_tool)를 쓴다 — 목록에서 뺀 도구를 호출로 우회할 수 없다 - capabilities --mcp --profile 에 sessionTools 선언 추가 (선언=실물) - 계약 테스트 2종: 목록·호출 두 층 모두 쓰기 도구 차단, 자기서술 일치 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jangster77
self-requested a review
August 1, 2026 14:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
mcp-serve --profile 아카이브검색(대량 RAG·감사용 조회 전용 직무, 허용 도구 7종에 쓰기 도구가 하나도 없습니다)으로 원본 문서를 덮어쓸 수 있습니다. 실측:동시에 선언과 서버가 어긋납니다 —
capabilities --mcp --profile 아카이브검색은 7종을 선언하는데 서버는 19종을 냅니다.원인
프로필의 세션 축이
bool하나였습니다.served_tools는 그 불리언이 참이면 12종을 무조건 push 하고, 호출 게이트도!include_session && is_session_tool(name)이라 같은 구멍을 그대로 물려받습니다. 그래서 "조회는 세션으로 반복하되 쓰기는 안 함"이라는 직무를 표현할 방법 자체가 없었고, 그 직무가 세션을 켜는 순간 편집·저장 4종이 딸려 왔습니다.mcp_serve.rs의 주석이 정확히 이 계약을 선언하고 있습니다:선언된 경계(7종)와 강제되는 경계(19종)가 달랐습니다.
가드가 놓친 이유:
tests/agent_profile_router_contract.rs는행정서식(세션+편집 의도)과데이터분석(세션 off) 두 가지만 시험합니다 — 조회 전용인데 세션은 켜는 조합이 미시험이었습니다.수정
SESSION_READ_TOOLS상수: 문서를 바꾸지 않는 8종(hwp_open/hwp_doc_text/hwp_doc_info/hwp_doc_fields/hwp_doc_tables/hwp_doc_search/hwp_doc_render_page/hwp_close).hwp_doc_render_page는 SVG 를 쓰지만 대상이 호출자가 지정한 새 산출물이지 원본 문서가 아니라 조회 축에 남겼습니다.served_tools와handle_tool_call이 같은 판정 함수(allows_session_tool)를 씁니다. 둘이 갈라지면 경계가 다시 뚫리므로 배선을 하나로 모았습니다.capabilities --mcp --profile에sessionTools를 실어 선언이 실물과 같아지게 했습니다.session: false인 프로필은null입니다.프로필별 결과:
행정서식·개발통합→ 전 세션 도구(변화 없음),아카이브검색→ 조회 8종, 나머지 4종 → 세션 없음(변화 없음).AFTER — 같은 시나리오
회귀 가드 2종
readonly_profile_serves_no_session_write_tools— 목록과 호출 두 층을 함께 봅니다. 조회 도구(hwp_open/hwp_doc_search)는 열려 있어야 하고(이 프로필의 레시피가 씁니다), 쓰기 4종은tools/list에 없고tools/call로도 안 들어가야 합니다.capabilities_declares_the_session_tools_it_actually_serves— 선언=실물. 매니페스트로 도구 정의를 자동 생성하는 소비자(cli_json_pipeline_guide.md가 문서화한 경로)가 실물과 다른 표면을 얻지 않도록 고정합니다.검증
cargo test --test agent_profile_router_contract— 7/7 (신규 2종 포함)mcp_server_contract22/22 ·mcp_session_edit_contract6/6 ·cli_json_contract5/5 — 무회귀cargo clippy --profile release-test --bin rhwp— 경고 0 /cargo fmt --check— 통과--profile 아카이브검색로 stdio 구동해 before/after 대조호환성
session: bool은pub필드였으므로 형식상 파괴적 변경이지만,agent_profiles를 소비하는 곳은 저장소 안에main.rs·mcp_serve.rs둘뿐이고 둘 다 이 PR 에서 갱신했습니다. 봉투 쪽은profile.session(불리언)이 그대로 남고sessionTools가 추가되므로 기존 소비자는 계속 파싱됩니다.🤖 Generated with Claude Code