Ctrl K
ComunidadGuías…

butler/mcp/tools_manifest.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Merge MCP SSOT / effective servers into ToolsEngine filtering (主线 J P2)."""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Any, cast

from butler.utilities.env_parse import env_truthy
from butler.defaults.env_defaults import MCP_TOOLS_ENGINE_SSOT_DEFAULT
from butler.mcp.naming import is_mcp_registered_name, safe_segment, tool_prefix

logger = logging.getLogger(__name__)


def tools_engine_ssot_enabled() -> bool:
    return bool(env_truthy("BUTLER_TOOLS_ENGINE_SSOT", default=MCP_TOOLS_ENGINE_SSOT_DEFAULT))


def _resolve_workspace() -> Path | None:
    from butler.mcp.tools_manifest_ops import resolve_workspace_safe

    return cast(Path | None, resolve_workspace_safe())


def effective_mcp_server_ids(*, workspace: Path | None = None) -> set[str]:
    ws = workspace if workspace is not None else _resolve_workspace()
    from butler.mcp.tools_manifest_ops import effective_mcp_server_ids_safe

    return cast(set[str], effective_mcp_server_ids_safe(workspace=ws))


def mcp_tool_matches_server(tool_name: str, server_id: str) -> bool:
    prefix = tool_prefix() + "_"
    if not str(tool_name or "").startswith(prefix):
        return False
    seg = safe_segment(server_id)
    return str(tool_name).startswith(f"{prefix}{seg}_")


def filter_tools_by_mcp_ssot(
    tools: list[dict[str, Any]],
    *,
    workspace: Path | None = None,
) -> tuple[list[dict[str, Any]], dict[str, Any]]:
    """Drop MCP tools whose server is not in effective mcp.yaml merge view."""
    diag: dict[str, Any] = {"tools_manifest_input": len(tools)}
    if not tools_engine_ssot_enabled():
        diag["tools_manifest_skipped"] = True
        return list(tools), diag

    server_ids = effective_mcp_server_ids(workspace=workspace)
    diag["tools_manifest_servers"] = sorted(server_ids)
    if not server_ids:
        kept: list[dict[str, Any]] = []
        dropped = 0
        for row in tools:
            name = str((row.get("function") or {}).get("name") or "")
            if is_mcp_registered_name(name):
                dropped += 1
                continue
            kept.append(row)
        diag["tools_manifest_dropped_mcp"] = dropped
        return kept, diag

    kept = []
    dropped = 0
    for row in tools:
        name = str((row.get("function") or {}).get("name") or "")
        if not is_mcp_registered_name(name):
            kept.append(row)
            continue
        if any(mcp_tool_matches_server(name, sid) for sid in server_ids):
            kept.append(row)
        else:
            dropped += 1
    diag["tools_manifest_dropped_mcp"] = dropped
    return kept, diag


__all__ = [
    "effective_mcp_server_ids",
    "filter_tools_by_mcp_ssot",
    "mcp_tool_matches_server",
    "tools_engine_ssot_enabled",
]