Skip to content

datarobot_genai.drmcputils.tool_gallery

Tool gallery utilities — shared between MCP servers and the ARD catalog.

This module has no fastmcp dependency and no MCP-protocol imports so it can be imported by drtools, drmcputils, and drmcpbase alike.

hosted_kind

hosted_kind(tool_category: str | None) -> dict[str, str] | None

Return the gallery classification for a hosted tool, or None if it isn't hosted.

Source code in datarobot_genai/drmcputils/tool_gallery.py
def hosted_kind(tool_category: str | None) -> dict[str, str] | None:
    """Return the gallery classification for a hosted tool, or None if it isn't hosted."""
    if not tool_category:
        return None
    return _HOSTED_TOOL_KINDS.get(tool_category)

is_hosted

is_hosted(tool: Any) -> bool

Return True for dynamic/proxied tools — those carrying a hosted tool_category.

Source code in datarobot_genai/drmcputils/tool_gallery.py
def is_hosted(tool: Any) -> bool:
    """Return True for dynamic/proxied tools — those carrying a hosted ``tool_category``."""
    return hosted_kind(_tool_category(tool)) is not None

merge_tool_info

merge_tool_info(tool: Any, ui_metadata: dict[str, dict[str, Any]]) -> dict[str, Any]

Combine a FastMCP Tool with drtools UI metadata + derived categories.

Carries the raw tool_category marker and the tool's own description so the builder can classify hosted tools (provider/categories) and fall back to the MCP description when there is no curated UI copy.

Source code in datarobot_genai/drmcputils/tool_gallery.py
def merge_tool_info(tool: Any, ui_metadata: dict[str, dict[str, Any]]) -> dict[str, Any]:
    """Combine a FastMCP ``Tool`` with drtools UI metadata + derived categories.

    Carries the raw ``tool_category`` marker and the tool's own ``description`` so the
    builder can classify hosted tools (provider/categories) and fall back to the MCP
    description when there is no curated UI copy.
    """
    ui = ui_metadata.get(tool.name, {})
    return {
        "name": tool.name,
        "display_name": ui.get("display_name"),
        "description_ui": ui.get("description_ui"),
        "description": getattr(tool, "description", None),
        "auth_provider": ui.get("auth_provider"),
        "tags": sorted(tool.tags or []),
        "categories": categories_for_tool(tool.name),
        "tool_category": _tool_category(tool),
        "hosted": is_hosted(tool),
    }
build_tool_gallery_items(tools: list[dict]) -> list[dict]

Build the tools-gallery JSON response items from merged tool dicts.

Each dict in tools should contain at minimum name and hosted. All other keys are optional and fall back to safe defaults.

Parameters:

Name Type Description Default
tools list[dict]

List of dicts with merged FastMCP tool attrs + drtools metadata.

required
Serialisable list of tool gallery item dicts.
Source code in datarobot_genai/drmcputils/tool_gallery.py
def build_tool_gallery_items(tools: list[dict]) -> list[dict]:
    """Build the tools-gallery JSON response items from merged tool dicts.

    Each dict in *tools* should contain at minimum ``name`` and ``hosted``.
    All other keys are optional and fall back to safe defaults.

    Args:
        tools: List of dicts with merged FastMCP tool attrs + drtools metadata.

    Returns
    -------
        Serialisable list of tool gallery item dicts.
    """
    items: list[dict] = []
    for t in tools:
        kind = hosted_kind(t.get("tool_category"))
        if kind is not None:
            # Hosted (dynamic) tool: classification comes from its provider's meta marker,
            # not the static taxonomy or a drtools auth_provider.
            provider = kind["provider"]
            oauth_provider_type = None
            categories = [kind["category"]]
            hosted = True
        else:
            auth_provider = t.get("auth_provider")
            provider = _provider_for(auth_provider)
            oauth_provider_type = _oauth_provider_type_for(auth_provider)
            categories = list(t.get("categories") or [])
            hosted = bool(t.get("hosted", False))
        items.append(
            {
                "name": t["name"],
                "display_name": t.get("display_name") or t["name"],
                # Prefer the curated UI copy (drtools ``description_ui``); fall back to the
                # tool's own MCP description (the only copy dynamic/proxied tools carry).
                "description": t.get("description_ui") or t.get("description") or "",
                "tags": sorted(t.get("tags") or []),
                "categories": categories,
                "provider": provider,
                "oauth_provider_type": oauth_provider_type,
                "hosted": hosted,
            }
        )
    return items