### Install Dependencies Source: https://github.com/oaklight/toolregistry/blob/master/examples/openapi_related/openapi_calculator/README.md Run this command to install all necessary Python packages for the server. ```bash pip install -r requirements.txt ``` -------------------------------- ### Install ToolRegistry Source: https://context7.com/oaklight/toolregistry/llms.txt Install the core package or with optional protocol extras for specific integrations. ```bash pip install toolregistry ``` ```bash pip install toolregistry[mcp] ``` ```bash pip install toolregistry[openapi] ``` ```bash pip install toolregistry[langchain] ``` ```bash pip install toolregistry[mcp,openapi] ``` ```bash pip install toolregistry-hub ``` -------------------------------- ### Run the Server Source: https://github.com/oaklight/toolregistry/blob/master/examples/openapi_related/openapi_calculator/README.md Execute this command to start the server. The port can be configured via the PORT environment variable. ```bash python main.py ``` -------------------------------- ### Run Other SSE Client Examples Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Commands to run various other SSE client examples, ensuring the PORT environment variable is set correctly. ```bash PORT=8002 python examples/mcp_clients/math_client_sse.py ``` ```bash PORT=8003 python examples/mcp_clients/sqlite_client_sse.py ``` -------------------------------- ### Run Other SSE Server Examples Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Commands to run various other SSE server examples provided by MCP, each on a different port. ```bash uvicorn mcp_related.mcp_servers.math_server_sse:app --port 8002 ``` ```bash uvicorn mcp_related.mcp_servers.sqlite_server_sse:app --port 8003 ``` ```bash uvicorn mcp_related.mcp_servers.str_ops_client_sse:app --port 8004 ``` ```bash uvicorn mcp_related.mcp_servers.everything_server_sse:app --port 8005 ``` -------------------------------- ### Run SSE Client Example Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Command to execute an SSE client script. The PORT environment variable should be set to match the running server. ```bash PORT=8001 python examples/mcp_clients/echo_client_sse.py ``` -------------------------------- ### Start and Manage ToolRegistry Admin Panel Source: https://context7.com/oaklight/toolregistry/llms.txt Starts a lightweight HTTP admin panel with REST API and optional web UI. Supports token authentication for remote access. Use `disable_admin()` to shut it down. ```python from toolregistry import ToolRegistry registry = ToolRegistry() @registry.register def ping() -> str: """Health check.""" return "pong" # Start local admin panel on port 8081 info = registry.enable_admin(host="127.0.0.1", port=8081, serve_ui=True) print(f"Admin panel: {info.url}") # http://127.0.0.1:8081 # Remote access with auto-generated token info = registry.enable_admin(remote=True, port=8090) print(f"Token: {info.token}") # e.g. "a1b2c3d4e5f6..." # Explicit token info = registry.enable_admin(remote=True, auth_token="mysecret", port=8090) # REST endpoints available: # GET /tools — list tools # POST /tools/{name}/disable — disable a tool # POST /tools/{name}/enable — enable a tool # GET /logs — execution log entries # GET /stats — execution statistics # Shutdown registry.disable_admin() ``` -------------------------------- ### Install ToolRegistry Core Package Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Install the core ToolRegistry package. Requires Python 3.10 or higher. ```bash pip install toolregistry ``` -------------------------------- ### Install ToolRegistry with Extra Modules Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Install ToolRegistry with additional support modules like MCP and OpenAPI. Specify desired modules in brackets. ```bash pip install toolregistry[mcp,openapi] ``` -------------------------------- ### Install toolregistry-hub Package Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Install the separate toolregistry-hub package for LLM function calling tools. Can be used independently. ```bash pip install toolregistry-hub ``` -------------------------------- ### ToolRegistry.enable_admin Source: https://context7.com/oaklight/toolregistry/llms.txt Starts a lightweight HTTP admin panel with REST API and optional web UI for live inspection and management of the registry. Supports token authentication for remote access. ```APIDOC ## `ToolRegistry.enable_admin` Starts a lightweight HTTP admin panel with REST API and optional web UI for live inspection and management of the registry. Supports token authentication for remote access. ### Method Signature `enable_admin(host: str = '127.0.0.1', port: int = 8080, remote: bool = False, serve_ui: bool = False, auth_token: Optional[str] = None)` ### Parameters - **host** (str) - The host address for the admin panel. - **port** (int) - The port number for the admin panel. - **remote** (bool) - Whether to enable remote access. - **serve_ui** (bool) - Whether to serve the web UI. - **auth_token** (Optional[str]) - An explicit authentication token for remote access. ### REST Endpoints - **GET** `/tools` - List tools - **POST** `/tools/{name}/disable` - Disable a tool - **POST** `/tools/{name}/enable` - Enable a tool - **GET** `/logs` - Execution log entries - **GET** `/stats` - Execution statistics ### Example Usage ```python from toolregistry import ToolRegistry registry = ToolRegistry() @registry.register def ping() -> str: """Health check.""" return "pong" # Start local admin panel on port 8081 info = registry.enable_admin(host="127.0.0.1", port=8081, serve_ui=True) print(f"Admin panel: {info.url}") # Remote access with auto-generated token info = registry.enable_admin(remote=True, port=8090) print(f"Token: {info.token}") # Explicit token info = registry.enable_admin(remote=True, auth_token="mysecret", port=8090) # Shutdown registry.disable_admin() ``` ``` -------------------------------- ### Query and Access Registered Tools Source: https://context7.com/oaklight/toolregistry/llms.txt Provides methods to list, get, and access tool callables by name. Supports checking tool membership and retrieving tool status. ```python from toolregistry import ToolRegistry registry = ToolRegistry() @registry.register def greet(name: str) -> str: """Say hello.""" return f"Hello, {name}!" # List enabled tool names print(registry.list_tools()) # ['greet'] print(registry.list_tools(include_disabled=True)) # includes disabled tools # Get the Tool object (metadata, schema, callable) tool = registry.get_tool("greet") print(tool.name) # 'greet' print(tool.description) # 'Say hello.' # Get the raw callable fn = registry.get_callable("greet") print(fn("Alice")) # 'Hello, Alice!' # Subscript access — also returns callable print(registry["greet"]("Bob")) # 'Hello, Bob!' # Membership test print("greet" in registry) # True # Get all tool statuses for status in registry.get_tools_status(): print(status) # {'name': 'greet', 'enabled': True, 'reason': None, 'namespace': None, # 'tags': [], 'locality': 'any', 'is_async': False, 'think_augment': None, # 'defer': False, 'has_native_thought': False} ``` -------------------------------- ### Basic Tool Registration and Invocation Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Demonstrates registering a simple 'add' function with ToolRegistry and then invoking it. Shows how to list available tools and retrieve callable functions. ```python from toolregistry import ToolRegistry registry = ToolRegistry() @registry.register def add(a: float, b: float) -> float: """Add two numbers together.""" return a + b available_tools = registry.list_tools() print(available_tools) # ['add'] add_func = registry.get_callable('add') print(type(add_func)) # add_result = add_func(1, 2) print(add_result) # 3 add_func = registry['add'] print(type(add_func)) # add_result = add_func(4, 5) print(add_result) # 9 ``` -------------------------------- ### ToolRegistry Initialization Source: https://context7.com/oaklight/toolregistry/llms.txt Demonstrates how to create a ToolRegistry instance, with options for naming, setting global result size limits, enabling think-augmented calling, and automatic tool discovery. ```APIDOC ## ToolRegistry.__init__ Creates the central registry instance. Accepts optional settings for name, global result size limits, think-augmented calling, and automatic tool discovery. ```python from toolregistry import ToolRegistry # Basic registry registry = ToolRegistry() # Named registry with options registry = ToolRegistry( name="my_agent_tools", default_max_result_size=4096, # Auto-truncate results over 4 KB think_augment=True, # Inject a "thought" field into all tool schemas tool_discovery=True, # Register a built-in "discover_tools" search tool ) ``` ``` -------------------------------- ### Initialize Configuration and Token Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Sets up the base API URL and retrieves the authentication token from local storage. Initializes variables for auto-refresh and tool storage. ```javascript const API_BASE = window.location.origin; let AUTH_TOKEN = localStorage.getItem('admin_token') || ''; let autoRefreshInterval = null; let allTools = []; ``` -------------------------------- ### Register Hub Tools with ToolRegistry Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Demonstrates how to register a hub tool class, such as Calculator, with the ToolRegistry. Shows how to list available tools after registration. ```python from toolregistry import ToolRegistry from toolregistry.hub import Calculator registry = ToolRegistry() registry.register_from_class(Calculator, namespace=True) # Get available tools list print(registry.list_tools()) ``` -------------------------------- ### Initialize ToolRegistry Source: https://context7.com/oaklight/toolregistry/llms.txt Create a new ToolRegistry instance. Options include naming, setting global result size limits, enabling think-augmented calling, and automatic tool discovery. ```python from toolregistry import ToolRegistry # Basic registry registry = ToolRegistry() ``` ```python from toolregistry import ToolRegistry # Named registry with options registry = ToolRegistry( name="my_agent_tools", default_max_result_size=4096, # Auto-truncate results over 4 KB think_augment=True, # Inject a "thought" field into all tool schemas tool_discovery=True, # Register a built-in "discover_tools" search tool ) ``` -------------------------------- ### ToolRegistry.list_tools, get_tool, get_callable Source: https://context7.com/oaklight/toolregistry/llms.txt Provides methods to query and retrieve tools registered in the registry. You can list tool names, get detailed tool objects, or directly access the callable function. ```APIDOC ## `ToolRegistry.list_tools` / `get_tool` / `get_callable` Query tools registered in the registry by name. ### Methods - **`list_tools(include_disabled=False)`**: Returns a list of enabled tool names. Set `include_disabled=True` to include disabled tools. - **`get_tool(name)`**: Retrieves the `Tool` object (containing metadata, schema, and callable) for a given tool name. - **`get_callable(name)`**: Retrieves the raw callable function for a given tool name. - **`registry[name]`**: Subscript access, also returns the callable function. - **`name in registry`**: Membership test to check if a tool name exists in the registry. - **`get_tools_status()`**: Returns a list of dictionaries, each containing the status of a tool (name, enabled, reason, etc.). ``` -------------------------------- ### Access the Service Source: https://github.com/oaklight/toolregistry/blob/master/examples/openapi_related/openapi_calculator/README.md Connect to the server using this URL. Adjust the port if it has been customized. ```bash http://localhost:8000 ``` -------------------------------- ### Get Tool Schemas for LLM APIs Source: https://context7.com/oaklight/toolregistry/llms.txt Retrieve tool definitions as JSON Schema dictionaries formatted for specific LLM APIs. Supports filtering by tags, deferring hidden tools, and stable sorting for prompt cache optimization. ```python from toolregistry import ToolRegistry, ToolTag registry = ToolRegistry() @registry.register def read_file(path: str) -> str: """Read a file from disk.""" with open(path) as f: return f.read() @registry.register def delete_file(path: str) -> str: """Delete a file.""" import os; os.remove(path); return "deleted" # Tag tools for filtering from toolregistry.tool import Tool, ToolMetadata registry._tools["read_file"].metadata.tags.add(ToolTag.READ_ONLY) registry._tools["delete_file"].metadata.tags.add(ToolTag.DESTRUCTIVE) # All tools — OpenAI Chat format (default) all_schemas = registry.get_schemas() # Anthropic format anthropic_schemas = registry.get_schemas(api_format="anthropic") # OpenAI Responses API format responses_schemas = registry.get_schemas(api_format="openai-response") # Gemini format gemini_schemas = registry.get_schemas(api_format="gemini") # Only read-only tools safe_schemas = registry.get_schemas(tags={ToolTag.READ_ONLY}) # Exclude destructive tools safe_schemas2 = registry.get_schemas(exclude_tags={ToolTag.DESTRUCTIVE}) # Schema for a single named tool single = registry.get_schemas(tool_name="read_file") print(single) # [{'type': 'function', 'function': {'name': 'read_file', 'description': '...', 'parameters': {...}}}] ``` -------------------------------- ### Registering LangChain Tools Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Demonstrates how to integrate LangChain tools into ToolRegistry. This allows for seamless registration and invocation of both synchronous and asynchronous LangChain tools. ```python from langchain_community.tools import ArxivQueryRun, PubmedQueryRun ``` ```python from toolregistry import ToolRegistry ``` ```python registry = ToolRegistry() ``` ```python registry.register_from_langchain([ArxivQueryRun(), PubmedQueryRun()]) ``` ```python tools_json = registry.get_schemas() ``` -------------------------------- ### Registering Instance Class Methods Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Illustrates registering instance methods from a class using `register_from_class` with `namespace=True`. An instance of the class is passed, and its methods become accessible via a namespaced key. ```python from toolregistry import ToolRegistry ``` ```python class InstanceExample: def __init__(self, name: str): self.name = name def greet(self, name: str) -> str: return f"Hello, {name}! I'm {self.name}." ``` ```python registry = ToolRegistry() registry.register_from_class(InstanceExample("Bob"), namespace=True) ``` ```python print(registry.list_tools()) # ['instance_example.greet'] ``` ```python print(registry["instance_example.greet"]("Alice")) # Hello, Alice! I'm Bob. ``` -------------------------------- ### Registering Tools from MCP Source: https://github.com/oaklight/toolregistry/blob/master/README.md Demonstrates various ways to register tools from a Message Communication Protocol (MCP). This includes using URLs, local script paths, MCP configuration dictionaries, and FastMCP instances. ```python transport = "https://mcphub.url/mcp" # Streamable HTTP MCP ``` ```python transport = "http://localhost:8000/sse/test_group" # Legacy HTTP+SSE ``` ```python transport = "examples/mcp_related/mcp_servers/math_server.py" # Local path ``` ```python transport = { "mcpServers": { "make_mcp": { "command": f"{Path.home()}/mambaforge/envs/toolregistry_dev/bin/python", "args": [ f"{Path.home()}/projects/toolregistry/examples/mcp_related/mcp_servers/math_server.py" ], "env": {}, } } } # MCP configuration dictionary example ``` ```python transport = FastMCP(name="MyFastMCP") # FastMCP instance ``` ```python transport = StreamableHttpTransport(url="https://mcphub.example.com/mcp", headers={"Authorization": "Bearer token"}) # Transport instance with custom headers ``` ```python registry.register_from_mcp(transport) ``` ```python # Get all tools' JSON, including MCP tools tools_json = registry.get_schemas() ``` -------------------------------- ### Initialization and Event Listeners Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Sets up the initial state of the application on DOMContentLoaded, including language selection, i18n application, and data refresh. Also handles keyboard shortcuts for modal closing. ```javascript document.addEventListener('DOMContentLoaded', () => { document.getElementById('langSwitcher').value = currentLang; applyI18n(); refreshTools(); refreshStats(); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeModal(); closeDetailModal(); } }); ``` -------------------------------- ### Establish SSE Client Connection Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Connect to an SSE endpoint and establish a session for communication. Use 'async with' for proper resource management. ```python from mcp.client.sse import sse_client from mcp.client.session import ClientSession async with sse_client("http://localhost:8001/sse") as (read_stream, write_stream): async with ClientSession(read_stream, write_stream) as session: await session.initialize() ``` -------------------------------- ### Create FastMCP SSE Server Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Initialize an SSE server using the FastMCP class. Specify server name and relevant API paths. ```python from mcp.server.fastmcp import FastMCP mcp = FastMCP("Server Name", sse_path="/sse", message_path="/mcp/messages/") ``` -------------------------------- ### Registering OpenAPI Specifications Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Shows how to register OpenAPI specifications using `register_from_openapi`. It details configuring the HTTP client with `HttpxClientConfig` and loading OpenAPI specs from local files or URLs. ```python from toolregistry.integrations.openapi import HttpxClientConfig, load_openapi_spec ``` ```python client_config = HttpxClientConfig(base_url="http://localhost:8000") ``` ```python openapi_spec = load_openapi_spec("./openapi_spec.json") ``` ```python openapi_spec = load_openapi_spec("http://localhost:8000") ``` ```python openapi_spec = load_openapi_spec("http://localhost:8000/openapi.json") ``` ```python registry.register_from_openapi( client_config=client_config, openapi_spec=openapi_spec ) ``` ```python # Get all tools' JSON, including OpenAPI tools tools_json = registry.get_schemas() ``` -------------------------------- ### Registering Static Class Methods Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Shows how to register static methods from a class using `register_from_class` with `namespace=True`. This makes the static method accessible via a namespaced key. ```python from toolregistry import ToolRegistry ``` ```python class StaticExample: @staticmethod def greet(name: str) -> str: return f"Hello, {name}!" ``` ```python registry = ToolRegistry() registry.register_from_class(StaticExample, namespace=True) ``` ```python print(registry.list_tools()) # ['static_example.greet'] ``` ```python print(registry["static_example.greet"]("Alice")) # Hello, Alice! ``` -------------------------------- ### Register, Merge, and Spinoff Tool Registries Source: https://context7.com/oaklight/toolregistry/llms.txt Demonstrates how to create, register tools, merge registries, and spinoff namespaces. Tools in merged registries are namespace-prefixed. ```python from toolregistry import ToolRegistry math_reg = ToolRegistry(name="math") @math_reg.register def add(a: float, b: float) -> float: """Add two numbers.""" return a + b text_reg = ToolRegistry(name="text") @text_reg.register def upper(s: str) -> str: """Convert string to uppercase.""" return s.upper() # Merge text_reg into math_reg (tools get namespace-prefixed) math_reg.merge(text_reg) print(math_reg.list_tools()) # ['math-add', 'text-upper'] # Spin off the math namespace into its own registry math_only = math_reg.spinoff("math") print(math_only.list_tools()) # ['add'] (namespace stripped) print(math_reg.list_tools()) # ['text-upper'] # reduce_namespace: flatten when only one sub-registry remains single_reg = ToolRegistry() single_reg.merge(math_reg) single_reg.reduce_namespace() # Strips the sole namespace prefix ``` -------------------------------- ### Register a Tool with Namespace Source: https://context7.com/oaklight/toolregistry/llms.txt Register a tool and assign it to a namespace, which prefixes the tool's name. This helps organize tools and avoid naming conflicts. ```python from toolregistry import ToolRegistry registry = ToolRegistry() @registry.register def search(query: str) -> str: """Search the web.""" return f"Results for: {query}" registry.register(search, namespace="web") # Registered as "web-search" print(registry.list_tools()) # ['add', 'subtract', 'web-search'] ``` -------------------------------- ### List Tools via SSE Client Session Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Retrieve the list of available tools from the server using the session. Access the tools directly via the '.tools' property. ```python tools_response = await session.list_tools() tools = tools_response.tools # Note: directly access .tools property for tool in tools: print(f"- {tool.name}: {tool.description}") ``` -------------------------------- ### Registering Tools from a Class Source: https://context7.com/oaklight/toolregistry/llms.txt Explains how to register all public methods from a Python class or instance using `register_from_class`. It details how the `namespace` parameter affects tool naming. ```APIDOC ## ToolRegistry.register_from_class Registers all public methods from a class or instance as tools. The `namespace` parameter controls whether tool names are prefixed with the class name. ```python from toolregistry import ToolRegistry class MathTools: @staticmethod def multiply(a: float, b: float) -> float: """Multiply two numbers.""" return a * b @staticmethod def divide(a: float, b: float) -> float: """Divide a by b.""" if b == 0: raise ValueError("Division by zero") return a / b class GreeterInstance: def __init__(self, greeting: str): self.greeting = greeting def greet(self, name: str) -> str: """Greet a person.""" return f"{self.greeting}, {name}!" registry = ToolRegistry() # Class (static methods, namespace derived from class name) registry.register_from_class(MathTools, namespace=True) print(registry.list_tools()) # ['math_tools-multiply', 'math_tools-divide'] # Instance (instance methods bound to the object) registry.register_from_class(GreeterInstance("Hello"), namespace="greeter") print(registry.list_tools()) # [..., 'greeter-greet'] # Call via subscript result = registry["math_tools-multiply"](3, 4) print(result) # 12.0 ``` ``` -------------------------------- ### Register Tools from an MCP Server Source: https://context7.com/oaklight/toolregistry/llms.txt Connect to an MCP (Model Context Protocol) server and register its tools. Supports various transport mechanisms like STDIO, SSE, HTTP, and WebSockets. ```python from toolregistry import ToolRegistry registry = ToolRegistry() # STDIO: path to a Python or JS MCP server script registry.register_from_mcp("path/to/math_server.py", namespace=True) # SSE transport registry.register_from_mcp("http://localhost:8000/sse", namespace="math") # Streamable HTTP transport registry.register_from_mcp("http://localhost:8000/mcp") # WebSocket transport registry.register_from_mcp("ws://localhost:9000") ``` -------------------------------- ### Run SSE Server with Uvicorn Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Command to run the FastMCP SSE server using uvicorn. Ensure the path to the app is correct. ```bash uvicorn mcp_related.mcp_servers.echo_server_sse:app --port 8001 ``` -------------------------------- ### Handle State Import File Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Processes a JSON file selected by the user for importing the tool registry state. It shows a confirmation modal before proceeding with the import. ```javascript async function handleImportFile(event) { const file = event.target.files[0]; if (!file) return; try { const text = await file.text(); const state = JSON.parse(text); showModal(t('modal.importState'),

