मुख्य सामग्री पर जाएं
रूट्स वे फ़ाइल सिस्टम सीमाएँ हैं जिन्हें Client द्वारा घोषित किया जाता है। सर्वर रूट्स का उपयोग यह समझने के लिए कर सकते हैं कि Client के फ़ाइल सिस्टम के कौन‑कौन से हिस्से इन‑स्कोप माने गए हैं (उदाहरण के लिए, “यह प्रोजेक्ट फ़ोल्डर”), और फ़ाइलों को पढ़ते या लिखते समय गार्डरेल लागू कर सकते हैं मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP) में, रूट्स एक Client capability (roots/list) होती है। Dedalus MCP एक सर्वर‑साइड RootsService प्रदान करता है जो:
  • Client से रूट्स फ़ेच करता है,
  • प्रति‑सेशन स्नैपशॉट को कैश करता है, और
  • पाथ जाँच के लिए RootGuard हेल्पर उपलब्ध कराता है।

बुनियादी उपयोग

वर्तमान सत्र के लिए नवीनतम रूट्स प्राप्त करें, फिर उन्हें उपयोग करें:
from dedalus_mcp import get_context, tool

@tool(description="Client रूट्स की सूची बनाएं")
async def list_roots() -> list[str]:
    ctx = get_context()
    server = ctx.server
    if server is None:
        raise RuntimeError("कॉन्टेक्स्ट में कोई सक्रिय सर्वर नहीं है")

    roots = await server.roots.refresh(ctx.session)  # Client से प्राप्त करें
    return [f"{r.name}: {r.uri}" for r in roots]
आपको हर बार फिर से फ़ेच करने की ज़रूरत नहीं है; आप कैश किया हुआ स्नैपशॉट पढ़ सकते हैं:
roots = ctx.server.roots.snapshot(ctx.session)

रूट संरचना

प्रत्येक रूट में निम्न शामिल होते हैं:
फ़ील्डप्रकारविवरण
uristrरूट URI (आमतौर पर file:// URI)
namestrमानव-पठनीय नाम

उदाहरण: सुरक्षित फ़ाइल ऑपरेशन (RootGuard)

RootGuard का उपयोग करके जाँचें कि दिया गया path अनुमत roots में से किसी एक के भीतर है या नहीं:
from pathlib import Path
from dedalus_mcp import get_context, tool

@tool(description="फ़ाइल पढ़ें, रूट्स तक सीमित")
async def safe_read(filepath: str) -> str:
    ctx = get_context()
    server = ctx.server
    if server is None:
        raise RuntimeError("संदर्भ में कोई सक्रिय सर्वर नहीं")

    # सुनिश्चित करें कि हमारे पास नवीनतम स्नैपशॉट है
    await server.roots.refresh(ctx.session)

    guard = server.roots.guard(ctx.session)
    target = Path(filepath).expanduser().resolve()

    if not guard.within(target):
        raise ValueError("पथ अनुमत रूट्स के बाहर है")

    return target.read_text(encoding="utf-8")

उदाहरण: प्रोजेक्ट खोज (file:// रूट्स)

यदि आपके Client रूट्स file://... URI हैं, तो आप उन्हें ट्रैवर्स (walk) करके प्रोजेक्ट खोज सकते हैं।
from pathlib import Path
from urllib.parse import urlparse, unquote

from dedalus_mcp import get_context, tool

def file_uri_to_path(uri: str) -> Path:
    parsed = urlparse(uri)
    if parsed.scheme != "file":
        raise ValueError(f"Unsupported root scheme: {parsed.scheme!r}")
    return Path(unquote(parsed.path)).expanduser().resolve()

@tool(description="मार्कर फ़ाइलों के आधार पर प्रोजेक्ट रूट खोजें")
async def find_projects() -> list[dict]:
    ctx = get_context()
    server = ctx.server
    if server is None:
        raise RuntimeError("No active server in context")

    roots = await server.roots.refresh(ctx.session)
    projects: list[dict] = []

    for root in roots:
        root_path = file_uri_to_path(str(root.uri))

        for marker in ["package.json", "pyproject.toml", "Cargo.toml"]:
            if (root_path / marker).exists():
                projects.append(
                    {
                        "root": root.name,
                        "path": str(root_path),
                        "type": marker,
                    }
                )

    return projects

केवल निर्दिष्ट roots के भीतर खोज करें (और जो आप कर रहे हैं उसे लॉग करें):
from pathlib import Path
from urllib.parse import urlparse, unquote

from dedalus_mcp import get_context, tool

def file_uri_to_path(uri: str) -> Path:
    parsed = urlparse(uri)
    if parsed.scheme != "file":
        raise ValueError(f"Unsupported root scheme: {parsed.scheme!r}")
    return Path(unquote(parsed.path)).expanduser().resolve()

@tool(description="रूट के भीतर फ़ाइलें खोजें")
async def search_files(pattern: str) -> list[str]:
    ctx = get_context()
    server = ctx.server
    if server is None:
        raise RuntimeError("No active server in context")

    roots = await server.roots.refresh(ctx.session)
    await ctx.info("Searching roots", data={"roots": len(roots), "pattern": pattern})

    matches: list[str] = []
    for root in roots:
        await ctx.debug("Searching root", data={"root": root.name, "uri": str(root.uri)})
        root_path = file_uri_to_path(str(root.uri))

        for match in root_path.rglob(pattern):
            matches.append(str(match))

    await ctx.info("Search complete", data={"matches": len(matches)})
    return matches

नोट्स

  • कैशिंग: server.roots.snapshot(session) कैश की गई roots लौटाता है। await server.roots.refresh(session) client को कॉल करके कैश को अपडेट करता है।
  • Client‑driven अपडेट्स: अगर client roots/list_changed भेजता है, तो Dedalus MCP उस session के लिए snapshot अपने आप (debounced) अपडेट कर देता है।
  • सुरक्षा: roots मार्गदर्शन के साथ‑साथ आपकी अपनी जाँचों के लिए एक boundary के रूप में काम करते हैं। अगर आप file I/O कर रहे हैं, तो पढ़ने/लिखने से पहले हमेशा एक guard (RootGuard.within(...)) लागू करें।