Skip to content

Core API Reference

Complete reference for the mcpstat Python API.


MCPStat Class

The main class for usage tracking.

Constructor

from mcpstat import MCPStat

stat = MCPStat(
    server_name: str,
    db_path: str | None = None,
    log_path: str | None = None,
    log_enabled: bool = False,
    metadata_presets: dict[str, dict] | None = None,
)
Parameter Type Default Description
server_name str Required Identifier for your MCP server
db_path str ./mcp_stat_data.sqlite SQLite database path
log_path str ./mcp_stat.log File log path
log_enabled bool False Enable file logging
metadata_presets dict None Pre-defined metadata

Core Methods

record()

Record a tool, prompt, or resource invocation.

await stat.record(
    name: str,
    primitive_type: Literal["tool", "prompt", "resource"] = "tool",
    *,
    success: bool = True,
    error_msg: str | None = None,
    response_chars: int | None = None,
    input_tokens: int | None = None,
    output_tokens: int | None = None,
)
Parameter Type Description
name str Name of the primitive
primitive_type str Type: tool, prompt, or resource
success bool Whether invocation succeeded
error_msg str Error message for failures (logged only)
response_chars int Response size for token estimation
input_tokens int Actual input token count
output_tokens int Actual output token count

Critical

Always call record() as the FIRST line in your handlers to guarantee 100% tracking coverage.

Example:

@app.call_tool()
async def handle_tool(name: str, arguments: dict):
    await stat.record(name, "tool")  # FIRST LINE
    result = await my_logic(arguments)
    return result

get_stats()

Query usage statistics.

stats = await stat.get_stats(
    *,
    include_zero: bool = True,
    limit: int | None = None,
    type_filter: Literal["tool", "prompt", "resource"] | None = None,
)
Parameter Type Description
include_zero bool Include items with zero calls
limit int Maximum results to return
type_filter str Filter by primitive type

Returns:

{
    "tracked_count": int,       # Total tracked items
    "total_calls": int,         # Sum of all call counts
    "zero_count": int,          # Items with zero calls
    "latest_access": str,       # Most recent timestamp
    "token_summary": {
        "total_input_tokens": int,
        "total_output_tokens": int,
        "total_estimated_tokens": int,
        "has_actual_tokens": bool,
    },
    "stats": [
        {
            "name": str,
            "type": str,
            "call_count": int,
            "last_accessed": str | None,
            "tags": list[str],
            "short_description": str | None,
            "total_input_tokens": int,
            "total_output_tokens": int,
            "estimated_tokens": int,
            "avg_tokens_per_call": int,
        }
    ]
}

get_catalog()

Browse and search the tool catalog.

catalog = await stat.get_catalog(
    *,
    tags: list[str] | None = None,
    query: str | None = None,
    include_usage: bool = True,
    limit: int | None = None,
)
Parameter Type Description
tags list[str] Filter by tags (AND logic)
query str Text search across names/descriptions
include_usage bool Include call counts
limit int Maximum results

AND Logic

Tag filtering uses AND logic - tools must have all specified tags.

Returns:

{
    "total_tracked": int,       # Total tools in catalog
    "matched": int,             # Tools matching filters
    "all_tags": list[str],      # Complete tag inventory
    "filters": {
        "tags": list[str],
        "query": str | None,
    },
    "results": [
        {
            "name": str,
            "tags": list[str],
            "short_description": str | None,
            "call_count": int,
            "last_accessed": str | None,
        }
    ]
}

report_tokens()

Report token usage for a previously recorded call.

await stat.report_tokens(
    name: str,
    input_tokens: int,
    output_tokens: int,
)

Use when actual token counts are available after the fact (e.g., from LLM API response).

Example:

# Record the call first
await stat.record("my_tool", "tool")

# Later, when you have actual tokens
response = await anthropic.messages.create(...)
await stat.report_tokens(
    "my_tool",
    response.usage.input_tokens,
    response.usage.output_tokens
)

sync_tools()

Sync metadata from MCP Tool objects.

await stat.sync_tools(tools: list[Tool])

Auto-extracts tags from tool names and descriptions from tool definitions.

Example:

tools = await server.list_tools()
await stat.sync_tools(tools)

register_metadata()

Manually register metadata for a tool.

await stat.register_metadata(
    name: str,
    tags: list[str] | None = None,
    short_description: str | None = None,
    full_description: str | None = None,
)

get_by_type()

Get call counts grouped by type.

counts = await stat.get_by_type()
# {"tool": 15, "prompt": 3, "resource": 2}

close()

Explicit cleanup (usually automatic).

stat.close()

Built-in Tools

build_tool_definitions()

Generate MCP tool schemas for mcpstat's built-in tools.

from mcpstat import build_tool_definitions

tools = build_tool_definitions(
    prefix: str = "get",
    server_name: str | None = None,
)

Returns tool definitions for:

  • get_tool_usage_stats
  • get_tool_catalog

BuiltinToolsHandler

Handle calls to mcpstat's built-in tools.

from mcpstat import BuiltinToolsHandler

handler = BuiltinToolsHandler(stat, prefix="get")

# Check if a tool name is a stats tool
if handler.is_stats_tool(name):
    result = await handler.handle(name, arguments)

Methods:

Method Description
is_stats_tool(name) Check if name is a built-in stats tool
handle(name, args) Handle the tool call, return result dict

Prompts

build_prompt_definition()

Generate MCP prompt schema for stats prompt.

from mcpstat import build_prompt_definition

prompt = build_prompt_definition(server_name="my-server")

generate_stats_prompt()

Generate prompt content with current stats.

from mcpstat import generate_stats_prompt

content = await generate_stats_prompt(stat, server_name="my-server")

Utility Functions

normalize_tags()

Normalize and filter tags from text.

from mcpstat.utils import normalize_tags

tags = normalize_tags(
    ["Fetch", "Weather", "Data", "the"],
    filter_stopwords=True
)
# ["fetch", "weather", "data"]