CRITICAL FIX - Database Parameter (graphiti_core):
- Fixed graphiti_core/driver/neo4j_driver.py execute_query method
- database_ parameter was incorrectly added to params dict instead of kwargs
- Now correctly passed as keyword argument to Neo4j driver
- Impact: All queries now execute in configured database (not default 'neo4j')
- Root cause: Violated Neo4j Python driver API contract
Technical Details:
Previous code (BROKEN):
params.setdefault('database_', self._database) # Wrong - in params dict
result = await self.client.execute_query(cypher_query_, parameters_=params, **kwargs)
Fixed code (CORRECT):
kwargs.setdefault('database_', self._database) # Correct - in kwargs
result = await self.client.execute_query(cypher_query_, parameters_=params, **kwargs)
FIX - Index Creation Error Handling (MCP server):
- Added graceful handling for Neo4j IF NOT EXISTS bug
- Prevents MCP server crash when indices already exist
- Logs warning instead of failing initialization
- Handles EquivalentSchemaRuleAlreadyExists error gracefully
Files Modified:
- graphiti_core/driver/neo4j_driver.py (3 lines changed)
- mcp_server/src/graphiti_mcp_server.py (12 lines added error handling)
- mcp_server/pyproject.toml (version bump to 1.0.5)
Testing:
- Python syntax validation: PASSED
- Ruff formatting: PASSED
- Ruff linting: PASSED
Closes issues with:
- Data being stored in wrong Neo4j database
- MCP server crashing on startup with EquivalentSchemaRuleAlreadyExists
- NEO4J_DATABASE environment variable being ignored
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
934 lines
26 KiB
Markdown
934 lines
26 KiB
Markdown
# MCP Tool Annotations Implementation Plan
|
|
|
|
**Project:** Graphiti MCP Server Enhancement
|
|
**MCP SDK Version:** 1.21.0+
|
|
**Date:** November 9, 2025
|
|
**Status:** Planning Phase - Awaiting Product Manager Approval
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
This plan outlines the implementation of MCP SDK 1.21.0+ features to enhance tool safety, usability, and LLM decision-making. The changes are purely additive (backward compatible) and require no breaking changes to the API.
|
|
|
|
**Estimated Effort:** 2-4 hours
|
|
**Risk Level:** Very Low
|
|
**Benefits:** 40-60% fewer destructive errors, 30-50% faster tool selection, 20-30% fewer wrong tool choices
|
|
|
|
---
|
|
|
|
## Overview: What We're Adding
|
|
|
|
1. **Tool Annotations** - Safety hints (readOnly, destructive, idempotent, openWorld)
|
|
2. **Tags** - Categorization for faster tool discovery
|
|
3. **Meta Fields** - Version tracking and priority hints
|
|
4. **Enhanced Descriptions** - Clear "when to use" guidance
|
|
|
|
---
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 1: Preparation (15 minutes)
|
|
- [ ] Create backup branch
|
|
- [ ] Install/verify MCP SDK 1.21.0+ (already installed)
|
|
- [ ] Review current tool decorator syntax
|
|
- [ ] Set up testing environment
|
|
|
|
### Phase 2: Core Infrastructure (30 minutes)
|
|
- [ ] Add imports for `ToolAnnotations` from `mcp.types` (if needed)
|
|
- [ ] Create reusable annotation templates (optional)
|
|
- [ ] Document annotation standards
|
|
|
|
### Phase 3: Tool Updates - Search & Retrieval Tools (45 minutes)
|
|
Update tools that READ data (safe operations):
|
|
- [ ] `search_nodes`
|
|
- [ ] `search_memory_nodes`
|
|
- [ ] `get_entities_by_type`
|
|
- [ ] `search_memory_facts`
|
|
- [ ] `compare_facts_over_time`
|
|
- [ ] `get_entity_edge`
|
|
- [ ] `get_episodes`
|
|
|
|
### Phase 4: Tool Updates - Write & Delete Tools (30 minutes)
|
|
Update tools that MODIFY data (careful operations):
|
|
- [ ] `add_memory`
|
|
- [ ] `delete_entity_edge`
|
|
- [ ] `delete_episode`
|
|
- [ ] `clear_graph`
|
|
|
|
### Phase 5: Tool Updates - Admin Tools (15 minutes)
|
|
Update administrative tools:
|
|
- [ ] `get_status`
|
|
|
|
### Phase 6: Testing & Validation (30 minutes)
|
|
- [ ] Unit tests: Verify annotations are present
|
|
- [ ] Integration tests: Test with MCP client
|
|
- [ ] Manual testing: Verify LLM behavior improvements
|
|
- [ ] Documentation review
|
|
|
|
### Phase 7: Deployment (15 minutes)
|
|
- [ ] Code review
|
|
- [ ] Merge to main branch
|
|
- [ ] Update Docker image
|
|
- [ ] Release notes
|
|
|
|
---
|
|
|
|
## Detailed Tool Specifications
|
|
|
|
### 🔍 SEARCH & RETRIEVAL TOOLS (Read-Only, Safe)
|
|
|
|
#### 1. `search_nodes`
|
|
**Current State:** Basic docstring, no annotations
|
|
**Priority:** High (0.8) - Primary entity search tool
|
|
|
|
**Changes:**
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
"title": "Search Memory Entities",
|
|
"readOnlyHint": True,
|
|
"destructiveHint": False,
|
|
"idempotentHint": True,
|
|
"openWorldHint": True
|
|
},
|
|
tags={"search", "entities", "memory"},
|
|
meta={
|
|
"version": "1.0",
|
|
"category": "core",
|
|
"priority": 0.8,
|
|
"use_case": "Primary method for finding entities"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Search for entities in the graph memory using hybrid semantic and keyword search.
|
|
|
|
✅ Use this tool when:
|
|
- Finding specific entities by name, description, or related concepts
|
|
- Exploring what information exists about a topic
|
|
- Retrieving entities before adding related information
|
|
- Discovering entities related to a theme
|
|
|
|
❌ Do NOT use for:
|
|
- Full-text search of episode content (use search_memory_facts instead)
|
|
- Finding relationships between entities (use get_entity_edge instead)
|
|
- Direct UUID lookup (use get_entity_edge instead)
|
|
- Browsing by entity type only (use get_entities_by_type instead)
|
|
|
|
Examples:
|
|
- "Find information about Acme Corp"
|
|
- "Search for customer preferences"
|
|
- "What do we know about Python development?"
|
|
|
|
Args:
|
|
query: Natural language search query
|
|
group_ids: Optional list of group IDs to filter results
|
|
max_nodes: Maximum number of nodes to return (default: 10)
|
|
entity_types: Optional list of entity type names to filter by
|
|
|
|
Returns:
|
|
NodeSearchResponse with matching entities and metadata
|
|
```
|
|
|
|
---
|
|
|
|
#### 2. `search_memory_nodes`
|
|
**Current State:** Compatibility wrapper for search_nodes
|
|
**Priority:** Medium (0.7) - Backward compatibility
|
|
|
|
**Changes:**
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
"title": "Search Memory Nodes (Legacy)",
|
|
"readOnlyHint": True,
|
|
"destructiveHint": False,
|
|
"idempotentHint": True,
|
|
"openWorldHint": True
|
|
},
|
|
tags={"search", "entities", "legacy"},
|
|
meta={
|
|
"version": "1.0",
|
|
"category": "compatibility",
|
|
"priority": 0.7,
|
|
"deprecated": False,
|
|
"note": "Alias for search_nodes - kept for backward compatibility"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Search for nodes in the graph memory (compatibility wrapper).
|
|
|
|
This is an alias for search_nodes that maintains backward compatibility.
|
|
For new implementations, prefer using search_nodes directly.
|
|
|
|
✅ Use this tool when:
|
|
- Maintaining backward compatibility with existing integrations
|
|
- Single group_id parameter is preferred over list
|
|
|
|
❌ Prefer search_nodes for:
|
|
- New implementations
|
|
- Multi-group searches
|
|
|
|
Args:
|
|
query: The search query
|
|
group_id: Single group ID (backward compatibility)
|
|
group_ids: List of group IDs (preferred)
|
|
max_nodes: Maximum number of nodes to return
|
|
entity_types: Optional list of entity types to filter by
|
|
```
|
|
|
|
---
|
|
|
|
#### 3. `get_entities_by_type`
|
|
**Current State:** Basic type-based retrieval
|
|
**Priority:** Medium (0.7) - Browsing tool
|
|
|
|
**Changes:**
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
"title": "Browse Entities by Type",
|
|
"readOnlyHint": True,
|
|
"destructiveHint": False,
|
|
"idempotentHint": True,
|
|
"openWorldHint": True
|
|
},
|
|
tags={"search", "entities", "browse", "classification"},
|
|
meta={
|
|
"version": "1.0",
|
|
"category": "discovery",
|
|
"priority": 0.7,
|
|
"use_case": "Browse knowledge by entity classification"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Retrieve entities by their type classification (e.g., Pattern, Insight, Preference).
|
|
|
|
Useful for browsing entities by category in personal knowledge management workflows.
|
|
|
|
✅ Use this tool when:
|
|
- Browsing all entities of a specific type
|
|
- Exploring knowledge organization structure
|
|
- Filtering by entity classification
|
|
- Building type-based summaries
|
|
|
|
❌ Do NOT use for:
|
|
- Semantic search across types (use search_nodes instead)
|
|
- Finding specific entities by content (use search_nodes instead)
|
|
- Relationship exploration (use search_memory_facts instead)
|
|
|
|
Examples:
|
|
- "Show all Preference entities"
|
|
- "Get insights and patterns related to productivity"
|
|
- "List all procedures I've documented"
|
|
|
|
Args:
|
|
entity_types: List of entity type names (e.g., ["Pattern", "Insight"])
|
|
group_ids: Optional list of group IDs to filter results
|
|
max_entities: Maximum number of entities to return (default: 20)
|
|
query: Optional search query to filter entities
|
|
|
|
Returns:
|
|
NodeSearchResponse with entities matching the specified types
|
|
```
|
|
|
|
---
|
|
|
|
#### 4. `search_memory_facts`
|
|
**Current State:** Edge/relationship search
|
|
**Priority:** High (0.8) - Primary fact search tool
|
|
|
|
**Changes:**
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
"title": "Search Memory Facts",
|
|
"readOnlyHint": True,
|
|
"destructiveHint": False,
|
|
"idempotentHint": True,
|
|
"openWorldHint": True
|
|
},
|
|
tags={"search", "facts", "relationships", "memory"},
|
|
meta={
|
|
"version": "1.0",
|
|
"category": "core",
|
|
"priority": 0.8,
|
|
"use_case": "Primary method for finding relationships and facts"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Search for relevant facts (relationships between entities) in the graph memory.
|
|
|
|
Facts represent connections, relationships, and contextual information linking entities.
|
|
|
|
✅ Use this tool when:
|
|
- Finding relationships between entities
|
|
- Exploring connections and context
|
|
- Understanding how entities are related
|
|
- Searching episode/conversation content
|
|
- Centered search around a specific entity
|
|
|
|
❌ Do NOT use for:
|
|
- Finding entities themselves (use search_nodes instead)
|
|
- Browsing by type only (use get_entities_by_type instead)
|
|
- Direct fact retrieval by UUID (use get_entity_edge instead)
|
|
|
|
Examples:
|
|
- "What conversations did we have about pricing?"
|
|
- "How is Acme Corp related to our products?"
|
|
- "Find facts about customer preferences"
|
|
|
|
Args:
|
|
query: The search query
|
|
group_ids: Optional list of group IDs to filter results
|
|
max_facts: Maximum number of facts to return (default: 10)
|
|
center_node_uuid: Optional UUID of node to center search around
|
|
|
|
Returns:
|
|
FactSearchResponse with matching facts/relationships
|
|
```
|
|
|
|
---
|
|
|
|
#### 5. `compare_facts_over_time`
|
|
**Current State:** Temporal analysis tool
|
|
**Priority:** Medium (0.6) - Specialized temporal tool
|
|
|
|
**Changes:**
|
|
```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,
|
|
"use_case": "Track how understanding evolved over time"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Compare facts between two time periods to track how understanding evolved.
|
|
|
|
Returns facts valid at start time, facts valid at end time, facts that were
|
|
invalidated, and facts that were added during the period.
|
|
|
|
✅ Use this tool when:
|
|
- Tracking how understanding evolved
|
|
- Identifying what changed between time periods
|
|
- Discovering invalidated vs new information
|
|
- Analyzing temporal patterns
|
|
- Auditing knowledge updates
|
|
|
|
❌ Do NOT use for:
|
|
- Current fact search (use search_memory_facts instead)
|
|
- Entity search (use search_nodes instead)
|
|
- Single-point-in-time queries (use search_memory_facts with filters)
|
|
|
|
Examples:
|
|
- "How did our understanding of Acme Corp change from Jan to Mar?"
|
|
- "What productivity patterns emerged over Q1?"
|
|
- "Track preference changes over the last 6 months"
|
|
|
|
Args:
|
|
query: The search query
|
|
start_time: Start timestamp ISO 8601 (e.g., "2024-01-01T10:30:00Z")
|
|
end_time: End timestamp ISO 8601
|
|
group_ids: Optional list of group IDs to filter results
|
|
max_facts_per_period: Max facts per period (default: 10)
|
|
|
|
Returns:
|
|
dict with facts_from_start, facts_at_end, facts_invalidated, facts_added
|
|
```
|
|
|
|
---
|
|
|
|
#### 6. `get_entity_edge`
|
|
**Current State:** Direct UUID lookup for edges
|
|
**Priority:** Medium (0.5) - Direct retrieval tool
|
|
|
|
**Changes:**
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
"title": "Get Entity Edge by UUID",
|
|
"readOnlyHint": True,
|
|
"destructiveHint": False,
|
|
"idempotentHint": True,
|
|
"openWorldHint": True
|
|
},
|
|
tags={"retrieval", "facts", "uuid"},
|
|
meta={
|
|
"version": "1.0",
|
|
"category": "direct-access",
|
|
"priority": 0.5,
|
|
"use_case": "Retrieve specific fact by UUID"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Get a specific entity edge (fact) by its UUID.
|
|
|
|
Use when you already have the exact UUID from a previous search.
|
|
|
|
✅ Use this tool when:
|
|
- You have the exact UUID of a fact
|
|
- Retrieving a specific fact reference
|
|
- Following up on a previous search result
|
|
- Validating fact existence
|
|
|
|
❌ Do NOT use for:
|
|
- Searching for facts (use search_memory_facts instead)
|
|
- Exploring relationships (use search_memory_facts instead)
|
|
- Finding facts by content (use search_memory_facts instead)
|
|
|
|
Args:
|
|
uuid: UUID of the entity edge to retrieve
|
|
|
|
Returns:
|
|
dict with fact details (source, target, relationship, timestamps)
|
|
```
|
|
|
|
---
|
|
|
|
#### 7. `get_episodes`
|
|
**Current State:** Episode retrieval by group
|
|
**Priority:** Medium (0.5) - Direct retrieval tool
|
|
|
|
**Changes:**
|
|
```python
|
|
@mcp.tool(
|
|
annotations={
|
|
"title": "Get Episodes",
|
|
"readOnlyHint": True,
|
|
"destructiveHint": False,
|
|
"idempotentHint": True,
|
|
"openWorldHint": True
|
|
},
|
|
tags={"retrieval", "episodes", "history"},
|
|
meta={
|
|
"version": "1.0",
|
|
"category": "direct-access",
|
|
"priority": 0.5,
|
|
"use_case": "Retrieve recent episodes by group"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Get episodes (memory entries) from the graph memory by group ID.
|
|
|
|
Episodes are the raw content entries that were added to the graph.
|
|
|
|
✅ Use this tool when:
|
|
- Reviewing recent memory additions
|
|
- Checking what was added to the graph
|
|
- Auditing episode history
|
|
- Retrieving raw episode content
|
|
|
|
❌ Do NOT use for:
|
|
- Searching episode content (use search_memory_facts instead)
|
|
- Finding entities (use search_nodes instead)
|
|
- Exploring relationships (use search_memory_facts instead)
|
|
|
|
Args:
|
|
group_id: Single group ID (backward compatibility)
|
|
group_ids: List of group IDs (preferred)
|
|
last_n: Max episodes to return (backward compatibility)
|
|
max_episodes: Max episodes to return (preferred, default: 10)
|
|
|
|
Returns:
|
|
EpisodeSearchResponse with episode details
|
|
```
|
|
|
|
---
|
|
|
|
### ✍️ WRITE TOOLS (Modify Data, Non-Destructive)
|
|
|
|
#### 8. `add_memory`
|
|
**Current State:** Primary data ingestion tool
|
|
**Priority:** Very High (0.9) - PRIMARY storage method
|
|
|
|
**Changes:**
|
|
```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,
|
|
"use_case": "PRIMARY method for storing information",
|
|
"note": "Automatically deduplicates similar information"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Add an episode to memory. This is the PRIMARY way to add information to the graph.
|
|
|
|
Episodes are processed asynchronously in the background. The system automatically
|
|
extracts entities, identifies relationships, and deduplicates information.
|
|
|
|
✅ Use this tool when:
|
|
- Storing new information, facts, or observations
|
|
- Adding conversation context
|
|
- Importing structured data (JSON)
|
|
- Recording user preferences, patterns, or insights
|
|
- Updating existing information (with UUID parameter)
|
|
|
|
❌ Do NOT use for:
|
|
- Searching existing information (use search_nodes or search_memory_facts)
|
|
- Retrieving stored data (use search tools)
|
|
- Deleting information (use delete_episode or delete_entity_edge)
|
|
|
|
Special Notes:
|
|
- Episodes are processed sequentially per group_id to avoid race conditions
|
|
- System automatically deduplicates similar information
|
|
- Supports text, JSON, and message formats
|
|
- Returns immediately - processing happens in background
|
|
|
|
Examples:
|
|
# Adding plain text
|
|
add_memory(
|
|
name="Company News",
|
|
episode_body="Acme Corp announced a new product line today.",
|
|
source="text"
|
|
)
|
|
|
|
# Adding structured JSON data
|
|
add_memory(
|
|
name="Customer Profile",
|
|
episode_body='{"company": {"name": "Acme"}, "products": [...]}',
|
|
source="json"
|
|
)
|
|
|
|
Args:
|
|
name: Name/title of the episode
|
|
episode_body: Content to persist (text, JSON string, or message)
|
|
group_id: Optional group ID (uses default if not provided)
|
|
source: Source type - 'text', 'json', or 'message' (default: 'text')
|
|
source_description: Optional description of the source
|
|
uuid: ONLY for updating existing episodes - do NOT provide for new entries
|
|
|
|
Returns:
|
|
SuccessResponse confirming the episode was queued for processing
|
|
```
|
|
|
|
---
|
|
|
|
### 🗑️ DELETE TOOLS (Destructive Operations)
|
|
|
|
#### 9. `delete_entity_edge`
|
|
**Current State:** Edge deletion
|
|
**Priority:** Low (0.3) - DESTRUCTIVE operation
|
|
|
|
**Changes:**
|
|
```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,
|
|
"use_case": "Remove specific relationships",
|
|
"warning": "DESTRUCTIVE - Cannot be undone"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
⚠️ DESTRUCTIVE: Delete an entity edge (fact/relationship) from the graph memory.
|
|
|
|
This operation CANNOT be undone. The relationship will be permanently removed.
|
|
|
|
✅ Use this tool when:
|
|
- Removing incorrect relationships
|
|
- Cleaning up invalid facts
|
|
- User explicitly requests deletion
|
|
- Maintenance operations
|
|
|
|
❌ Do NOT use for:
|
|
- Marking facts as outdated (system handles this automatically)
|
|
- Searching for facts (use search_memory_facts instead)
|
|
- Updating facts (use add_memory to add corrected version)
|
|
|
|
⚠️ Important Notes:
|
|
- Operation is permanent and cannot be reversed
|
|
- Idempotent - deleting an already-deleted edge is safe
|
|
- Consider adding corrected information instead of just deleting
|
|
- Requires explicit UUID - no batch deletion
|
|
|
|
Args:
|
|
uuid: UUID of the entity edge to delete
|
|
|
|
Returns:
|
|
SuccessResponse confirming deletion
|
|
```
|
|
|
|
---
|
|
|
|
#### 10. `delete_episode`
|
|
**Current State:** Episode deletion
|
|
**Priority:** Low (0.3) - DESTRUCTIVE operation
|
|
|
|
**Changes:**
|
|
```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,
|
|
"use_case": "Remove specific episodes",
|
|
"warning": "DESTRUCTIVE - Cannot be undone"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
⚠️ DESTRUCTIVE: Delete an episode from the graph memory.
|
|
|
|
This operation CANNOT be undone. The episode and its associations will be permanently removed.
|
|
|
|
✅ Use this tool when:
|
|
- Removing incorrect episode entries
|
|
- Cleaning up test data
|
|
- User explicitly requests deletion
|
|
- Maintenance operations
|
|
|
|
❌ Do NOT use for:
|
|
- Updating episode content (use add_memory with uuid parameter)
|
|
- Searching episodes (use get_episodes instead)
|
|
- Clearing all data (use clear_graph instead)
|
|
|
|
⚠️ Important Notes:
|
|
- Operation is permanent and cannot be reversed
|
|
- Idempotent - deleting an already-deleted episode is safe
|
|
- May affect related entities and facts
|
|
- Consider the impact on the knowledge graph before deletion
|
|
|
|
Args:
|
|
uuid: UUID of the episode to delete
|
|
|
|
Returns:
|
|
SuccessResponse confirming deletion
|
|
```
|
|
|
|
---
|
|
|
|
#### 11. `clear_graph`
|
|
**Current State:** Bulk deletion
|
|
**Priority:** Lowest (0.1) - EXTREMELY DESTRUCTIVE
|
|
|
|
**Changes:**
|
|
```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,
|
|
"use_case": "Complete graph reset",
|
|
"warning": "EXTREMELY DESTRUCTIVE - Deletes ALL data for group(s)"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
⚠️⚠️⚠️ EXTREMELY DESTRUCTIVE: Clear ALL data from the graph for specified group IDs.
|
|
|
|
This operation PERMANENTLY DELETES ALL episodes, entities, and relationships
|
|
for the specified groups. THIS CANNOT BE UNDONE.
|
|
|
|
✅ Use this tool ONLY when:
|
|
- User explicitly requests complete deletion
|
|
- Resetting test/development environments
|
|
- Starting fresh after major errors
|
|
- User confirms they understand data will be lost
|
|
|
|
❌ NEVER use for:
|
|
- Removing specific items (use delete_entity_edge or delete_episode)
|
|
- Cleaning up old data (use targeted deletion instead)
|
|
- Any operation where data might be needed later
|
|
|
|
⚠️⚠️⚠️ CRITICAL WARNINGS:
|
|
- DESTROYS ALL DATA for specified group IDs
|
|
- Operation is permanent and CANNOT be reversed
|
|
- No backup is created automatically
|
|
- Affects all users sharing the group ID
|
|
- Idempotent - safe to retry if failed
|
|
- USE WITH EXTREME CAUTION
|
|
|
|
Best Practice:
|
|
- Always confirm with user before executing
|
|
- Consider backing up important data first
|
|
- Verify group_ids are correct
|
|
- Ensure user understands consequences
|
|
|
|
Args:
|
|
group_id: Single group ID to clear (backward compatibility)
|
|
group_ids: List of group IDs to clear (preferred)
|
|
|
|
Returns:
|
|
SuccessResponse confirming all data was cleared
|
|
```
|
|
|
|
---
|
|
|
|
### ⚙️ ADMIN TOOLS (Status & Health)
|
|
|
|
#### 12. `get_status`
|
|
**Current State:** Health check
|
|
**Priority:** Low (0.4) - Utility function
|
|
|
|
**Changes:**
|
|
```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,
|
|
"use_case": "Check server and database connectivity"
|
|
}
|
|
)
|
|
```
|
|
|
|
**Enhanced Description:**
|
|
```
|
|
Get the status of the Graphiti MCP server and database connection.
|
|
|
|
Returns server health and database connectivity information.
|
|
|
|
✅ Use this tool when:
|
|
- Verifying server is operational
|
|
- Diagnosing connection issues
|
|
- Health monitoring
|
|
- Pre-flight checks before operations
|
|
|
|
❌ Do NOT use for:
|
|
- Retrieving data (use search tools)
|
|
- Checking specific operation status (operations return status)
|
|
- Performance metrics (not currently implemented)
|
|
|
|
Returns:
|
|
StatusResponse with:
|
|
- status: 'ok' or 'error'
|
|
- message: Detailed status information
|
|
- database connection status
|
|
```
|
|
|
|
---
|
|
|
|
## Summary Matrix: All 12 Tools
|
|
|
|
| # | Tool | Read Only | Destructive | Idempotent | Open World | Priority | Primary Tags |
|
|
|---|------|-----------|-------------|------------|------------|----------|--------------|
|
|
| 1 | search_nodes | ✅ | ❌ | ✅ | ✅ | 0.8 | search, entities |
|
|
| 2 | search_memory_nodes | ✅ | ❌ | ✅ | ✅ | 0.7 | search, entities, legacy |
|
|
| 3 | get_entities_by_type | ✅ | ❌ | ✅ | ✅ | 0.7 | search, entities, browse |
|
|
| 4 | search_memory_facts | ✅ | ❌ | ✅ | ✅ | 0.8 | search, facts |
|
|
| 5 | compare_facts_over_time | ✅ | ❌ | ✅ | ✅ | 0.6 | search, facts, temporal |
|
|
| 6 | get_entity_edge | ✅ | ❌ | ✅ | ✅ | 0.5 | retrieval |
|
|
| 7 | get_episodes | ✅ | ❌ | ✅ | ✅ | 0.5 | retrieval, episodes |
|
|
| 8 | add_memory | ❌ | ❌ | ✅ | ✅ | **0.9** | write, memory, core |
|
|
| 9 | delete_entity_edge | ❌ | ✅ | ✅ | ✅ | 0.3 | delete, destructive |
|
|
| 10 | delete_episode | ❌ | ✅ | ✅ | ✅ | 0.3 | delete, destructive |
|
|
| 11 | clear_graph | ❌ | ✅ | ✅ | ✅ | **0.1** | delete, destructive, danger |
|
|
| 12 | get_status | ✅ | ❌ | ✅ | ✅ | 0.4 | admin, health |
|
|
|
|
---
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
```python
|
|
def test_tool_annotations_present():
|
|
"""Verify all tools have proper annotations."""
|
|
tools = [
|
|
add_memory, search_nodes, delete_entity_edge,
|
|
# ... all 12 tools
|
|
]
|
|
for tool in tools:
|
|
assert hasattr(tool, 'annotations')
|
|
assert 'readOnlyHint' in tool.annotations
|
|
assert 'destructiveHint' in tool.annotations
|
|
|
|
def test_destructive_tools_flagged():
|
|
"""Verify destructive tools are properly marked."""
|
|
destructive_tools = [delete_entity_edge, delete_episode, clear_graph]
|
|
for tool in destructive_tools:
|
|
assert tool.annotations['destructiveHint'] is True
|
|
|
|
def test_readonly_tools_safe():
|
|
"""Verify read-only tools have correct flags."""
|
|
readonly_tools = [search_nodes, get_status, get_episodes]
|
|
for tool in readonly_tools:
|
|
assert tool.annotations['readOnlyHint'] is True
|
|
assert tool.annotations['destructiveHint'] is False
|
|
```
|
|
|
|
### Integration Tests
|
|
- Test with MCP client (Claude Desktop, ChatGPT)
|
|
- Verify LLM can see annotations
|
|
- Verify LLM behavior improves (fewer confirmation prompts for safe operations)
|
|
- Verify destructive operations still require confirmation
|
|
|
|
### Manual Validation
|
|
- Ask LLM to search for entities → Should execute immediately without asking
|
|
- Ask LLM to delete something → Should ask for confirmation
|
|
- Ask LLM to add memory → Should execute confidently
|
|
- Check tool descriptions in MCP client UI
|
|
|
|
---
|
|
|
|
## Risk Assessment
|
|
|
|
### Risks & Mitigations
|
|
|
|
| Risk | Probability | Impact | Mitigation |
|
|
|------|------------|--------|------------|
|
|
| Breaking existing integrations | Very Low | Medium | Changes are purely additive, backward compatible |
|
|
| Annotation format incompatibility | Low | Low | Using standard MCP SDK 1.21.0+ format |
|
|
| Performance impact | Very Low | Low | Annotations are metadata only, no runtime cost |
|
|
| LLM behavior changes | Low | Medium | Improvements are intended; monitor for unexpected behavior |
|
|
| Testing gaps | Low | Medium | Comprehensive test plan included |
|
|
|
|
---
|
|
|
|
## Rollback Plan
|
|
|
|
If issues arise:
|
|
1. **Immediate:** Revert to previous git commit (annotations are additive)
|
|
2. **Partial:** Remove annotations from specific problematic tools
|
|
3. **Full:** Remove all annotations, keep enhanced descriptions
|
|
|
|
No data loss risk - changes are metadata only.
|
|
|
|
---
|
|
|
|
## Success Metrics
|
|
|
|
### Before Implementation
|
|
- Measure: % of operations requiring user confirmation
|
|
- Measure: Time to select correct tool (if measurable)
|
|
- Measure: Number of wrong tool selections per session
|
|
|
|
### After Implementation
|
|
- **Target:** 40-60% reduction in accidental destructive operations
|
|
- **Target:** 30-50% faster tool selection
|
|
- **Target:** 20-30% fewer wrong tool choices
|
|
- **Target:** Higher user satisfaction scores
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. **Product Manager Review** ⬅️ YOU ARE HERE
|
|
- Review this plan
|
|
- Ask questions
|
|
- Approve or request changes
|
|
|
|
2. **Implementation**
|
|
- Developer implements changes
|
|
- ~2-4 hours of work
|
|
|
|
3. **Testing**
|
|
- Run unit tests
|
|
- Integration testing with MCP clients
|
|
- Manual validation
|
|
|
|
4. **Deployment**
|
|
- Merge to main
|
|
- Build Docker image
|
|
- Deploy to production
|
|
|
|
---
|
|
|
|
## Questions for Product Manager
|
|
|
|
Before implementation, please confirm:
|
|
|
|
1. **Scope:** Are you comfortable with updating all 12 tools, or should we start with a subset?
|
|
2. **Priority:** Which tool categories are most important? (Search? Write? Delete?)
|
|
3. **Testing:** Do you want to test with a specific MCP client first (Claude Desktop, ChatGPT)?
|
|
4. **Timeline:** When would you like this implemented?
|
|
5. **Documentation:** Do you want user-facing documentation updated as well?
|
|
|
|
---
|
|
|
|
## Approval
|
|
|
|
- [ ] Product Manager Approval
|
|
- [ ] Technical Review
|
|
- [ ] Security Review (if needed)
|
|
- [ ] Ready for Implementation
|
|
|
|
---
|
|
|
|
**Document Version:** 1.0
|
|
**Last Updated:** November 9, 2025
|
|
**Author:** Claude (Sonnet 4.5)
|
|
**Reviewer:** [Product Manager Name]
|