본문 바로가기
C.W.K.
Stream
Lesson 03 of 05 · published

Root Directory Scope

~18 min · roots, scope, filesystem, sandboxing

Level 0호기심 많은 독자
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Primitive track 에서 Roots 를 client capability 로 만났었지 — host 가 server 한테 움직여도 되는 폴더를 알려주는 것. 이번엔 보안의 눈으로 다시 읽어보자. Roots 는 filesystem 을 만지는 server 가 엉뚱한 데를 돌아다니지 않게 막는 장치야.

Roots 가 없으면 filesystem MCP server 는 자기 활동 범위를 넘겨짚어야 해. $HOME 일까, 지금 폴더일까, user 가 쳐 넣은 그 경로일까. 어떤 짐작이든 누군가한테는 틀리고, 그 틀린 경우가 바로 'AI 가 내 SSH 설정을 건드렸다' 로 이어지는 사고야. Roots 가 있으면 host 가 대신 답해줘 — user 눈에 보이는 화면 (workspace, 열어둔 폴더, 직접 고른 경로) 이 지금 뭘 가리키는지를 근거로.

Protocol 상의 모양은 이래. Server 가 initialize 때 root 목록을 받아오고, 원하면 notifications/roots/listChanged 를 구독하고, 인자로 받은 경로가 지금 root 바깥이면 그 tool 호출을 거절해. 거절은 정중하게 — stack trace 말고 정돈된 에러로 — 해야 LLM 이 다음 turn 에 방향을 고칠 수 있어. 'root 바깥' 은 server 의 버그가 아니라 모델이 contract 를 어긴 거니까.

Code

Out-of-root path 거절·python
from pathlib import Path

def assert_in_roots(path_str: str, roots: list[str]):
    p = Path(path_str).resolve()
    for r in roots:
        if str(p).startswith(str(Path(r.replace('file://','')).resolve())):
            return
    raise PermissionError(f"path {p} is outside the active roots")

@app.tool()
async def read_file(path: str) -> str:
    roots = await app.request_context.session.list_roots()
    assert_in_roots(path, [r.uri for r in roots.roots])
    return open(path).read()
Root 변경 subscribe·python
# User 가 host 에서 workspace 바꾸면 roots/listChanged 발사.
# 받으면 scope 갱신; 공격적으로 cache하지 마.
@app.notification("notifications/roots/listChanged")
async def on_roots_changed(params):
    fresh = await app.request_context.session.list_roots()
    update_my_scope(fresh)

External links

Exercise

Filesystem 을 만지는 server 를 짜뒀다면, 활동 범위에 대해 숨어 있는 짐작을 ($HOME, 현재 폴더, 박아둔 경로) 전부 찾아봐. 각각을 요청 시점의 Roots 조회로 바꿔. 점검은 짧게 끝나는데 안전은 영구히 올라가.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.