Skip to main content
Glama
tool_formatter.py4.48 kB
"""Utilities for formatting MCP tool schemas for LLM consumption.""" from __future__ import annotations import json from typing import TYPE_CHECKING, Any, Mapping, Sequence if TYPE_CHECKING: # pragma: no cover - typing only import dspy as dspy_module # type: ignore ToolLike = dspy_module.Tool else: # Runtime fallback keeps the formatter usable without DSpy installed. ToolLike = Any class ToolSchemaFormatter: """Format MCP tools into readable documentation blocks.""" def __init__(self, tools: Sequence[ToolLike]): self.tools = list(tools) def format_for_llm(self) -> str: """Return markdown describing all available tools.""" header = f"# Available MCP Tools ({len(self.tools)} total)\n\n" if not self.tools: return header + "No tools are currently available." body = "\n\n".join(self._format_single_tool(tool) for tool in self.tools) return header + body def get_tool_names(self) -> list[str]: """Return the tool names in discovery order.""" names: list[str] = [] for tool in self.tools: name = getattr(tool, "name", None) if isinstance(name, str): names.append(name) return names def _format_single_tool(self, tool: ToolLike) -> str: """Create a markdown block describing one tool.""" name = getattr(tool, "name", "unknown_tool") description = getattr(tool, "description", "") # Handle case where description is a method (e.g. in some dspy versions) if callable(description): description = description() description = description.strip() if isinstance(description, str) else "No description." schema = getattr(tool, "input_schema", None) or {} params = self._extract_properties(schema) required = self._extract_required(schema) signature = self._signature(params, required) param_json = json.dumps(params, indent=2, sort_keys=True) example = self._generate_example(name, params, required) return ( f"## {name}\n" f"**Description**: {description}\n\n" f"**Usage**:\n" "```python\n" f"result = {name}({signature})\n" "```\n\n" f"**Parameters**:\n{param_json}\n\n" "**Example**:\n" "```python\n" f"{example}\n" "```" ) def _extract_properties(self, schema: Mapping[str, Any]) -> dict[str, Any]: properties = schema.get("properties") if isinstance(properties, Mapping): return dict(properties) return {} def _extract_required(self, schema: Mapping[str, Any]) -> list[str]: required = schema.get("required") or [] return [str(item) for item in required if isinstance(item, str)] def _signature( self, params: Mapping[str, Any], required: Sequence[str], ) -> str: parts: list[str] = [] for name, info in params.items(): type_hint = ( info.get("type") if isinstance(info, Mapping) else None ) or "any" required_marker = "" if name in required else "?" parts.append(f"{name}{required_marker}: {type_hint}") return ", ".join(parts) def _generate_example( self, tool_name: str, params: Mapping[str, Any], required: Sequence[str], ) -> str: example_args: list[str] = [] param_names = list(required) if required else list(params.keys()) for param in param_names: info = params.get(param, {}) type_hint = ( info.get("type") if isinstance(info, Mapping) else None ) or "string" example_args.append(f"{param}={self._example_value(param, type_hint)}") args = ", ".join(example_args) if args: return f"result = {tool_name}({args})\nprint(result)" return f"result = {tool_name}()\nprint(result)" def _example_value(self, name: str, type_hint: str) -> str: if type_hint == "integer": return "42" if type_hint == "number": return "3.14" if type_hint == "boolean": return "True" if type_hint == "array": return f"[\"{name}_item\"]" return f'"{name}_value"' __all__ = ["ToolSchemaFormatter"]

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/draphonix/mcp-code-mode'

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