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 한테 동작 허용 directory 알려줌. Security 렌즈로 다시 읽어: Roots 가 filesystem-만지는 server 의 의도치 않은 roaming 막는 방법.

Roots 없으면 filesystem MCP server 는 scope 에 대해 뭔가 가정 해야: 어쩌면 $HOME, 어쩌면 cwd, 어쩌면 user 가 친 거. 모든 가정이 어떤 user 에겐 틀리고, 그 틀린 케이스가 정확히 — 'AI 가 내 SSH config 썼어' 가 되는 — 사고 종류. Roots 와 함께면 host 가 — user-facing UX (workspace, 열린 폴더, picker) 가 active context 라고 말하는 거 — 에서 도출해 scope 답함.

Protocol 패턴: server 가 initialize 시 root list, optionally notifications/roots/listChanged subscribe, 인자 path 가 현재 root set 밖인 tool 호출 다 거절. 정중히 거절 — stack trace 아니고 구조화된 에러 — LLM 이 다음 turn 에 코스 수정 가능. 'root 밖' 은 server bug 아니고 모델의 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 X.
@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 짰으면 scope 에 대한 숨은 가정 ($HOME, cwd, hardcoded path) audit. 각각 request 시점 Roots query 로 교체. Audit 짧고 안전 개선 영구.

Progress

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

댓글 0

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

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