Skip to content

MCP Toolset Policy

Shared policy for building AI toolsets from the Imbi OpenAPI spec.

Overview

The Imbi AI services (imbi-mcp, imbi-assistant, and future bots) turn the Imbi API's /openapi.json into a toolset via fastmcp.FastMCP.from_openapi. This module centralises which operations are kept out of those toolsets so the decision lives in one place instead of being copied into each consumer:

  • EXCLUDED_ROUTE_MAPS — a static path/method denylist (auth, MFA, status, thumbnails) passed as route_maps.
  • exclude_non_ai_tools — a route_map_fn that honours the x-imbi-ai-tool: false extension imbi-api stamps on sensitive operations (e.g. project Configuration / SSM Parameter Store).

Keeping the which in imbi-api (it stamps the extension on tagged operations) and the how to honour it here means hiding a future endpoint from every AI service is just a matter of tagging it in imbi-api.

Requires the mcp extra:

imbi-common[mcp]

Usage

The two pieces compose — pass the static maps as route_maps (alongside any consumer-specific maps) and the hook as route_map_fn:

import fastmcp
import httpx

from imbi_common import mcp

client = httpx.AsyncClient(base_url="http://localhost:8000")
server = fastmcp.FastMCP.from_openapi(
    openapi_spec=spec,
    client=client,
    name="Imbi",
    route_maps=list(mcp.EXCLUDED_ROUTE_MAPS),
    route_map_fn=mcp.exclude_non_ai_tools,
)

A consumer that also classifies routes (e.g. read-only GETs as MCP resources) prepends the shared maps to its own:

server = fastmcp.FastMCP.from_openapi(
    openapi_spec=spec,
    client=client,
    route_maps=[*mcp.EXCLUDED_ROUTE_MAPS, *MY_SEMANTIC_ROUTE_MAPS],
    route_map_fn=mcp.exclude_non_ai_tools,
)

exclude_non_ai_tools is backward compatible: when the extension is absent it returns None and changes nothing, so a consumer can adopt it before or after imbi-api ships the flag.

API Reference

AI_TOOL_EXTENSION module-attribute

AI_TOOL_EXTENSION = 'x-imbi-ai-tool'

EXCLUDED_ROUTE_MAPS module-attribute

EXCLUDED_ROUTE_MAPS: list[RouteMap] = [
    RouteMap(pattern='^/auth/', mcp_type=EXCLUDE),
    RouteMap(pattern='^/mfa/', mcp_type=EXCLUDE),
    RouteMap(pattern='^/status/?$', mcp_type=EXCLUDE),
    RouteMap(pattern='.*/thumbnail/?$', mcp_type=EXCLUDE),
]

exclude_non_ai_tools

exclude_non_ai_tools(
    route: HTTPRoute, _mcp_type: MCPType
) -> MCPType | None

Exclude operations imbi-api flagged as off-limits for AI.

Intended to be passed as route_map_fn to :meth:fastmcp.FastMCP.from_openapi.

Parameters:

Name Type Description Default
route HTTPRoute

The OpenAPI route fastmcp is classifying.

required
_mcp_type MCPType

The component type fastmcp would otherwise assign; unused, since the flag overrides any classification.

required

Returns:

Type Description
MCPType | None

attr:MCPType.EXCLUDE when the operation carries

MCPType | None

x-imbi-ai-tool: false, else None to leave the existing

MCPType | None

route-map decision unchanged. The check is identity-against

MCPType | None

False so an explicit x-imbi-ai-tool: true (or the absence

MCPType | None

of the extension) keeps the operation.

Source code in src/imbi_common/mcp.py
def exclude_non_ai_tools(
    route: HTTPRoute, _mcp_type: MCPType
) -> MCPType | None:
    """Exclude operations imbi-api flagged as off-limits for AI.

    Intended to be passed as ``route_map_fn`` to
    :meth:`fastmcp.FastMCP.from_openapi`.

    Args:
        route: The OpenAPI route fastmcp is classifying.
        _mcp_type: The component type fastmcp would otherwise assign;
            unused, since the flag overrides any classification.

    Returns:
        :attr:`MCPType.EXCLUDE` when the operation carries
        ``x-imbi-ai-tool: false``, else ``None`` to leave the existing
        route-map decision unchanged. The check is identity-against
        ``False`` so an explicit ``x-imbi-ai-tool: true`` (or the absence
        of the extension) keeps the operation.

    """
    if route.extensions.get(AI_TOOL_EXTENSION) is False:
        return MCPType.EXCLUDE
    return None