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>
30 KiB
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:
- ✅ LLM-visible priority - Critical information in docstrings, not hidden in meta
- ✅ Decision trees - Clear guidance for overlapping tools
- ✅ Standard annotations - Using only MCP-specified fields
- ✅ Accessibility first - No emojis, clear language
- ✅ 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)
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)
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)
@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)
@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)
@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)
@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)
@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)
@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)
@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)
@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)
@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)
@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)
@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)
@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:
# 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
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.priorityvalues (0.1-0.9) → Client UX only- Title emojis (removed for accessibility)
- Tags (used for client filtering)
Key Improvements Over Original
-
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)
-
Decision Trees
- ✅ Kept and refined for all overlapping tools
- ✅ Clear "A vs B vs C" guidance
-
MCP Compliance
- ✅ Standard annotations only
- ✅ No non-standard fields
- ✅ Proper use of meta for client UX
-
Accessibility
- ✅ No emojis in titles (screen reader friendly)
- ✅ Clear, professional language
- ✅ Standard Python docstring format
-
Examples
- ✅ Standard placement (after Args section)
- ✅ Realistic, varied use cases
- ✅ Shows different parameter combinations
-
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.mdwith findings
Rollback Plan
# If issues occur, rollback via git
git checkout HEAD -- mcp_server/src/graphiti_mcp_server.py
# Or restore from this documented state
Next Steps
- ✅ Review this revised document
- ⬜ Approve for implementation
- ⬜ Implement using Serena tools
- ⬜ Validate with ruff + py_compile
- ⬜ Test with MCP client
- ⬜ Measure impact on tool selection
- ⬜ 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.