मुख्य सामग्री पर जाएं
टूल्स एजेंट्स को आपके Python फ़ंक्शन्स को कॉल करने की सुविधा देते हैं। डेकोरेट करें, रजिस्टर करें, सर्व करें। टूल्स वे मूलभूत बिल्डिंग ब्लॉक्स हैं जो किसी मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP) Client को MCP प्रोटोकॉल के ज़रिए आपके Python फ़ंक्शन्स को invoke करने देते हैं:
  1. कोई Client tools/list के ज़रिए टूल्स खोजता है (हर tool में inputSchema और वैकल्पिक outputSchema शामिल होता है)।
  2. कोई Client tools/call के ज़रिए किसी tool को ऐसे arguments के साथ कॉल करता है जो schema से मेल खाते हों।
  3. सर्वर आपके callable को execute करता है।
  4. सर्वर MCP Spec के अनुसार content (और वैकल्पिक structuredContent) के साथ CallToolResult वापस करता है।

बेसिक tool

from dedalus_mcp import MCPServer, tool

@tool(description="दो संख्याएँ जोड़ें")
def add(a: int, b: int) -> int:
    return a + b

server = MCPServer("math")
server.collect(add)
यह विवरण LLM को बताता है कि tool क्या करता है। टाइप हिंट्स JSON Schema में बदल जाते हैं।

असिंक्रोनस टूल्स

import anyio
from dedalus_mcp import tool

@tool(description="उपयोगकर्ता डेटा प्राप्त करें (सिम्युलेटेड I/O)")
async def get_user(user_id: str) -> dict:
    await anyio.sleep(0.1)
    return {"user_id": user_id, "status": "ok"}
I/O के लिए async को प्राथमिकता दें। महत्वपूर्ण: Dedalus मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP) में, sync टूल्स इनलाइन चलते हैं (उन्हें अपने‑आप thread pool में नहीं भेजा जाता)। यदि आपको blocking काम के लिए concurrency चाहिए, तो async def का उपयोग करें और काम को स्पष्ट रूप से offload करें।

प्रकार अनुमान

टाइप हिंट अपने‑आप JSON Schema में बदल जाते हैं:
from typing import Literal
from pydantic import BaseModel
from dedalus_mcp import tool

class SearchFilters(BaseModel):
    category: str | None = None
    min_price: float = 0.0

@tool(description="उत्पादों को खोजें")
def search(
    query: str,
    limit: int = 10,
    sort: Literal["relevance", "price", "date"] = "relevance",
    filters: SearchFilters | None = None,
) -> list[dict]:
    return [{"query": query, "limit": limit, "sort": sort, "filters": filters.model_dump() if filters else None}]
समर्थित: primitives, list, dict, Literal, Enum, optionals/unions, Pydantic models, dataclasses, nested models। आवश्यक parameters के लिए कोई default मान नहीं होता। वैकल्पिक parameters के लिए एक default मान होता है।

डेकोरेटर विकल्प

from dedalus_mcp import tool

@tool(
    name="find_products",           # tool का नाम ओवरराइड करें
    description="Search catalog",   # tool का विवरण
    tags={"search", "catalog"},     # फ़िल्टरिंग/मेटाडेटा के लिए
)
def search_products_impl(query: str) -> list[dict]:
    return [{"id": "p_1", "name": "Widget", "query": query}]

संरचित रिटर्न

ऐसे मान लौटाएँ जिन्हें JSON में serialise किया जा सके:
from dedalus_mcp import tool

@tool(description="टेक्स्ट का विश्लेषण करें")
def analyze(text: str) -> dict:
    return {"word_count": len(text.split()), "char_count": len(text)}
स्पष्ट नियंत्रण के लिए CallToolResult लौटाएँ:
from dedalus_mcp import tool
from dedalus_mcp.types import CallToolResult, TextContent

@tool(description="Custom result")
def custom() -> CallToolResult:
    return CallToolResult(
        content=[TextContent(type="text", text="Custom message")],
        isError=False,
    )

कॉन्टेक्स्ट एक्सेस

लॉगिंग और प्रगति के लिए get_context():
import anyio
from dedalus_mcp import tool, get_context

@tool(description="प्रगति रिपोर्टिंग के साथ फ़ाइलों को प्रोसेस करें")
async def process_files(paths: list[str]) -> dict:
    ctx = get_context()
    await ctx.info("प्रारंभ हो रहा है", data={"count": len(paths)})

    processed = 0
    try:
        async with ctx.progress(total=len(paths)) as tracker:
            for path in paths:
                # कार्य का अनुकरण; रद्दीकरण को टास्क रद्दीकरण के रूप में प्रदान किया जाता है
                await anyio.sleep(0.01)
                processed += 1
                await tracker.advance(1)
    except anyio.get_cancelled_exc_class():
        await ctx.warning("रद्द कर दिया गया", data={"processed": processed})
        raise

    return {"processed": processed}

अनुमति सूचियाँ

दृश्यमान टूल्स को सीमित करें:
from dedalus_mcp import MCPServer, tool

@tool(description="जोड़ना")
def add(a: int, b: int) -> int:
    return a + b

@tool(description="गुणा करना")
def multiply(a: int, b: int) -> int:
    return a * b

server = MCPServer("gated")
server.collect(add, multiply)
server.allow_tools({"add"})
किसी छिपे हुए tool को कॉल करने पर CallToolResult नामक त्रुटि लौटती है, जो संकेत करती है कि वह tool उपलब्ध नहीं है।

त्रुटि हैंडलिंग

Exceptions को सामान्य रूप से raise करें:
from dedalus_mcp import tool

@tool(description="Divide")
def divide(a: float, b: float) -> float:
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

परीक्षण

tool को सामान्य functions की तरह ही परीक्षण करें:
def test_add():
    assert add(2, 3) == 5
context का उपयोग करने वाले टूल्स के लिए, core logic को अलग से टेस्ट करें (या integration-style harness का उपयोग करें)।