Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "mcpcat"
version = "0.1.8"
version = "0.1.9"
description = "Analytics Tool for MCP Servers - provides insights into MCP tool usage patterns"
authors = [
{ name = "MCPCat", email = "support@mcpcat.io" },
Expand Down
24 changes: 14 additions & 10 deletions src/mcpcat/modules/compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,35 +30,39 @@ def call_tool(self, name: str, arguments: dict) -> Any:

def is_community_fastmcp_server(server: Any) -> bool:
"""Check if the server is a community FastMCP instance.

Community FastMCP comes from the 'fastmcp' package.
Supports FastMCP subclasses like FastMCPOpenAPI, FastMCPProxy, etc.
"""
# Check by class name and module
class_name = server.__class__.__name__
module_name = server.__class__.__module__

# Community FastMCP has class name 'FastMCP' and module starts with 'fastmcp'

# Community FastMCP has class name containing 'FastMCP' and module starts with 'fastmcp'
# This supports FastMCPOpenAPI, FastMCPProxy, and other subclasses
return (
class_name == "FastMCP" and
"FastMCP" in class_name and
module_name.startswith("fastmcp") and
hasattr(server, "_mcp_server") and
hasattr(server, "_mcp_server") and
hasattr(server, "_tool_manager")
)

def is_official_fastmcp_server(server: Any) -> bool:
"""Check if the server is an official FastMCP instance.

Official FastMCP comes from the 'mcp.server.fastmcp' module.
Supports FastMCP subclasses like FastMCPOpenAPI, FastMCPProxy, etc.
"""
# Check by class name and module
class_name = server.__class__.__name__
module_name = server.__class__.__module__

# Official FastMCP has class name 'FastMCP' and module 'mcp.server.fastmcp'

# Official FastMCP has class name containing 'FastMCP' and module 'mcp.server.fastmcp'
# This supports FastMCPOpenAPI, FastMCPProxy, and other subclasses
return (
class_name == "FastMCP" and
"FastMCP" in class_name and
module_name.startswith("mcp.server.fastmcp") and
hasattr(server, "_mcp_server") and
hasattr(server, "_mcp_server") and
hasattr(server, "_tool_manager")
)

Expand Down
1 change: 1 addition & 0 deletions src/mcpcat/modules/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
SESSION_ID_PREFIX = "ses"
EVENT_ID_PREFIX = "evt"
MCPCAT_API_URL = "https://api.mcpcat.io" # Default API URL for MCPCat events
DEFAULT_CONTEXT_DESCRIPTION = "Describe why you are calling this tool and how it fits into your overall task"
12 changes: 8 additions & 4 deletions src/mcpcat/modules/context_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from typing import Any


def add_context_parameter_to_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]:
def add_context_parameter_to_tools(
tools: list[dict[str, Any]], custom_context_description: str
) -> list[dict[str, Any]]:
"""Add context parameter to tool schemas."""
modified_tools = []

Expand All @@ -13,15 +15,17 @@ def add_context_parameter_to_tools(tools: list[dict[str, Any]]) -> list[dict[str

if "inputSchema" in modified_tool:
modified_tool["inputSchema"] = add_context_parameter_to_schema(
modified_tool["inputSchema"]
modified_tool["inputSchema"], custom_context_description
)

modified_tools.append(modified_tool)

return modified_tools


def add_context_parameter_to_schema(schema: dict[str, Any]) -> dict[str, Any]:
def add_context_parameter_to_schema(
schema: dict[str, Any], custom_context_description: str
) -> dict[str, Any]:
"""Add context parameter to a JSON schema."""
# Create a copy to avoid modifying original
modified_schema = schema.copy()
Expand All @@ -36,7 +40,7 @@ def add_context_parameter_to_schema(schema: dict[str, Any]) -> dict[str, Any]:
# Add context parameter
modified_schema["properties"]["context"] = {
"type": "string",
"description": "Describe why you are calling this tool and how it fits into your overall task",
"description": custom_context_description,
}

# Add to required fields
Expand Down
5 changes: 3 additions & 2 deletions src/mcpcat/modules/overrides/community/tool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ async def get_more_tools(context: str | None = "") -> str:
def patch_existing_tools(server: FastMCP) -> None:
"""Modify existing tools to include the context parameter."""
try:
data = get_server_tracking_data(server._mcp_server)
tool_manager = server._tool_manager
if not hasattr(tool_manager, "_tools"):
write_to_log("No _tools dictionary found on tool manager")
Expand All @@ -102,7 +103,7 @@ def patch_existing_tools(server: FastMCP) -> None:
# Always overwrite the context property with MCPCat's version
tool.parameters["properties"]["context"] = {
"type": "string",
"description": "Describe why you are calling this tool and how it fits into your overall task"
"description": data.options.custom_context_description,
}

# Add to required array
Expand Down Expand Up @@ -168,7 +169,7 @@ def patched_add_tool(tool: Any) -> Any:
# Always overwrite the context property with MCPCat's version
tool.parameters["properties"]["context"] = {
"type": "string",
"description": "Describe why you are calling this tool and how it fits into your overall task"
"description": data.options.custom_context_description
}

# Add to required array
Expand Down
2 changes: 1 addition & 1 deletion src/mcpcat/modules/overrides/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async def wrapped_list_tools_handler(request: ListToolsRequest) -> ServerResult:

tool.inputSchema["properties"]["context"] = {
"type": "string",
"description": "Describe why you are calling this tool and how it fits into your overall task",
"description": data.options.custom_context_description,
}

# Add context to required array if it exists
Expand Down
2 changes: 1 addition & 1 deletion src/mcpcat/modules/overrides/official/monkey_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ async def get_more_tools_fn(context: str) -> Any:

tool.parameters["properties"]["context"] = {
"type": "string",
"description": "Describe why you are calling this tool and how it fits into your overall task",
"description": current_data.options.custom_context_description,
}

# Add to required array
Expand Down
3 changes: 3 additions & 0 deletions src/mcpcat/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from mcpcat_api import PublishEventRequest
from pydantic import BaseModel

from mcpcat.modules.constants import DEFAULT_CONTEXT_DESCRIPTION

# Type alias for identify function
IdentifyFunction = Callable[[dict[str, Any], Any], Optional["UserIdentity"]]
# Type alias for redaction function
Expand Down Expand Up @@ -119,6 +121,7 @@ class MCPCatOptions:
enable_report_missing: bool = True
enable_tracing: bool = True
enable_tool_call_context: bool = True
custom_context_description: str = DEFAULT_CONTEXT_DESCRIPTION
identify: IdentifyFunction | None = None
redact_sensitive_information: RedactionFunction | None = None
exporters: dict[str, ExporterConfig] | None = None
Expand Down