${t('confirm.importState')}

${t('confirm.importOverwrite')}

${t('confirm.disabledItems', {count: Object.keys(state.disabled || {}).length})}
, async () => { try { await api.importState(state); showToast(t('toast.stateImported'), 'success'); refreshAll(); } catch (e) { showToast(e.message, 'error'); } }); } catch (e) { showToast(t('toast.invalidJson'), 'error'); } event.target.value = ''; } ``` -------------------------------- ### Enable a Tool Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Sends an API request to enable a specific tool. Shows a success toast and refreshes the tool list and statistics. ```javascript async function enableTool(name) { try { await api.enableTool(name); showToast(t('toast.toolEnabled', {name}), 'success'); refreshTools(); refreshStats(); } catch (e) { showToast(e.message, 'error'); } } ``` -------------------------------- ### Render Tools Table Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Populates the tools table in the UI, grouping tools by namespace. If no tools are found, it displays an empty state message. It sorts namespaces alphabetically, with 'default' appearing first. ```javascript function renderTools(tools) { const tbody = document.getElementById('tools-body'); if (tools.length === 0) { tbody.innerHTML = `
${t('empty.tools')}
${t('empty.toolsHint')}
`; return; } // Group: standalone tools (no namespace) go under "default", rest by namespace const nsMap = {}; tools.forEach(t => { const ns = t.namespace || 'default'; if (!nsMap[ns]) nsMap[ns] = []; nsMap[ns].push(t); }); let html = ''; // Render all groups (default first, then sorted) const nsKeys = Object.keys(nsMap).sort((a, b) => { if (a === 'default') return -1; if (b === 'default') return 1; return a.localeCompare(b); }); nsKeys.forEach(ns => { const children = nsMap[ns]; const allEnabled = children.every(t => t.enabled); const allThink = children.every(t => t. ``` -------------------------------- ### Registering Tools Source: https://context7.com/oaklight/toolregistry/llms.txt Shows how to register individual Python callables (functions or methods) using the `register` method, either directly or as a decorator. It also covers overriding names and descriptions, and using namespaces. ```APIDOC ## ToolRegistry.register Registers a single callable or `Tool` instance. Can be used as a decorator or called directly. Supports an optional custom name, description override, and namespace prefix. ```python from toolregistry import ToolRegistry registry = ToolRegistry() # Decorator style (name and description taken from function) @registry.register def add(a: float, b: float) -> float: """Add two numbers together.""" return a + b # Explicit name and description override @registry.register def _internal_sub(a: int, b: int) -> int: return a - b registry.register(_internal_sub, name="subtract", description="Subtract b from a") # With namespace @registry.register def search(query: str) -> str: """Search the web.""" return f"Results for: {query}" registry.register(search, namespace="web") # Registered as "web-search" print(registry.list_tools()) # ['add', 'subtract', 'web-search'] ``` ``` -------------------------------- ### ToolRegistry.register_from_langchain Source: https://context7.com/oaklight/toolregistry/llms.txt Wraps LangChain `BaseTool` instances and registers them as standard ToolRegistry tools, supporting both sync and async invocations. ```APIDOC ## ToolRegistry.register_from_langchain Wraps LangChain `BaseTool` instances and registers them as standard ToolRegistry tools, supporting both sync and async invocations. ```python from langchain_community.tools import ArxivQueryRun, PubmedQueryRun from toolregistry import ToolRegistry registry = ToolRegistry() # Register a single LangChain tool registry.register_from_langchain(ArxivQueryRun()) # Register multiple tools (pass a list) registry.register_from_langchain([ArxivQueryRun(), PubmedQueryRun()]) schemas = registry.get_schemas() # Ready for OpenAI / Anthropic API print([s["function"]["name"] for s in schemas]) # ['arxiv', 'pub_med'] ``` ``` -------------------------------- ### Call Tool via SSE Client Session Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Invoke a registered tool on the server, providing the tool name and its input parameters. The result is returned asynchronously. ```python result = await session.call_tool( "echo_tool", {"message": "Hello from client!"} ) print(f"Tool result: {result}") ``` -------------------------------- ### Registering Tools from MCP Server Source: https://context7.com/oaklight/toolregistry/llms.txt Details how to register tools from an MCP (Model Context Protocol) server using `register_from_mcp`. It covers various transport methods like STDIO, SSE, HTTP, and WebSockets. ```APIDOC ## ToolRegistry.register_from_mcp Connects to an MCP (Model Context Protocol) server and registers all its tools. Supports STDIO scripts, SSE, Streamable HTTP, WebSocket, FastMCP instances, and JSON config dicts. The async variant `register_from_mcp_async` is also available. ```python from toolregistry import ToolRegistry registry = ToolRegistry() # STDIO: path to a Python or JS MCP server script registry.register_from_mcp("path/to/math_server.py", namespace=True) # SSE transport registry.register_from_mcp("http://localhost:8000/sse", namespace="math") # Streamable HTTP transport registry.register_from_mcp("http://localhost:8000/mcp") # WebSocket transport registry.register_from_mcp("ws://localhost:9000") ``` ``` -------------------------------- ### Register Hub Tools with Namespaces Source: https://context7.com/oaklight/toolregistry/llms.txt Register ready-to-use tool classes from the toolregistry-hub with a namespace to group related tools. This simplifies exposing a collection of tools to an LLM. ```python from toolregistry import ToolRegistry from toolregistry.hub import Calculator, UnitConverter, DateTime registry = ToolRegistry() # Register hub tool classes with namespace registry.register_from_class(Calculator, namespace=True) registry.register_from_class(UnitConverter, namespace=True) registry.register_from_class(DateTime, namespace=True) print(registry.list_tools()) schemas = registry.get_schemas() ``` -------------------------------- ### Register LangChain Tools Source: https://context7.com/oaklight/toolregistry/llms.txt Wrap LangChain `BaseTool` instances and register them as standard ToolRegistry tools. Supports both synchronous and asynchronous invocations. ```python from langchain_community.tools import ArxivQueryRun, PubmedQueryRun from toolregistry import ToolRegistry registry = ToolRegistry() # Register a single LangChain tool registry.register_from_langchain(ArxivQueryRun()) # Register multiple tools (pass a list) registry.register_from_langchain([ArxivQueryRun(), PubmedQueryRun()]) schemas = registry.get_schemas() # Ready for OpenAI / Anthropic API print([s["function"]["name"] for s in schemas]) # ['arxiv', 'pub_med'] ``` -------------------------------- ### Enable Tool Discovery with BM25F Search Source: https://context7.com/oaklight/toolregistry/llms.txt Registers a `discover_tools` function for BM25F full-text search over tool metadata. LLMs can use this to find tools by natural language queries or exact names. Deferred tools are hidden from the initial schema but discoverable. ```python from toolregistry import ToolRegistry from toolregistry.tool import Tool, ToolMetadata registry = ToolRegistry() @registry.register def add(a: float, b: float) -> float: """Add two numbers.""" return a + b # Defer some tools so they're hidden from the initial schema # but discoverable via search registry._tools["add"].metadata.search_hint = "sum plus arithmetic addition" # Enable discovery (also accessible at init via tool_discovery=True) discovers = registry.enable_tool_discovery() # LLMs invoke "discover_tools" as a regular tool call; # you can also call it directly: results = discoverer.discover("add numbers", top_k=5) for r in results: print(r["name"], r["score"]) # add 12.34 # Exact name lookup returns full schema exact = discoverer.discover("add") print(exact[0]["schema"]) # Deferred tools: hide in initial schema, reveal via discover_tools registry._tools["add"].metadata.defer = True hidden_schemas = registry.get_schemas(include_deferred=False) # 'add' not in hidden_schemas; LLM calls discover_tools("add") to get it summaries = registry.get_deferred_summaries() # [{'name': 'add', 'description': 'Add two numbers.', 'namespace': None}] ``` -------------------------------- ### Enable and Query Tool Execution Log Source: https://context7.com/oaklight/toolregistry/llms.txt Activates a thread-safe ring-buffer execution log that records tool call timing, arguments, result, and status. Use disable_logging to turn it off. ```python from toolregistry import ToolRegistry from toolregistry.admin import ExecutionStatus registry = ToolRegistry() @registry.register def add(a: float, b: float) -> float: """Add two numbers.""" return a + b # Enable logging with capacity for 500 entries log = registry.enable_logging(max_entries=500) # ... run tool calls ... # Query recent entries entries = log.get_entries(limit=10) for entry in entries: print(f"{entry.tool_name} | {entry.status.value} | {entry.duration_ms:.2f}ms | result={entry.result}") # Filter by tool name and status errors = log.get_entries(tool_name="add", status=ExecutionStatus.ERROR) # Aggregate statistics stats = log.get_stats() print(stats) # {'total_entries': 42, 'total_added': 42, 'max_entries': 500, # 'by_status': {'success': 40, 'error': 2}, 'by_tool': {'add': 42}, # 'avg_duration_ms': 0.85, 'oldest_entry': datetime(...), 'newest_entry': datetime(...)} # Disable logging registry.disable_logging() ``` -------------------------------- ### Register Tools from OpenAPI Specification Source: https://context7.com/oaklight/toolregistry/llms.txt Register tools from an OpenAPI 3.x specification. `HttpClientConfig` is used to set up headers, authentication, and timeouts for HTTP calls. Tools can be loaded from a URL or a local file. ```python from toolregistry import ToolRegistry from toolregistry.integrations.openapi import HttpClientConfig, load_openapi_spec registry = ToolRegistry() # Load spec from URL (auto-discovers /openapi.json or /swagger.json) openapi_spec = load_openapi_spec("http://localhost:8000") # Or load from a local file (resolves $ref references automatically) openapi_spec = load_openapi_spec("./openapi_spec.json") # Configure the HTTP client client_config = HttpClientConfig( base_url="http://localhost:8000", headers={"Authorization": "Bearer my-token"}, timeout=30.0, ) # Register with optional namespace registry.register_from_openapi(client_config, openapi_spec, namespace="calculator") print(registry.list_tools()) # e.g. ['calculator-add', 'calculator-subtract', 'calculator-multiply'] ``` ```python import asyncio from toolregistry.integrations.openapi import load_openapi_spec_async async def setup(): spec = await load_openapi_spec_async("http://localhost:8000") async with ToolRegistry() as reg: await reg.register_from_openapi_async(client_config, spec) print(reg.list_tools()) asyncio.run(setup()) ``` -------------------------------- ### Subscribe to Tool Registry Change Events Source: https://context7.com/oaklight/toolregistry/llms.txt Subscribes to registry change events (REGISTER, UNREGISTER, ENABLE, DISABLE, METADATA_UPDATE, PERMISSION_DENIED, PERMISSION_ASKED). Use remove_on_change to unsubscribe. ```python from toolregistry import ToolRegistry from toolregistry.events import ChangeEvent, ChangeEventType registry = ToolRegistry() def audit_handler(event: ChangeEvent) -> None: print(f"[{event.event_type.value}] tool={event.tool_name}, reason={event.reason}") registry.on_change(audit_handler) @registry.register def my_tool(x: int) -> int: """Double a number.""" return x * 2 # Prints: [register] tool=my_tool, reason=None registry.disable("my_tool", reason="Maintenance") # Prints: [disable] tool=my_tool, reason=Maintenance # Unsubscribe registry.remove_on_change(audit_handler) ``` -------------------------------- ### Registering MCP Transports Source: https://github.com/oaklight/toolregistry/blob/master/README_en.md Demonstrates various ways to define and register MCP transports, including URLs, local paths, dictionary configurations, FastMCP instances, and StreamableHttpTransport instances with custom headers. ```python transport = "https://mcphub.url/mcp" # Streamable HTTP MCP ``` ```python transport = "http://localhost:8000/sse/test_group" # Legacy HTTP+SSE ``` ```python transport = "examples/mcp_related/mcp_servers/math_server.py" # Local path ``` ```python transport = { "mcpServers": { "make_mcp": { "command": f"{Path.home()}/mambaforge/envs/toolregistry_dev/bin/python", "args": [ f"{Path.home()}/projects/toolregistry/examples/mcp_related/mcp_servers/math_server.py" ], "env": {}, } } } # MCP configuration dictionary example ``` ```python transport = FastMCP(name="MyFastMCP") # FastMCP instance ``` ```python transport = StreamableHttpTransport(url="https://mcphub.example.com/mcp", headers={"Authorization": "Bearer token"}) # Transport instance with custom headers ``` ```python registry.register_from_mcp(transport) ``` ```python tools_json = registry.get_schemas() ``` -------------------------------- ### Enable Namespace Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Enables a given namespace via the API. Shows a success toast and refreshes namespaces, tools, and stats upon completion. Handles errors by showing an error toast. ```javascript async function enableNamespace(name) { try { await api.enableNamespace(name); showToast(t('toast.nsEnabled', {name}), 'success'); refreshNamespaces(); refreshTools(); refreshStats(); } catch (e) { showToast(e.message, 'error'); } } ``` -------------------------------- ### Create Starlette App from FastMCP Source: https://github.com/oaklight/toolregistry/blob/master/examples/mcp_related/README.md Generate a Starlette application instance from the configured FastMCP server. This app can then be run with a server like uvicorn. ```python app = mcp.sse_app() ``` -------------------------------- ### ToolRegistry.enable_tool_discovery Source: https://context7.com/oaklight/toolregistry/llms.txt Registers a built-in `discover_tools` function that uses BM25F full-text search over tool names, descriptions, tags, parameter names, and `search_hint`. LLMs can call it to find tools by natural language query or exact name. ```APIDOC ## `ToolRegistry.enable_tool_discovery` Registers a built-in `discover_tools` function that uses BM25F full-text search over tool names, descriptions, tags, parameter names, and `search_hint`. LLMs can call it to find tools by natural language query or exact name. ### Method Signature `enable_tool_discovery()` ### Returns - **discoverer** (object) - An object with a `discover` method for searching tools. ### `discoverer.discover` Method - **query** (str) - The natural language query or exact tool name. - **top_k** (int) - The number of top results to return. ### Example Usage ```python from toolregistry import ToolRegistry from toolregistry.tool import Tool, ToolMetadata registry = ToolRegistry() @registry.register def add(a: float, b: float) -> float: """Add two numbers.""" return a + b registry._tools["add"].metadata.search_hint = "sum plus arithmetic addition" discovers = registry.enable_tool_discovery() results = discovers.discover("add numbers", top_k=5) for r in results: print(r["name"], r["score"]) exact = discovers.discover("add") print(exact[0]["schema"]) registry._tools["add"].metadata.defer = True hidden_schemas = registry.get_schemas(include_deferred=False) summaries = registry.get_deferred_summaries() print(summaries) ``` ``` -------------------------------- ### Admin API Client Class Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Provides a client for interacting with the Tool Registry admin API. Handles authentication, request formatting, and error handling for various API endpoints. ```javascript class AdminAPI { constructor(baseUrl, token) { this.baseUrl = baseUrl; this.token = token; } getHeaders() { const headers = { 'Content-Type': 'application/json' }; if (this.token) { headers['Authorization'] = 'Bearer ' + this.token; } return headers; } async request(path, options = {}) { options.headers = { ...this.getHeaders(), ...options.headers }; try { const response = await fetch(this.baseUrl + path, options); if (response.status === 401) { const token = prompt(t('misc.enterToken')); if (token) { localStorage.setItem('admin_token', token); this.token = token; AUTH_TOKEN = token; return this.request(path, options); } throw new Error('Unauthorized'); } const data = await response.json(); if (!response.ok) { throw new Error(data.message || 'Request failed'); } return data; } catch (error) { if (error.name === 'TypeError') { updateConnectionStatus(false); throw new Error('Connection failed'); } throw error; } } async getTools() { return this.request('/api/tools'); } async getTool(name) { return this.request('/api/tools/' + encodeURIComponent(name)); } async enableTool(name) { return this.request('/api/tools/' + encodeURIComponent(name) + '/enable', { method: 'POST' }); } async disableTool(name, reason = '') { return this.request('/api/tools/' + encodeURIComponent(name) + '/disable', { method: 'POST', body: JSON.stringify({ reason }) }); } async getNamespaces() { return this.request('/api/namespaces'); } async enableNamespace(ns) { return this.request('/api/namespaces/' + encodeURIComponent(ns) + '/enable', { method: 'POST' }); } async disableNamespace(ns, reason = '') { return this.request('/api/namespaces/' + encodeURIComponent(ns) + '/disable', { method: 'POST', body: JSON.stringify({ reason }) }); } async updateToolMetadata(name, metadata) { return this.request('/api/tools/' + encodeURIComponent(name) + '/metadata', { method: 'PATCH', body: JSON.stringify(metadata) }); } async updateNamespaceMetadata(ns, metadata) { return this.request('/api/namespaces/' + encodeURIComponent(ns) + '/metadata', { method: 'PATCH', body: JSON.stringify(metadata) }); } async getLogs(params = {}) { const query = new URLSearchParams(); if (params.limit) query.set('limit', params.limit); if (params.tool_name) query.set('tool_name', params.tool_name); if (params.status) query.set('status', params.status); const queryStr = query.toString(); return this.request('/api/logs' + (queryStr ? '?' + queryStr : '')); } async getLogStats() { return this.request('/api/logs/stats'); } async clearLogs() { return this.request('/api/logs', { method: 'DELETE' }); } async exportState() { return this.request('/api/state'); } async importState(state) { return this.request('/api/state', { method: 'POST', body: JSON.stringify(state) }); } async getPermissions() { return this.request('/api/permissions'); } } ``` -------------------------------- ### Register Tools from a Class Source: https://context7.com/oaklight/toolregistry/llms.txt Register all public methods from a class or instance as tools. The `namespace` parameter controls whether tool names are prefixed with the class name. ```python from toolregistry import ToolRegistry class MathTools: @staticmethod def multiply(a: float, b: float) -> float: """Multiply two numbers.""" return a * b @staticmethod def divide(a: float, b: float) -> float: """Divide a by b.""" if b == 0: raise ValueError("Division by zero") return a / b class GreeterInstance: def __init__(self, greeting: str): self.greeting = greeting def greet(self, name: str) -> str: """Greet a person.""" return f"{self.greeting}, {name}!" registry = ToolRegistry() # Class (static methods, namespace derived from class name) registry.register_from_class(MathTools, namespace=True) print(registry.list_tools()) # ['math_tools-multiply', 'math_tools-divide'] # Instance (instance methods bound to the object) registry.register_from_class(GreeterInstance("Hello"), namespace="greeter") print(registry.list_tools()) # [..., 'greeter-greet'] # Call via subscript result = registry["math_tools-multiply"](3, 4) print(result) # 12.0 ``` -------------------------------- ### UI Helper: Show Modal Dialog Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Displays a modal dialog with a title, content, and confirmation/cancellation actions. The `onCancel` callback is stored globally. ```javascript let _modalOnCancel = null; function showModal(title, content, onConfirm, onCancel) { document.getElementById('modal-t ``` -------------------------------- ### State Management Source: https://github.com/oaklight/toolregistry/blob/master/src/toolregistry/admin/admin.html Endpoints for exporting and importing the system's state. ```APIDOC ## GET /api/state ### Description Exports the current state of the tool registry system. ### Method GET ### Endpoint /api/state ### Response #### Success Response (200) - **state** (object) - The current system state. #### Response Example { "state": { "tools": { ... }, "namespaces": { ... } } } ## POST /api/state ### Description Imports a system state into the tool registry. ### Method POST ### Endpoint /api/state ### Parameters #### Request Body - **state** (object) - Required - The system state to import. ### Request Example { "state": { "tools": { ... }, "namespaces": { ... } } } ```