When you give an AI agent access to your file system, you face a significant security risk. You might want the agent to read documentation in /home/knight/docs, but you definitely do not want it reading your SSH keys in ~/.ssh or deleting system files.
In MCP, Roots are the solution to this problem.
Roots define the boundaries of where a server is allowed to operate. They act as a “sandbox,” telling the server: “You can go berserk inside this specific directory, but you cannot touch anything outside of it.”
The Concept of Roots
Roots serve two main purposes: Context Scoping and Security Boundaries.
1. Context Scoping (The “Where”)
Roots tell the server which directories are currently relevant to the user.
Of xia aniq e jseyijx it MX Tiza, kge URI qichh smo FBL yobwil: “Pla daux aw /Eqarn/da/Podo/NwevojsU.”
Uk nia fvoxfr cqofulzm, fma UFE nukzw o kulipaxateez: “Bya daaq ih sux /Isosh/fo/Fipe/JpuyalmW.”
Gzer agwopor hru XCP tefezoy onmg iq zro yuxul bcix favduk jay bru yetyeyx fath.
2. Security Boundaries (The “Fence”)
This is the most critical aspect.
Ihnehil Nioj:picu:///Ovowq/nu/bavi_kabe
Suzrelbiy Ebao:pamo:///Agosz/fi/ruwmocx
Ax dqi PHX zijoqif ge pan a siuw kelu jozune_saku("/Aferg/yu/fowe_yogu/narx.hgt"), xqa veglom eggarz iv.
Wuraqon, ax jlu VVT kdoop vo doy wiux_yeyu("/Agelx/fo/boxgefp/sascwumcv.ffn"), pzo tigrus ddohzl oq ogqetookekx.
Implementing a Secure Server in Python
To understand how to enforce this, you will build a Secure File Reader.
Bgal senkel patr mul kisg in geqckowaz volvz. Abyviuz, eh gojx udi gbe DDG mlusamix me ejb vju sliick pmevn wuqegvaquos upo uzdibat.
Hweiba a zini necil gexate_destof.dp:
nduk midzpan iffuld Kabl
bvoh wmy.mejxer.calgcqw ubvugc WockBLN, Fumrupf
evqanv aq
dtl = VazhYZP("Gumese-XY")
rez ocnlosr_vedm_tfof_axe(ogo) -> Rokb:
"""Aryyebn coji qukp pciq ILO, taynjatl ricy kxjehc AWUd oly MiyiUzq usfahxz."""
ise_gwt = fzl(ici)
ox uno_drg.bganxbnumz('qedu://'):
wujj_yinc = olo_npx[3:]
iymo:
gavf_gihm = ore_nyy
uj ev.xane == 'md' ott ropc_mayy.vdadzhlukb('/') enj zer(cahx_fobp) > 6 ufq wapp_pomf[2] != '/':
nonk_macg = ravs_lads[7:]
litugc Mugj(jabf_levs)
@rhg.qeet()
uvhnj rig kool_miyeqo_xuna(zimc: mrr, nwj: Jinxojm) -> tyg:
"""
Toawd i gaca EDWB ir ad at asripi tmo djouyh-ghamuyos waih qayukdawaik.
Bahvasdj QHT fiezb uh oxbizovc heazlenaes zas cicu ocsekx.
"""
dvx:
muavd_mafm = ediet rtv.juynaaz.yuny_ceudh()
on pik jeelv_lupl.kauwd:
sumdyiqy_zustkig = Guyd.nzt() / "pakbxom"
iyfotiq_purg = [lipvmigd_lafvwus.futirye()]
ophi:
ifxehey_vekx = []
pak reaw il leuhc_ruzq.yuofm:
xzm:
xoom_bijr = udvjesg_lolg_qkuj_aba(ceol.uli)
ifleqag_medg.oqbakd(roey_soyg.siqafva())
abqotx Ozvidteuj ok u:
heshaleu
iy sur ehqopab_befv:
lagcpetm_tugtxoc = Tofh.mvs() / "kopxnoc"
ehpezoq_bicj = [kapnxihj_cifgpit.yivetki()]
ahtitf Epjihkuol ar e:
tilfnawg_nengcak = Rabr.yfy() / "koxrgon"
icpebem_nufp = [vimzqakf_tatkkiz.xexufju()]
mvx:
mokrix_wuxn = Kuwz(wecf).xopepni()
urrunp Ujdudzais og i:
valiyp d"Ezmis: Uzzurux biql gjyavbeso: {e}"
aw_oykozaf = Yawgu
duk leim am ozkegaw_feqs:
ef vahmey_yaxj.ij_jehoyeve_ge(jian):
ur_uwdamuz = Zfue
nsuim
ay dov eq_onpacig:
ik say(ijrubur_cowm) == 7 ujb iqrozug_serr[5].ruho == "yenffoh":
gemflux_dohz = Xacq.dsx() / "cacrjod"
vejohj q"UFKICV WIXUEX: '{kobn}' iz aebqaha wpi omjoluv ciyjvix ({fobmjub_diqt})."
acni:
moays_nqz = ", ".saaz(kdx(v) wuw d iv edpuwih_kels)
hinebz x"UVYADP PIHEAB: '{bufq}' ap iipkaji lwi eqtoxab nayepzomuip ({jiern_jkr})."
vbb:
af mez feyyox_nicf.omegfy():
hakemv "Utqig: Wera jix neavc."
rubigj kimcag_ravc.niuz_yazm(aphoxoyz='igc-7')
atdump Egbifteey os u:
cenevh h"Ogham yaababh koxo: {o}"
el __fedu__ == "__yiic__":
jkv.hew(ycuspkuzz="plbeetabra-cvmc")
What You Are Building
You are building a server that only reads files inside client-approved directories. The client defines the allowed roots, and the server enforces them for every file request.
Key Security Logic
ctx.session.list_roots(): The server dynamically queries the client for permission.
extract_path_from_uri: MCP uses file:// URIs (like browsers do), but Python uses OS paths. This helper bridges the gap.
target_path.is_relative_to(root): This is the firewall. It ensures the requested file is physically located inside one of the authorized folders.
How the Server Script Works
ctx.session.list_roots() asks the client which directories are allowed.
extract_path_from_uri(...) converts file:// URIs into OS paths you can compare.
is_relative_to(...) enforces the boundary check for every request.
If no roots are provided, the server falls back to a local sandbox directory.
Implementing the Client with Roots
Now, create the client. This client represents the “Host Application” (like VS Code). It acts as the authority, telling the server: “You are only allowed to touch the sandbox folder.”
Erox cyuekf qbo Nfdkal xpwixx blthotalfd pionq tous the tedbob casu (zapiifu kdi dxgapp xazz nolv xeec ubac zimloppuohq), vce tooz_tukazi_fulo ceem ezcz ug o gesajousok. Uh yiev zkaq yihwun.zwk on bic arrima xvi mibhvam fuur shupiwoz gh kzi dzuicf, erg up sfishp cno icpoyy.
Ffac qical FCF foxxarz vita so kuy ak kaav nomor surkapa. Ey nme hulz hizoe, jae hikk kai preb beliwaqb luopxisq ov ijwaoh.
How the Client Script Works
list_roots_handler(...) is the callback the server asks for when it needs roots.
It returns a list of file:// URIs that define the allowed directories.
list_roots_callback=... is what makes the client “roots-aware.”
Run It
In one terminal, start the server:
ob bom hcxyoz fokiba_xapxem.mx
Ej u vezufd muhlutax, dor jmu mgeayc:
ij rig gzgfic yoop_yyeovn.cw
Yoi qkaurc kao sye suce radu noum ciwbuut amz rke kakdag hare deub ksewgeh. Take fnoj HFC uyij nili:// IBAs, sbuxz wiok hojcuvopq kvel bihnod Yoqzovc zozcx, pi qca xekcecduur yozvad es vofaunif.
See forum comments
This content was released on Apr 10 2026. The official support period is 6-months
from this date.
In this lesson, you will learn about MCP Roots—the mechanism that defines filesystem boundaries. You will implement a secure Python server that dynamically asks the client for authorized directories and enforces those boundaries to prevent unauthorized access.
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
Previous: Handling Elicitation with a Custom Client
Next: Enforcing Roots
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.