Updated all 12 MCP tool docstrings with: - LLM-visible priority markers in docstrings (was hidden in meta) - Decision trees to disambiguate overlapping tools - Standard Python docstring format with Examples sections - Enhanced safety protocols for destructive operations - Increased priority for search_memory_facts (0.85) and get_entities_by_type (0.75) Changes are docstring-only with no breaking changes to functionality. Validated with ruff format, ruff check, and py_compile. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1004 lines
30 KiB
Markdown
1004 lines
30 KiB
Markdown
# MCP Tool Descriptions - Production-Ready Revision
|
|
|
|
**Date:** November 9, 2025
|
|
**Status:** Implementation Ready
|
|
**MCP Compliance:** Validated against MCP SDK 1.21.0 and 2025-06-18 specification
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
This document contains MCP-compliant tool descriptions optimized for LLM tool selection accuracy. All changes are **docstring-only** with no breaking changes to functionality.
|
|
|
|
**Key Design Principles:**
|
|
1. ✅ **LLM-visible priority** - Critical information in docstrings, not hidden in meta
|
|
2. ✅ **Decision trees** - Clear guidance for overlapping tools
|
|
3. ✅ **Standard annotations** - Using only MCP-specified fields
|
|
4. ✅ **Accessibility first** - No emojis, clear language
|
|
5. ✅ **Proven patterns** - Standard Python docstring conventions
|
|
|
|
**What Changed:**
|
|
- Priority guidance moved INTO docstrings (LLM-visible)
|
|
- Decision trees added for tool disambiguation
|
|
- Examples in standard format (after Args section)
|
|
- Clearer differentiation between overlapping tools
|
|
- No cosmetic changes (emojis, etc.)
|
|
|
|
---
|
|
|
|
## MCP Compliance Verification
|
|
|
|
### Annotations Used (All Standard)
|
|
```python
|
|
annotations={
|
|
'title': str, # Display name
|
|
'readOnlyHint': bool, # Never modifies data
|
|
'destructiveHint': bool, # May destroy data
|
|
'idempotentHint': bool, # Safe to retry
|
|
'openWorldHint': bool, # Accesses external resources
|
|
}
|
|
```
|
|
|
|
### Additional Parameters (SDK-Supported)
|
|
```python
|
|
tags={'category', 'keywords'} # For client filtering
|
|
meta={ # For client UX (NOT visible to LLM)
|
|
'version': str,
|
|
'category': str,
|
|
'priority': float, # Client hint only
|
|
}
|
|
```
|
|
|
|
**Critical:** Meta fields are NOT visible to LLMs. Priority/importance MUST be in docstring.
|
|
|
|
---
|
|
|
|
## Tool Descriptions - Ready for Implementation
|
|
|
|
### Tool 1: `add_memory` (PRIMARY STORAGE)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Add Memory',
|
|
'readOnlyHint': False,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'write', 'memory', 'ingestion', 'core'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'core',
|
|
'priority': 0.9,
|
|
},
|
|
)
|
|
async def add_memory(
|
|
name: str,
|
|
episode_body: str,
|
|
group_id: str | None = None,
|
|
source: str = 'text',
|
|
source_description: str = '',
|
|
uuid: str | None = None,
|
|
) -> SuccessResponse | ErrorResponse:
|
|
"""Add information to memory. **This is the PRIMARY method for storing information.**
|
|
|
|
**PRIORITY: Use this tool FIRST when storing any information.**
|
|
|
|
Processes content asynchronously, automatically extracting entities, relationships,
|
|
and deduplicating similar information. Returns immediately while processing continues
|
|
in background.
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- Storing information → add_memory (this tool) **USE THIS FIRST**
|
|
- Searching information → use search_nodes or search_memory_facts
|
|
- Deleting information → use delete_episode or delete_entity_edge
|
|
|
|
Use Cases:
|
|
- Recording conversation context, insights, or observations
|
|
- Storing user preferences, requirements, or procedures
|
|
- Capturing information about people, organizations, events, topics
|
|
- Importing structured data (JSON format)
|
|
- Updating existing information (provide uuid parameter)
|
|
|
|
Args:
|
|
name: Brief descriptive title for this memory episode
|
|
episode_body: Content to store. For JSON source, must be properly escaped JSON string
|
|
group_id: Optional namespace for organizing memories (uses default if not provided)
|
|
source: Content format - 'text', 'json', or 'message' (default: 'text')
|
|
source_description: Optional context about where this information came from
|
|
uuid: ONLY for updates - provide existing episode UUID. DO NOT provide for new memories
|
|
|
|
Returns:
|
|
SuccessResponse confirming episode was queued for processing
|
|
|
|
Examples:
|
|
# Store plain text observation
|
|
add_memory(
|
|
name="Customer preference",
|
|
episode_body="Acme Corp prefers email communication over phone calls"
|
|
)
|
|
|
|
# Store structured data
|
|
add_memory(
|
|
name="Product catalog",
|
|
episode_body='{"company": "Acme", "products": [{"id": "P001", "name": "Widget"}]}',
|
|
source="json"
|
|
)
|
|
|
|
# Update existing episode
|
|
add_memory(
|
|
name="Customer preference",
|
|
episode_body="Acme Corp prefers Slack communication",
|
|
uuid="abc-123-def-456" # UUID from previous get_episodes or search
|
|
)
|
|
"""
|
|
```
|
|
|
|
**Changes:**
|
|
- Added "**This is the PRIMARY method**" in first line (LLM-visible)
|
|
- Added "**PRIORITY: Use this tool FIRST**" guidance
|
|
- Decision tree at top for quick disambiguation
|
|
- Examples in standard location after Args
|
|
- Removed emoji from title
|
|
|
|
---
|
|
|
|
### Tool 2: `search_nodes` (PRIMARY ENTITY SEARCH)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Search Memory Entities',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'search', 'entities', 'memory', 'core'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'core',
|
|
'priority': 0.8,
|
|
},
|
|
)
|
|
async def search_nodes(
|
|
query: str,
|
|
group_ids: list[str] | None = None,
|
|
max_nodes: int = 10,
|
|
entity_types: list[str] | None = None,
|
|
) -> NodeSearchResponse | ErrorResponse:
|
|
"""Search for entities by name or content. **PRIMARY method for finding entities.**
|
|
|
|
**PRIORITY: Use this tool for entity searches (people, organizations, concepts).**
|
|
|
|
Searches entity names, summaries, and attributes using hybrid semantic + keyword matching.
|
|
Returns the entities themselves (nodes), not relationships or conversation content.
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- Finding specific entities by name/content → search_nodes (this tool) **USE THIS**
|
|
- Listing ALL entities of a type → use get_entities_by_type
|
|
- Searching conversation content or relationships → use search_memory_facts
|
|
|
|
Use Cases:
|
|
- "Find information about Acme Corporation"
|
|
- "Search for entities related to Python programming"
|
|
- "What entities exist about productivity?"
|
|
- Retrieving entities before adding related information
|
|
|
|
Args:
|
|
query: Search keywords or semantic description
|
|
group_ids: Optional list of memory namespaces to search within
|
|
max_nodes: Maximum number of results to return (default: 10)
|
|
entity_types: Optional filter by entity types (e.g., ["Organization", "Person"])
|
|
|
|
Returns:
|
|
NodeSearchResponse containing matching entities with names, summaries, and metadata
|
|
|
|
Examples:
|
|
# Find entities by name
|
|
search_nodes(query="Acme")
|
|
|
|
# Semantic search
|
|
search_nodes(query="companies in the technology sector")
|
|
|
|
# Filter by entity type
|
|
search_nodes(
|
|
query="productivity",
|
|
entity_types=["Insight", "Pattern"]
|
|
)
|
|
"""
|
|
```
|
|
|
|
**Changes:**
|
|
- "**PRIMARY method for finding entities**" in first line
|
|
- Clear priority guidance for LLMs
|
|
- Decision tree distinguishes from search_memory_facts and get_entities_by_type
|
|
- Examples show different search patterns
|
|
- Clean title without emoji
|
|
|
|
---
|
|
|
|
### Tool 3: `search_memory_facts` (PRIMARY CONTENT SEARCH)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Search Memory Facts',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'search', 'facts', 'relationships', 'memory', 'core'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'core',
|
|
'priority': 0.85,
|
|
},
|
|
)
|
|
async def search_memory_facts(
|
|
query: str,
|
|
group_ids: list[str] | None = None,
|
|
max_facts: int = 10,
|
|
center_node_uuid: str | None = None,
|
|
) -> FactSearchResponse | ErrorResponse:
|
|
"""Search conversation content and relationships. **PRIMARY method for content search.**
|
|
|
|
**PRIORITY: Use this tool for searching conversation/episode content and entity relationships.**
|
|
|
|
"Facts" in this context means relationships/connections between entities, not factual
|
|
statements. Searches the actual conversation content and how entities are connected.
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- Searching conversation/episode content → search_memory_facts (this tool) **USE THIS**
|
|
- Finding entity relationships → search_memory_facts (this tool) **USE THIS**
|
|
- Finding entities by name → use search_nodes
|
|
- Listing entities by type → use get_entities_by_type
|
|
|
|
Use Cases:
|
|
- "What conversations mentioned pricing?"
|
|
- "How is Acme Corp related to our products?"
|
|
- "Find relationships between User and productivity patterns"
|
|
- Searching what was actually said in conversations
|
|
|
|
Args:
|
|
query: Search query for conversation content or relationships
|
|
group_ids: Optional list of memory namespaces to search within
|
|
max_facts: Maximum number of results to return (default: 10)
|
|
center_node_uuid: Optional entity UUID to center search around (find relationships)
|
|
|
|
Returns:
|
|
FactSearchResponse containing matching relationships with source, target, and context
|
|
|
|
Examples:
|
|
# Search conversation content
|
|
search_memory_facts(query="discussions about budget")
|
|
|
|
# Find entity relationships
|
|
search_memory_facts(
|
|
query="collaboration",
|
|
center_node_uuid="entity-uuid-123"
|
|
)
|
|
|
|
# Broad relationship search
|
|
search_memory_facts(query="how does Acme relate to pricing")
|
|
"""
|
|
```
|
|
|
|
**Changes:**
|
|
- "**PRIMARY method for content search**" in first line
|
|
- Explicit priority guidance
|
|
- Clarified "facts = relationships" confusion
|
|
- Decision tree clearly separates from search_nodes
|
|
- Use cases show conversation search vs entity search
|
|
|
|
---
|
|
|
|
### Tool 4: `get_entities_by_type` (BROWSE BY TYPE)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Get Entities by Type',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'search', 'entities', 'browse', 'classification'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'discovery',
|
|
'priority': 0.75,
|
|
},
|
|
)
|
|
async def get_entities_by_type(
|
|
entity_types: list[str],
|
|
group_ids: list[str] | None = None,
|
|
max_entities: int = 20,
|
|
query: str | None = None,
|
|
) -> NodeSearchResponse | ErrorResponse:
|
|
"""Retrieve ALL entities of specified type(s), optionally filtered by query.
|
|
|
|
**Use this to browse/list entities by their classification type.**
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- Listing ALL entities of a type → get_entities_by_type (this tool) **USE THIS**
|
|
- Searching entities by content → use search_nodes
|
|
- Searching relationships/content → use search_memory_facts
|
|
|
|
Use Cases:
|
|
- "Show me all Preferences"
|
|
- "List all Insights and Patterns"
|
|
- "Get all Organizations" (optionally filtered by keyword)
|
|
- Browsing knowledge organized by entity classification
|
|
|
|
Args:
|
|
entity_types: REQUIRED. Type(s) to retrieve (e.g., ["Insight"], ["Preference", "Requirement"])
|
|
group_ids: Optional list of memory namespaces to search within
|
|
max_entities: Maximum results (default: 20, higher than search tools)
|
|
query: Optional keyword filter within the type(s). Omit to get ALL entities of type
|
|
|
|
Returns:
|
|
NodeSearchResponse containing all entities of the specified type(s)
|
|
|
|
Examples:
|
|
# Get ALL entities of a type
|
|
get_entities_by_type(entity_types=["Preference"])
|
|
|
|
# Get multiple types
|
|
get_entities_by_type(entity_types=["Insight", "Pattern"])
|
|
|
|
# Filter within a type
|
|
get_entities_by_type(
|
|
entity_types=["Organization"],
|
|
query="technology"
|
|
)
|
|
"""
|
|
```
|
|
|
|
**Changes:**
|
|
- Clear "browse/list" positioning
|
|
- Decision tree separates from search tools
|
|
- Emphasized that query is optional (can get ALL)
|
|
- Higher default max_entities (20 vs 10) documented
|
|
|
|
---
|
|
|
|
### Tool 5: `compare_facts_over_time` (TEMPORAL ANALYSIS)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Compare Facts Over Time',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'search', 'facts', 'temporal', 'analysis', 'evolution'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'analytics',
|
|
'priority': 0.6,
|
|
},
|
|
)
|
|
async def compare_facts_over_time(
|
|
query: str,
|
|
start_time: str,
|
|
end_time: str,
|
|
group_ids: list[str] | None = None,
|
|
max_facts_per_period: int = 10,
|
|
) -> dict[str, Any] | ErrorResponse:
|
|
"""Compare relationships/facts between two time periods to track knowledge evolution.
|
|
|
|
**Use for temporal analysis - how information changed over time.**
|
|
|
|
Returns four categories: facts at start, facts at end, facts invalidated, facts added.
|
|
Useful for understanding how knowledge evolved or changed during a specific time window.
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- Analyzing how information changed over time → compare_facts_over_time (this tool)
|
|
- Current/recent information → use search_memory_facts
|
|
- Single point-in-time search → use search_memory_facts
|
|
|
|
Use Cases:
|
|
- "How did our understanding of Acme Corp change this month?"
|
|
- "What information was added/updated between Jan-Feb?"
|
|
- "Track evolution of productivity insights over Q1"
|
|
|
|
Args:
|
|
query: Search query for facts to track over time
|
|
start_time: Start timestamp in ISO 8601 format (e.g., "2024-01-01" or "2024-01-01T10:30:00Z")
|
|
end_time: End timestamp in ISO 8601 format
|
|
group_ids: Optional list of memory namespaces to analyze
|
|
max_facts_per_period: Maximum facts per category (default: 10)
|
|
|
|
Returns:
|
|
Dictionary with: facts_from_start, facts_at_end, facts_invalidated, facts_added
|
|
|
|
Examples:
|
|
# Track changes over a month
|
|
compare_facts_over_time(
|
|
query="customer requirements",
|
|
start_time="2024-01-01",
|
|
end_time="2024-01-31"
|
|
)
|
|
|
|
# Analyze knowledge evolution
|
|
compare_facts_over_time(
|
|
query="productivity patterns",
|
|
start_time="2024-01-01T00:00:00Z",
|
|
end_time="2024-03-31T23:59:59Z"
|
|
)
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
### Tool 6: `get_entity_edge` (DIRECT UUID LOOKUP)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Get Entity Edge by UUID',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'retrieval', 'facts', 'uuid', 'direct-access'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'direct-access',
|
|
'priority': 0.5,
|
|
},
|
|
)
|
|
async def get_entity_edge(uuid: str) -> dict[str, Any] | ErrorResponse:
|
|
"""Retrieve a specific relationship/fact by its UUID. **Direct lookup only.**
|
|
|
|
**Use ONLY when you already have the exact UUID from a previous search.**
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- You have a UUID from previous search → get_entity_edge (this tool)
|
|
- Searching for facts → use search_memory_facts
|
|
- Don't have a UUID → use search_memory_facts
|
|
|
|
Args:
|
|
uuid: UUID of the relationship to retrieve
|
|
|
|
Returns:
|
|
Dictionary with fact details (source entity, target entity, relationship, timestamps)
|
|
|
|
Examples:
|
|
# Retrieve specific relationship
|
|
get_entity_edge(uuid="abc-123-def-456")
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
### Tool 7: `get_episodes` (RECENT EPISODES)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Get Recent Episodes',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'retrieval', 'episodes', 'history', 'changelog'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'direct-access',
|
|
'priority': 0.5,
|
|
},
|
|
)
|
|
async def get_episodes(
|
|
group_id: str | None = None,
|
|
group_ids: list[str] | None = None,
|
|
last_n: int | None = None,
|
|
max_episodes: int = 10,
|
|
) -> EpisodeSearchResponse | ErrorResponse:
|
|
"""Retrieve recent episodes by recency. **Like 'git log' for memory.**
|
|
|
|
**Use for listing what was added recently, NOT for searching content.**
|
|
|
|
Think: "git log" (this tool) vs "git grep" (search_memory_facts)
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- List recent additions to memory → get_episodes (this tool)
|
|
- Audit what was added recently → get_episodes (this tool)
|
|
- Search episode CONTENT → use search_memory_facts
|
|
- Find episodes by keywords → use search_memory_facts
|
|
|
|
Use Cases:
|
|
- "What was added to memory recently?"
|
|
- "Show me the last 10 episodes"
|
|
- "List recent memory additions as a changelog"
|
|
|
|
Args:
|
|
group_id: Single memory namespace (legacy parameter)
|
|
group_ids: List of memory namespaces (preferred)
|
|
last_n: Maximum episodes (legacy parameter, use max_episodes instead)
|
|
max_episodes: Maximum episodes to return (default: 10)
|
|
|
|
Returns:
|
|
EpisodeSearchResponse with episodes sorted by recency (newest first)
|
|
|
|
Examples:
|
|
# Get recent episodes
|
|
get_episodes(max_episodes=10)
|
|
|
|
# Get recent episodes from specific namespace
|
|
get_episodes(group_ids=["my-project"], max_episodes=20)
|
|
"""
|
|
```
|
|
|
|
**Changes:**
|
|
- Added "git log vs git grep" analogy
|
|
- Clear separation from content search
|
|
- Emphasized recency, not content
|
|
|
|
---
|
|
|
|
### Tool 8: `delete_entity_edge` (DESTRUCTIVE)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Delete Entity Edge',
|
|
'readOnlyHint': False,
|
|
'destructiveHint': True,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'delete', 'destructive', 'facts', 'admin'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'maintenance',
|
|
'priority': 0.3,
|
|
},
|
|
)
|
|
async def delete_entity_edge(uuid: str) -> SuccessResponse | ErrorResponse:
|
|
"""Delete a specific relationship/fact. **DESTRUCTIVE - Cannot be undone.**
|
|
|
|
**WARNING: This operation is permanent and irreversible.**
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- User explicitly confirms deletion → delete_entity_edge (this tool)
|
|
- Removing verified incorrect relationship → delete_entity_edge (this tool)
|
|
- Updating information → use add_memory (preferred)
|
|
- Marking as outdated → system handles automatically
|
|
|
|
Safety Requirements:
|
|
- Only use after explicit user confirmation
|
|
- Verify UUID is correct before deleting
|
|
- Cannot be undone - ensure user understands
|
|
- Idempotent (safe to retry if operation fails)
|
|
|
|
Args:
|
|
uuid: UUID of the relationship to permanently delete
|
|
|
|
Returns:
|
|
SuccessResponse confirming deletion
|
|
|
|
Examples:
|
|
# Delete after user confirmation
|
|
delete_entity_edge(uuid="abc-123-def-456")
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
### Tool 9: `delete_episode` (DESTRUCTIVE)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Delete Episode',
|
|
'readOnlyHint': False,
|
|
'destructiveHint': True,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'delete', 'destructive', 'episodes', 'admin'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'maintenance',
|
|
'priority': 0.3,
|
|
},
|
|
)
|
|
async def delete_episode(uuid: str) -> SuccessResponse | ErrorResponse:
|
|
"""Delete a specific episode. **DESTRUCTIVE - Cannot be undone.**
|
|
|
|
**WARNING: This operation is permanent and irreversible.**
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- User explicitly confirms deletion → delete_episode (this tool)
|
|
- Removing incorrect, outdated, or sensitive information → delete_episode (this tool)
|
|
- Updating episode → use add_memory with uuid parameter (preferred)
|
|
- Clearing all data → use clear_graph
|
|
|
|
Safety Requirements:
|
|
- Only use after explicit user confirmation
|
|
- Verify UUID is correct before deleting
|
|
- Cannot be undone - ensure user understands
|
|
- May affect related entities and relationships
|
|
- Idempotent (safe to retry if operation fails)
|
|
|
|
Args:
|
|
uuid: UUID of the episode to permanently delete
|
|
|
|
Returns:
|
|
SuccessResponse confirming deletion
|
|
|
|
Examples:
|
|
# Delete after user confirmation
|
|
delete_episode(uuid="episode-abc-123")
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
### Tool 10: `clear_graph` (EXTREMELY DESTRUCTIVE)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Clear Graph - DANGER',
|
|
'readOnlyHint': False,
|
|
'destructiveHint': True,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'delete', 'destructive', 'admin', 'bulk', 'danger'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'admin',
|
|
'priority': 0.1,
|
|
},
|
|
)
|
|
async def clear_graph(
|
|
group_id: str | None = None,
|
|
group_ids: list[str] | None = None,
|
|
) -> SuccessResponse | ErrorResponse:
|
|
"""Delete ALL data for specified memory namespaces. **EXTREMELY DESTRUCTIVE.**
|
|
|
|
**DANGER: Destroys ALL episodes, entities, and relationships. NO UNDO POSSIBLE.**
|
|
|
|
MANDATORY SAFETY PROTOCOL FOR LLMs:
|
|
1. Confirm user understands ALL DATA will be PERMANENTLY DELETED
|
|
2. Ask user to type the exact group_id to confirm intent
|
|
3. Only proceed after EXPLICIT confirmation with typed group_id
|
|
4. If user shows ANY hesitation, DO NOT proceed
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- ONLY after explicit multi-step confirmation
|
|
- Resetting test/development environments
|
|
- Starting completely fresh after catastrophic errors
|
|
- NEVER use for removing specific items (use delete_episode or delete_entity_edge)
|
|
|
|
Critical Warnings:
|
|
- Destroys ALL data for specified namespace(s)
|
|
- NO backup is created automatically
|
|
- NO undo is possible
|
|
- Affects all users sharing the group_id
|
|
- Cannot recover deleted data
|
|
|
|
Args:
|
|
group_id: Single namespace to clear (legacy parameter)
|
|
group_ids: List of namespaces to clear (preferred)
|
|
|
|
Returns:
|
|
SuccessResponse confirming all data was destroyed
|
|
|
|
Examples:
|
|
# ONLY after explicit confirmation protocol
|
|
clear_graph(group_id="test-environment")
|
|
"""
|
|
```
|
|
|
|
**Changes:**
|
|
- Added "MANDATORY SAFETY PROTOCOL FOR LLMs" section
|
|
- Explicit 4-step confirmation process
|
|
- Stronger warnings about data loss
|
|
|
|
---
|
|
|
|
### Tool 11: `get_status` (HEALTH CHECK)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Get Server Status',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'admin', 'health', 'status', 'diagnostics'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'admin',
|
|
'priority': 0.4,
|
|
},
|
|
)
|
|
async def get_status() -> StatusResponse:
|
|
"""Check server health and database connectivity.
|
|
|
|
**Use for diagnostics and health checks.**
|
|
|
|
WHEN TO USE THIS TOOL:
|
|
- Verifying server is operational → get_status (this tool)
|
|
- Diagnosing connection issues → get_status (this tool)
|
|
- Pre-flight health check → get_status (this tool)
|
|
- Retrieving data → use search tools (not this)
|
|
|
|
Returns:
|
|
StatusResponse with status ('ok' or 'error') and connection details
|
|
|
|
Examples:
|
|
# Check server health
|
|
get_status()
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
### Tool 12: `search_memory_nodes` (LEGACY ALIAS)
|
|
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
'title': 'Search Memory Nodes',
|
|
'readOnlyHint': True,
|
|
'destructiveHint': False,
|
|
'idempotentHint': True,
|
|
'openWorldHint': True,
|
|
},
|
|
tags={'search', 'entities', 'legacy', 'compatibility'},
|
|
meta={
|
|
'version': '1.0',
|
|
'category': 'compatibility',
|
|
'priority': 0.7,
|
|
'note': 'Legacy alias - prefer search_nodes for new code',
|
|
},
|
|
)
|
|
async def search_memory_nodes(
|
|
query: str,
|
|
group_id: str | None = None,
|
|
group_ids: list[str] | None = None,
|
|
max_nodes: int = 10,
|
|
entity_types: list[str] | None = None,
|
|
) -> NodeSearchResponse | ErrorResponse:
|
|
"""Search for entities. **Legacy compatibility alias for search_nodes.**
|
|
|
|
**For new code, prefer using search_nodes instead.**
|
|
|
|
This tool provides backward compatibility with older clients. It delegates to
|
|
search_nodes with identical functionality.
|
|
|
|
Args:
|
|
query: Search query for finding entities
|
|
group_id: Single namespace (legacy parameter)
|
|
group_ids: List of namespaces (preferred)
|
|
max_nodes: Maximum results (default: 10)
|
|
entity_types: Optional type filter
|
|
|
|
Returns:
|
|
NodeSearchResponse (delegates to search_nodes)
|
|
|
|
Examples:
|
|
# Works identically to search_nodes
|
|
search_memory_nodes(query="Acme")
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Instructions
|
|
|
|
### Step 1: Update Tool Docstrings
|
|
|
|
Use Serena's symbolic editing tools to update each tool's docstring:
|
|
|
|
```bash
|
|
# For each tool:
|
|
mcp__serena__replace_symbol_body(
|
|
name_path="add_memory",
|
|
relative_path="mcp_server/src/graphiti_mcp_server.py",
|
|
body="<new implementation from above>"
|
|
)
|
|
```
|
|
|
|
### Step 2: Update Priority Metadata
|
|
|
|
Update meta dictionaries for two tools:
|
|
- `search_memory_facts`: `'priority': 0.85` (was 0.8)
|
|
- `get_entities_by_type`: `'priority': 0.75` (was 0.7)
|
|
|
|
### Step 3: Validation
|
|
|
|
```bash
|
|
cd mcp_server
|
|
|
|
# Format code
|
|
uv run ruff format src/graphiti_mcp_server.py
|
|
|
|
# Lint
|
|
uv run ruff check src/graphiti_mcp_server.py
|
|
|
|
# Syntax check
|
|
python3 -m py_compile src/graphiti_mcp_server.py
|
|
```
|
|
|
|
### Step 4: Testing Checklist
|
|
|
|
Test with MCP clients (Claude Desktop, Cline, etc.):
|
|
|
|
- [ ] Decision trees help LLM choose correct tool
|
|
- [ ] Priority guidance is visible in tool descriptions
|
|
- [ ] Destructive operations trigger appropriate caution
|
|
- [ ] Examples are clear and helpful
|
|
- [ ] No rendering issues (emojis, formatting)
|
|
- [ ] Tool selection accuracy improved
|
|
|
|
---
|
|
|
|
## Priority Guidance Summary (LLM-Visible)
|
|
|
|
### How Priority is Communicated to LLMs
|
|
|
|
**In docstring first line:**
|
|
- "**This is the PRIMARY method**" → Top priority
|
|
- "**PRIMARY method for X**" → Category leader
|
|
- "**Use for X**" → Standard tool
|
|
- "**Direct lookup only**" → Specialized use
|
|
- "**DESTRUCTIVE**" → Use with extreme caution
|
|
|
|
**In WHEN TO USE section:**
|
|
- "**USE THIS FIRST**" → Highest priority
|
|
- "**USE THIS**" → Preferred for this use case
|
|
- "Prefer X over Y" → Comparative guidance
|
|
|
|
**NOT communicated to LLMs:**
|
|
- `meta.priority` values (0.1-0.9) → Client UX only
|
|
- Title emojis (removed for accessibility)
|
|
- Tags (used for client filtering)
|
|
|
|
---
|
|
|
|
## Key Improvements Over Original
|
|
|
|
1. **LLM-Visible Priority**
|
|
- ✅ Priority in docstring first line (LLM sees this)
|
|
- ✅ Explicit "USE THIS FIRST" guidance
|
|
- ❌ Removed reliance on meta.priority (LLM doesn't see this)
|
|
|
|
2. **Decision Trees**
|
|
- ✅ Kept and refined for all overlapping tools
|
|
- ✅ Clear "A vs B vs C" guidance
|
|
|
|
3. **MCP Compliance**
|
|
- ✅ Standard annotations only
|
|
- ✅ No non-standard fields
|
|
- ✅ Proper use of meta for client UX
|
|
|
|
4. **Accessibility**
|
|
- ✅ No emojis in titles (screen reader friendly)
|
|
- ✅ Clear, professional language
|
|
- ✅ Standard Python docstring format
|
|
|
|
5. **Examples**
|
|
- ✅ Standard placement (after Args section)
|
|
- ✅ Realistic, varied use cases
|
|
- ✅ Shows different parameter combinations
|
|
|
|
6. **Conciseness**
|
|
- ✅ Removed unsupported claims (40-60% improvement, etc.)
|
|
- ✅ Focused on actionable guidance
|
|
- ✅ ~50% shorter than original document
|
|
|
|
---
|
|
|
|
## What Was Removed/Fixed
|
|
|
|
### Removed
|
|
- ❌ Emojis in title field (⭐ 🔍 ⚠️)
|
|
- ❌ Examples in Args section (non-standard)
|
|
- ❌ Unsupported quantitative claims (40-60% improvement)
|
|
- ❌ Reliance on meta.priority for LLM guidance
|
|
|
|
### Fixed
|
|
- ✅ Priority now in docstring (LLM-visible)
|
|
- ✅ Examples in standard location
|
|
- ✅ "Facts = relationships" clarified
|
|
- ✅ Clear separation of tools
|
|
|
|
### Kept
|
|
- ✅ Decision trees
|
|
- ✅ Safety protocols
|
|
- ✅ Clear differentiation
|
|
- ✅ Standard annotations
|
|
|
|
---
|
|
|
|
## Expected Outcomes
|
|
|
|
### Measurable Goals
|
|
- Improved LLM tool selection accuracy (measure after deployment)
|
|
- Reduced tool selection errors (track wrong tool usage)
|
|
- Faster decision time (fewer tools evaluated)
|
|
|
|
### Qualitative Goals
|
|
- LLMs choose correct tool more consistently
|
|
- Users see appropriate warnings for destructive operations
|
|
- Clearer documentation for developers
|
|
- Better developer experience
|
|
|
|
**Note:** Specific percentages removed. Measure actual impact after deployment.
|
|
|
|
---
|
|
|
|
## Files to Modify
|
|
|
|
**Primary:**
|
|
- `mcp_server/src/graphiti_mcp_server.py` (12 tool docstrings + 2 meta priority values)
|
|
|
|
**Documentation:**
|
|
- `DOCS/MCP-Tool-Descriptions-REVISED.md` (this file)
|
|
|
|
**Optional:**
|
|
- Update `.serena/memories/mcp_tool_descriptions_final_revision.md` with findings
|
|
|
|
---
|
|
|
|
## Rollback Plan
|
|
|
|
```bash
|
|
# If issues occur, rollback via git
|
|
git checkout HEAD -- mcp_server/src/graphiti_mcp_server.py
|
|
|
|
# Or restore from this documented state
|
|
```
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. ✅ Review this revised document
|
|
2. ⬜ Approve for implementation
|
|
3. ⬜ Implement using Serena tools
|
|
4. ⬜ Validate with ruff + py_compile
|
|
5. ⬜ Test with MCP client
|
|
6. ⬜ Measure impact on tool selection
|
|
7. ⬜ Iterate based on real usage data
|
|
|
|
---
|
|
|
|
## FAQ
|
|
|
|
**Q: Why no emojis?**
|
|
A: Accessibility (screen readers), professionalism, and inconsistent rendering across clients. Priority should be communicated through words, not symbols.
|
|
|
|
**Q: Why is priority in docstrings instead of meta?**
|
|
A: Meta fields are not visible to LLMs (per MCP SDK docs). For LLMs to see priority, it must be in the docstring text itself.
|
|
|
|
**Q: Will this work with all entity types?**
|
|
A: Yes. Descriptions are generic with examples showing variety (PKM, business, technical use cases).
|
|
|
|
**Q: Any breaking changes?**
|
|
A: No. All changes are docstring-only. Functionality is identical.
|
|
|
|
**Q: How to measure success?**
|
|
A: Track tool selection accuracy before/after deployment. Monitor wrong tool usage rates. Gather user feedback.
|
|
|
|
---
|
|
|
|
**END OF DOCUMENT**
|
|
|
|
Ready for implementation via Serena symbolic editing tools.
|