Skip to main content
Glama
isdaniel

PostgreSQL-Performance-Tuner-Mcp

toolhandler.py5.7 kB
"""Abstract base class for tool handlers following the ToolHandler pattern.""" from __future__ import annotations from abc import ABC, abstractmethod from collections.abc import Sequence from typing import Any from mcp.types import TextContent, Tool, ToolAnnotations class ToolHandler(ABC): """ Abstract base class for MCP tool handlers. This pattern allows for modular organization of tools where each handler is responsible for defining its schema and executing its logic. Subclasses must implement: - name: The unique tool name - description: Human-readable description - get_tool_definition(): Returns the Tool schema - run_tool(): Executes the tool logic Optional attributes for MCP Tool Annotations: - title: Human-readable title for UI display - read_only_hint: If True, tool doesn't modify environment (default: True for most query tools) - destructive_hint: If True, tool may perform destructive updates - idempotent_hint: If True, calling multiple times with same args has same effect - open_world_hint: If True, tool interacts with external entities Example: class MyToolHandler(ToolHandler): name = "my_tool" description = "Does something useful" title = "My Useful Tool" read_only_hint = True def get_tool_definition(self) -> Tool: return Tool( name=self.name, description=self.description, inputSchema={ "type": "object", "properties": { "param": {"type": "string", "description": "A parameter"} }, "required": ["param"] }, annotations=self.get_annotations() ) async def run_tool(self, arguments: dict[str, Any]) -> Sequence[TextContent]: result = do_something(arguments["param"]) return [TextContent(type="text", text=result)] """ name: str = "" description: str = "" # MCP Tool Annotation hints title: str | None = None read_only_hint: bool | None = None destructive_hint: bool | None = None idempotent_hint: bool | None = None open_world_hint: bool | None = None def get_annotations(self) -> ToolAnnotations | None: """ Build ToolAnnotations from the handler's hint attributes. Returns: ToolAnnotations object or None if no annotations are set """ # Only include annotations if at least one hint is set if all( v is None for v in [ self.title, self.read_only_hint, self.destructive_hint, self.idempotent_hint, self.open_world_hint ] ): return None return ToolAnnotations( title=self.title, readOnlyHint=self.read_only_hint, destructiveHint=self.destructive_hint, idempotentHint=self.idempotent_hint, openWorldHint=self.open_world_hint ) @abstractmethod def get_tool_definition(self) -> Tool: """ Return the MCP Tool definition including input schema. Returns: Tool: The tool definition with name, description, and inputSchema """ pass @abstractmethod async def run_tool(self, arguments: dict[str, Any]) -> Sequence[TextContent]: """ Execute the tool logic with the provided arguments. Args: arguments: Dictionary of arguments matching the input schema Returns: Sequence[TextContent]: The tool output as text content Raises: ValueError: If required arguments are missing or invalid Exception: If tool execution fails """ pass def validate_required_args( self, arguments: dict[str, Any], required: list[str] ) -> None: """ Validate that required arguments are present. Args: arguments: The arguments dictionary to validate required: List of required argument names Raises: ValueError: If any required argument is missing """ missing = [arg for arg in required if arg not in arguments or arguments[arg] is None] if missing: raise ValueError(f"Missing required arguments: {', '.join(missing)}") def format_error(self, error: Exception) -> Sequence[TextContent]: """ Format an error as TextContent for tool response. Args: error: The exception to format Returns: Sequence[TextContent]: Error message as text content """ return [TextContent(type="text", text=f"Error: {str(error)}")] def format_result(self, result: str) -> Sequence[TextContent]: """ Format a string result as TextContent. Args: result: The result string to format Returns: Sequence[TextContent]: Result as text content """ return [TextContent(type="text", text=result)] def format_json_result(self, data: Any) -> Sequence[TextContent]: """ Format data as JSON TextContent. Args: data: The data to serialize as JSON Returns: Sequence[TextContent]: JSON-formatted text content """ import json return [TextContent(type="text", text=json.dumps(data, indent=2, default=str))]

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/isdaniel/pgtuner-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server