Documentation Index
Fetch the complete documentation index at: https://docs.praison.ai/llms.txt
Use this file to discover all available pages before exploring further.
MCP Tool Search Module
The MCP Server V2 provides a powerful tool search capability as an extension method (tools/search). This is not part of the core MCP spec but provides valuable server-side filtering.
Overview
Tool search supports:
- Text query: Search in name, description, and tags
- Category filter: Filter by tool category
- Tags filter: Filter by one or more tags
- Annotation filter: Filter by
readOnlyHint
- Pagination: Results are paginated like
tools/list
Code Usage
Basic Search
from praisonai.mcp_server.registry import MCPToolRegistry, MCPToolDefinition
# Create registry with tools
registry = MCPToolRegistry()
registry._tools["memory.show"] = MCPToolDefinition(
name="memory.show",
description="Show memory contents",
handler=lambda: None,
input_schema={"type": "object"},
category="memory",
read_only_hint=True,
)
registry._tools["file.delete"] = MCPToolDefinition(
name="file.delete",
description="Delete a file",
handler=lambda: None,
input_schema={"type": "object"},
category="file",
destructive_hint=True,
)
# Search by query
results, next_cursor, total = registry.search(query="memory")
print(f"Found {total} tools matching 'memory'")
Search by Category
# Find all file-related tools
results, _, total = registry.search(category="file")
print(f"Found {total} file tools")
for tool in results:
print(f" - {tool['name']}")
Search by Read-Only Hint
# Find all read-only tools (safe to call without side effects)
results, _, total = registry.search(read_only=True)
print(f"Found {total} read-only tools")
# Find all non-read-only tools (may modify state)
results, _, total = registry.search(read_only=False)
print(f"Found {total} tools that may modify state")
# Register tool with tags
registry._tools["web.search"] = MCPToolDefinition(
name="web.search",
description="Search the web",
handler=lambda: None,
input_schema={"type": "object"},
tags=["search", "internet", "query"],
)
# Search by tags (any match)
results, _, total = registry.search(tags=["search"])
print(f"Found {total} tools with 'search' tag")
Combined Filters
# Find read-only tools in memory category
results, _, total = registry.search(
category="memory",
read_only=True,
)
# Find tools matching query with specific category
results, _, total = registry.search(
query="show",
category="memory",
)
Paginated Search
# Search with pagination
results, next_cursor, total = registry.search(
query="tool",
page_size=10,
)
print(f"Page 1: {len(results)} of {total} total")
# Get next page
if next_cursor:
results2, next_cursor2, _ = registry.search(
query="tool",
cursor=next_cursor,
page_size=10,
)
print(f"Page 2: {len(results2)} results")
Server Handler
The MCP server exposes search via the tools/search method:
from praisonai.mcp_server.server import MCPServer
import asyncio
server = MCPServer(name="my-server")
async def demo():
# Simulate client request
result = await server._handle_tools_search({
"query": "memory",
"category": "memory",
"readOnly": True,
})
print(f"Found {result['total']} tools")
for tool in result['tools']:
print(f" - {tool['name']}")
asyncio.run(demo())
Request Parameters
| Parameter | Type | Description |
|---|
query | string | Text to search in name, description, tags |
category | string | Filter by category |
tags | array | Filter by tags (any match) |
readOnly | boolean | Filter by readOnlyHint |
cursor | string | Pagination cursor |
{
"tools": [
{
"name": "memory.show",
"description": "Show memory contents",
"inputSchema": {"type": "object"},
"annotations": {"readOnlyHint": true}
}
],
"total": 1,
"nextCursor": null
}
Search Algorithm
The search implementation:
-
Query matching: Case-insensitive search in:
- Tool name
- Tool description
- Tool tags (if any)
-
Filter application: All filters are AND-ed together
-
Sorting: Results are sorted by name for deterministic ordering
-
Pagination: Applied after filtering and sorting
from praisonai.mcp_server.registry import MCPToolRegistry
def discover_tools(registry: MCPToolRegistry):
"""Discover and categorize available tools."""
# Find safe tools (read-only)
safe_tools, _, _ = registry.search(read_only=True)
print(f"Safe tools ({len(safe_tools)}):")
for t in safe_tools:
print(f" ✓ {t['name']}")
# Find potentially dangerous tools
dangerous, _, _ = registry.search(read_only=False)
print(f"\nTools that may modify state ({len(dangerous)}):")
for t in dangerous:
print(f" ⚠ {t['name']}")
# Group by category
categories = set()
all_tools, _, _ = registry.search()
for t in all_tools:
# Extract category from annotations or name
name_parts = t['name'].split('.')
if len(name_parts) > 1:
categories.add(name_parts[-2])
print(f"\nCategories: {', '.join(sorted(categories))}")
See Also