Files
leo-claude-mktplace/mcp-servers/wikijs/mcp_server/tools/lessons_learned.py
lmiranda a686c3c5bc feat: implement Wiki.js MCP Server with full test coverage
Implements Phase 1.1b - Wiki.js MCP Server for documentation management
and lessons learned capture.

**Features:**
- GraphQL client for Wiki.js API
- Page management (CRUD operations)
- Lessons learned workflow
- Mode detection (project vs company-wide)
- Hybrid configuration system
- 18 comprehensive tests (all passing)

**Components:**
- config.py: Configuration loader with mode detection
- wikijs_client.py: GraphQL client implementation
- server.py: MCP server with 8 tools
- tools/pages.py: Page management tools
- tools/lessons_learned.py: Lessons learned tools

**Tools Provided:**
- search_pages: Search by keywords and tags
- get_page: Retrieve specific page
- create_page: Create new page with markdown
- update_page: Update existing page
- list_pages: List pages under path
- create_lesson: Create lessons learned entry
- search_lessons: Search previous lessons
- tag_lesson: Add/update lesson tags

**Testing:**
- 18 unit tests with mocks (all passing)
- Integration tests with real Wiki.js instance
- Configuration validation tests
- GraphQL error handling tests

**Documentation:**
- Comprehensive README.md with usage guide
- TESTING.md with testing instructions
- Integration test script for validation

Verified working with live Wiki.js instance at http://wikijs.hotport

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 16:26:03 -05:00

184 lines
5.5 KiB
Python

"""
MCP tools for Wiki.js lessons learned management.
"""
from typing import Dict, Any, List, Optional
from mcp.server import Tool
from ..wikijs_client import WikiJSClient
import logging
logger = logging.getLogger(__name__)
def create_lesson_tools(client: WikiJSClient) -> List[Tool]:
"""
Create MCP tools for lessons learned management.
Args:
client: WikiJSClient instance
Returns:
List of MCP tools
"""
async def create_lesson(
title: str,
content: str,
tags: str,
category: str = "sprints"
) -> Dict[str, Any]:
"""
Create a lessons learned entry.
After 15 sprints without systematic lesson capture, repeated mistakes occurred.
This tool ensures lessons are captured and searchable for future sprints.
Args:
title: Lesson title (e.g., "Sprint 16 - Claude Code Infinite Loop on Label Validation")
content: Lesson content in markdown (problem, solution, prevention)
tags: Comma-separated tags (e.g., "claude-code, testing, labels, validation")
category: Category for organization (default: "sprints", also: "patterns", "architecture")
Returns:
Created lesson page data
Example:
create_lesson(
title="Sprint 16 - Prevent Infinite Loops in Validation",
content="## Problem\\n\\nClaude Code entered infinite loop...\\n\\n## Solution\\n\\n...",
tags="claude-code, testing, infinite-loop, validation",
category="sprints"
)
"""
try:
tag_list = [t.strip() for t in tags.split(',')]
lesson = await client.create_lesson(
title=title,
content=content,
tags=tag_list,
category=category
)
return {
'success': True,
'lesson': lesson,
'message': f'Lesson learned captured: {title}'
}
except Exception as e:
logger.error(f"Error creating lesson: {e}")
return {
'success': False,
'error': str(e)
}
async def search_lessons(
query: Optional[str] = None,
tags: Optional[str] = None,
limit: int = 20
) -> Dict[str, Any]:
"""
Search lessons learned entries.
Use this at sprint start to find relevant lessons from previous sprints.
Prevents repeating the same mistakes.
Args:
query: Search query (e.g., "validation", "infinite loop", "docker")
tags: Comma-separated tags to filter by (e.g., "claude-code, testing")
limit: Maximum number of results (default: 20)
Returns:
List of matching lessons learned
Example:
# Before implementing validation logic
search_lessons(query="validation", tags="testing, claude-code")
# Before working with Docker
search_lessons(query="docker", tags="deployment")
"""
try:
tag_list = [t.strip() for t in tags.split(',')] if tags else None
lessons = await client.search_lessons(
query=query,
tags=tag_list,
limit=limit
)
return {
'success': True,
'count': len(lessons),
'lessons': lessons,
'message': f'Found {len(lessons)} relevant lessons'
}
except Exception as e:
logger.error(f"Error searching lessons: {e}")
return {
'success': False,
'error': str(e)
}
async def tag_lesson(
page_id: int,
tags: str
) -> Dict[str, Any]:
"""
Add or update tags on a lesson.
Args:
page_id: Lesson page ID (from create_lesson or search_lessons)
tags: Comma-separated tags (will replace existing tags)
Returns:
Updated lesson data
"""
try:
tag_list = [t.strip() for t in tags.split(',')]
lesson = await client.tag_lesson(
page_id=page_id,
new_tags=tag_list
)
return {
'success': True,
'lesson': lesson,
'message': 'Tags updated successfully'
}
except Exception as e:
logger.error(f"Error tagging lesson: {e}")
return {
'success': False,
'error': str(e)
}
# Define MCP tools
tools = [
Tool(
name="create_lesson",
description=(
"Create a lessons learned entry to prevent repeating mistakes. "
"Critical for capturing sprint insights, architectural decisions, "
"and technical gotchas for future reference."
),
function=create_lesson
),
Tool(
name="search_lessons",
description=(
"Search lessons learned from previous sprints and projects. "
"Use this before starting new work to avoid known pitfalls and "
"leverage past solutions."
),
function=search_lessons
),
Tool(
name="tag_lesson",
description="Add or update tags on a lessons learned entry for better categorization",
function=tag_lesson
)
]
return tools