# Sensei MCP - Option B Architecture: Granular Persona Tools

**Date:** 2025-01-23
**Status:** Design Approved - Ready for Implementation

---

## 🎯 CORE PRINCIPLE

> **MCP provides content, LLM does analysis**

The MCP server is a **content provider**, not an analysis engine. It returns persona skill content (prompts, guidelines, principles) that the calling LLM (Claude) uses to perform analysis.

---

## 🏗️ ARCHITECTURE OVERVIEW

### Current Flow (Broken)
```
Claude Code
    ↓
MCP: get_engineering_guidance()
    ↓
Orchestrator tries to analyze (fails - returns placeholders)
    ↓
Returns: "[This would be generated by the orchestrator...]"
    ↓
Claude: ❌ Gets useless placeholder text
```

### New Flow (Option B - Correct)
```
Claude Code
    ↓
MCP: list_available_personas()
    ↓
Returns: JSON list of personas with metadata
    ↓
Claude: Decides which personas are relevant
    ↓
MCP: get_persona_content(name="security-sentinel")
    ↓
Returns: Full SKILL.md content for that persona
    ↓
Claude: Analyzes query using persona content as context
    ↓
MCP: get_persona_content(name="pragmatic-architect")
    ↓
Returns: Full SKILL.md content for that persona
    ↓
Claude: Analyzes from second perspective
    ↓
Claude: ✅ Synthesizes both perspectives into recommendation
```

---

## 📦 NEW MCP TOOLS

### 1. `list_available_personas()` ✅ EXISTS (needs minor updates)

**Purpose:** Let Claude discover available personas.

**Current Implementation:** `list_available_skills()` in `server.py:801`

**Status:** Already implemented, but returns formatted text instead of structured data.

**Proposed Changes:**
- Add JSON output format option
- Return structured persona metadata for programmatic use

**Signature:**
```python
@mcp.tool()
def list_available_personas(
    category: str = None,
    format: str = "json"  # json | markdown | quick
) -> str:
    """
    List all available personas with metadata.

    Args:
        category: Filter by category (core, specialized, operations, security, etc.)
        format: Output format
            - "json": Structured JSON for programmatic use (default)
            - "markdown": Human-readable markdown
            - "quick": One-line summaries

    Returns:
        List of personas with name, description, expertise, and metadata
    """
```

**JSON Output Example:**
```json
{
  "personas": [
    {
      "name": "security-sentinel",
      "display_name": "Security Sentinel",
      "description": "Paranoid security expert who audits for vulnerabilities",
      "category": "security",
      "expertise": ["security", "vulnerabilities", "auth", "encryption"],
      "use_when": "Security reviews, threat modeling, vulnerability assessments",
      "related_personas": ["compliance-guardian", "site-reliability-engineer"],
      "examples": [
        "Review this authentication flow",
        "Assess security risks in this API design"
      ]
    },
    {
      "name": "pragmatic-architect",
      "display_name": "Pragmatic Architect",
      "description": "System design expert who balances purity with delivery",
      "category": "core",
      "expertise": ["architecture", "scalability", "system-design"],
      "use_when": "Architectural decisions, system design, scalability planning",
      "related_personas": ["snarky-senior-engineer", "site-reliability-engineer"],
      "examples": [
        "Should we migrate to microservices?",
        "Design a multi-tenant architecture"
      ]
    }
  ],
  "count": 23,
  "categories": ["core", "specialized", "operations", "security", "platform", "cost", "leadership", "meta"]
}
```

---

### 2. `get_persona_content()` 🆕 NEW

**Purpose:** Return full persona skill content for a specific persona.

**Signature:**
```python
@mcp.tool()
def get_persona_content(
    persona_name: str,
    include_metadata: bool = True
) -> str:
    """
    Get full skill content for a specific persona.

    This returns the complete SKILL.md content that defines the persona's
    expertise, principles, personality, and guidelines. The calling LLM
    should use this content to analyze queries from that persona's perspective.

    Args:
        persona_name: Name of persona (e.g., "security-sentinel", "pragmatic-architect")
        include_metadata: Include metadata header (name, description, expertise)

    Returns:
        Full persona skill content (markdown format)

    Example:
        # Get Security Sentinel's content
        content = get_persona_content("security-sentinel")

        # Use content in Claude's analysis
        # Claude receives: Full security sentinel skill file content
    """
```

**Implementation:**
```python
@mcp.tool()
def get_persona_content(persona_name: str, include_metadata: bool = True) -> str:
    """Get full skill content for a specific persona."""
    persona = persona_registry.get(persona_name)

    if not persona:
        available = ", ".join(persona_registry.get_all().keys())
        return f"❌ Persona '{persona_name}' not found.\n\nAvailable personas: {available}"

    result = []

    # Optional metadata header
    if include_metadata:
        result.append(f"# {persona.name.replace('-', ' ').title()}\n")
        result.append(f"**Description:** {persona.description}\n")
        result.append(f"**Expertise:** {', '.join(persona.expertise_areas)}\n")
        result.append(f"\n---\n\n")

    # Full skill content (the complete SKILL.md)
    result.append(persona.full_content)

    return "".join(result)
```

**Output Example:**
```markdown
# Security Sentinel

**Description:** Paranoid security expert who audits for vulnerabilities
**Expertise:** security, vulnerabilities, auth, encryption, supply-chain

---

You are the Security Sentinel inside Claude Code.

## 0. Core Principles (Security-First)

1. **Trust No One**
   Assume all input is hostile...

[... FULL SKILL.MD CONTENT ...]

## 5. Mantras

- "Security is not a feature, it's a requirement"
- "Defense in depth"
- "Fail secure, not open"
```

---

### 3. `suggest_personas_for_query()` 🆕 NEW

**Purpose:** Use intelligent selection logic to suggest relevant personas for a query.

**Signature:**
```python
@mcp.tool()
def suggest_personas_for_query(
    query: str,
    max_suggestions: int = 5,
    context: str = None  # "crisis" | "security" | "architectural" | etc.
) -> str:
    """
    Suggest relevant personas for a given query using intelligent selection.

    Uses keyword matching, context detection, and relevance scoring to
    recommend which personas would be most helpful for the query.

    Args:
        query: The user's question or scenario
        max_suggestions: Maximum number of personas to suggest (default: 5)
        context: Optional context hint to improve suggestions

    Returns:
        JSON list of suggested personas with relevance scores and rationale

    Example:
        # Get suggestions for a query
        suggestions = suggest_personas_for_query(
            query="How should we handle user authentication?",
            max_suggestions=3
        )

        # Returns:
        # {
        #   "query": "How should we handle user authentication?",
        #   "detected_context": "security",
        #   "suggestions": [
        #     {
        #       "name": "security-sentinel",
        #       "relevance": 0.95,
        #       "rationale": "Expert in authentication and security best practices"
        #     },
        #     {
        #       "name": "compliance-guardian",
        #       "relevance": 0.78,
        #       "rationale": "Can advise on regulatory requirements (GDPR, etc.)"
        #     },
        #     {
        #       "name": "pragmatic-architect",
        #       "relevance": 0.65,
        #       "rationale": "Can design scalable authentication architecture"
        #     }
        #   ]
        # }
    """
```

**Implementation:**
```python
@mcp.tool()
def suggest_personas_for_query(
    query: str,
    max_suggestions: int = 5,
    context: str = None
) -> str:
    """Suggest relevant personas for a given query."""

    # Use existing orchestrator logic
    from .context_detector import ContextDetector, QueryContext

    detector = ContextDetector()

    # Detect context if not provided
    if context:
        try:
            primary_context = QueryContext(context.upper())
        except ValueError:
            primary_context = detector.get_primary_context(query)
    else:
        primary_context = detector.get_primary_context(query)

    # Select personas using orchestrator's selection logic
    personas = orchestrator.select_personas(
        query=query,
        mode='auto',
        specific_personas=None,
        max_personas=max_suggestions
    )

    # Build suggestions with rationale
    suggestions = []
    for persona in personas:
        relevance = persona.relevance_score(query)

        # Generate rationale based on expertise match
        matched_expertise = [
            kw for kw in persona.expertise_areas
            if kw.lower() in query.lower()
        ]

        if matched_expertise:
            rationale = f"Expert in {', '.join(matched_expertise[:3])}"
        else:
            rationale = f"Relevant for {primary_context.value} context"

        suggestions.append({
            "name": persona.name,
            "display_name": persona.name.replace('-', ' ').title(),
            "relevance": round(relevance, 2),
            "rationale": rationale
        })

    # Return as JSON
    import json
    result = {
        "query": query,
        "detected_context": primary_context.value,
        "suggestions": suggestions,
        "count": len(suggestions)
    }

    return json.dumps(result, indent=2)
```

---

### 4. `get_session_context()` 🆕 NEW

**Purpose:** Return session memory (constraints, decisions, patterns) for context-aware analysis.

**Signature:**
```python
@mcp.tool()
def get_session_context(
    session_id: str = "default",
    project_root: str = None
) -> str:
    """
    Get session context (constraints, decisions, patterns) for context-aware analysis.

    Returns session memory that can be included when asking personas to analyze queries.
    This ensures consistency with previous decisions and agreed patterns.

    Args:
        session_id: Session identifier
        project_root: Optional project root for local sessions

    Returns:
        JSON with session constraints, patterns, and recent decisions
    """
```

**Implementation:**
```python
@mcp.tool()
def get_session_context(session_id: str = "default", project_root: str = None) -> str:
    """Get session context for context-aware analysis."""

    session = session_mgr.get_or_create_session(session_id, project_root)

    import json
    context = {
        "session_id": session_id,
        "active_constraints": session.active_constraints,
        "patterns_agreed": session.patterns_agreed,
        "recent_decisions": [
            {
                "id": d.id,
                "category": d.category,
                "description": d.description,
                "rationale": d.rationale,
                "timestamp": d.timestamp.isoformat() if hasattr(d, 'timestamp') else None
            }
            for d in session.decisions[-5:]  # Last 5 decisions
        ] if session.decisions else []
    }

    return json.dumps(context, indent=2)
```

---

### 5. `record_consultation()` 🆕 NEW

**Purpose:** Record a consultation for session history and analytics.

**Signature:**
```python
@mcp.tool()
def record_consultation(
    query: str,
    personas_used: List[str],
    session_id: str = "default",
    project_root: str = None,
    synthesis: str = None  # Optional: Claude's synthesis
) -> str:
    """
    Record a consultation in session history.

    After Claude analyzes a query using persona content, record the consultation
    for session analytics and history.

    Args:
        query: The original query
        personas_used: List of persona names that were consulted
        session_id: Session identifier
        project_root: Optional project root
        synthesis: Optional synthesis/recommendation from Claude

    Returns:
        Confirmation with consultation ID
    """
```

---

## 🔄 WORKFLOW EXAMPLES

### Example 1: Simple Single-Persona Query

**User asks Claude Code:** "Review this API design"

**Claude's internal process:**
```
1. Claude: Calls suggest_personas_for_query("Review this API design")
   MCP returns: ["api-platform-engineer", "security-sentinel", "pragmatic-architect"]

2. Claude: Decides to consult API Platform Engineer
   Calls get_persona_content("api-platform-engineer")
   MCP returns: Full API Platform Engineer SKILL.md content

3. Claude: Analyzes the API design using the persona content as context
   Generates response as API Platform Engineer

4. Claude: Calls record_consultation(
       query="Review this API design",
       personas_used=["api-platform-engineer"],
       synthesis="[Claude's analysis]"
   )
```

---

### Example 2: Multi-Persona Complex Query

**User asks Claude Code:** "Should we migrate to microservices?"

**Claude's internal process:**
```
1. Claude: Calls suggest_personas_for_query("Should we migrate to microservices?")
   MCP returns: [
     "pragmatic-architect" (relevance: 0.95),
     "site-reliability-engineer" (relevance: 0.85),
     "finops-optimizer" (relevance: 0.78),
     "devex-champion" (relevance: 0.65)
   ]

2. Claude: Calls get_session_context(session_id="my-project")
   MCP returns: {
     "active_constraints": ["AWS only", "Budget: $5K/month"],
     "patterns_agreed": ["Use Terraform for IaC"],
     "recent_decisions": [...]
   }

3. Claude: Consults each persona in sequence

   a. Calls get_persona_content("pragmatic-architect")
      MCP returns: Full Pragmatic Architect content
      Claude analyzes: "Architect's perspective: ..."

   b. Calls get_persona_content("site-reliability-engineer")
      MCP returns: Full SRE content
      Claude analyzes: "SRE's perspective: ..."

   c. Calls get_persona_content("finops-optimizer")
      MCP returns: Full FinOps content
      Claude analyzes: "FinOps perspective: ..."

   d. Calls get_persona_content("devex-champion")
      MCP returns: Full DevEx content
      Claude analyzes: "DevEx perspective: ..."

4. Claude: Synthesizes all perspectives
   - Identifies consensus: "All agree monitoring is critical"
   - Identifies tensions: "Architect wants split, FinOps warns about cost"
   - Provides recommendation: "Start with modular monolith..."

5. Claude: Calls record_consultation(
       query="Should we migrate to microservices?",
       personas_used=["pragmatic-architect", "site-reliability-engineer",
                      "finops-optimizer", "devex-champion"],
       synthesis="[Claude's full synthesis]"
   )
```

---

## 📊 COMPARISON: OLD vs NEW

### OLD (Broken) - MCP Does Analysis

| Aspect | Implementation |
|--------|---------------|
| **Tool** | `get_engineering_guidance(query)` |
| **MCP Role** | Tries to orchestrate and analyze |
| **Problem** | Returns placeholder text |
| **Result** | ❌ Useless |

### NEW (Correct) - MCP Provides Content

| Aspect | Implementation |
|--------|---------------|
| **Tools** | `list_available_personas()`, `get_persona_content()`, `suggest_personas_for_query()` |
| **MCP Role** | Content provider |
| **Benefit** | Claude gets real persona content |
| **Result** | ✅ Claude can analyze using persona context |

---

## 🛠️ IMPLEMENTATION PLAN

### Phase 1: Add New MCP Tools (6-8 hours)

1. **Update `list_available_skills()`** (1-2 hours)
   - Add JSON format option
   - Return structured metadata
   - Keep backward compatibility with markdown format

2. **Implement `get_persona_content()`** (2-3 hours)
   - Simple: just return `persona.full_content`
   - Add metadata header option
   - Add error handling for invalid names

3. **Implement `suggest_personas_for_query()`** (2-3 hours)
   - Reuse orchestrator's `select_personas()` logic
   - Return JSON with relevance scores
   - Add rationale generation

4. **Implement `get_session_context()`** (1 hour)
   - Return session memory as JSON
   - Include constraints, patterns, decisions

5. **Implement `record_consultation()`** (1 hour)
   - Record consultation in session history
   - Return confirmation with ID

---

### Phase 2: Deprecate Old Tools (2-3 hours)

1. **Mark `get_engineering_guidance()` as deprecated** (1 hour)
   - Add deprecation warning
   - Update docstring to point to new tools
   - Keep for backward compatibility (for now)

2. **Mark `consult_skill()` as deprecated** (1 hour)
   - Add deprecation warning
   - Update docstring
   - Keep for backward compatibility

3. **Update documentation** (1 hour)
   - README.md: Document new tools
   - Add migration guide from old to new

---

### Phase 3: Testing & Validation (4-6 hours)

1. **Unit Tests** (2-3 hours)
   - Test each new tool
   - Test JSON output formats
   - Test error handling

2. **Integration Tests** (1-2 hours)
   - Test workflow: list → suggest → get_content → record
   - Test with session context
   - Test with multiple personas

3. **Claude Code Testing** (1 hour)
   - Test calling new tools from Claude Code
   - Verify Claude can use persona content
   - Validate end-to-end flow

---

### Phase 4: Documentation & Release (2-3 hours)

1. **Update CHANGELOG.md** (30 min)
   - Document new tools
   - Mark old tools as deprecated

2. **Update README.md** (1 hour)
   - Add "How to Use" section with examples
   - Document tool signatures
   - Add workflow diagrams

3. **Update UPGRADING.md** (30 min)
   - Migration guide from v0.5.0 to v0.6.0
   - Explain new architecture

4. **Release** (30 min)
   - Tag v0.6.0
   - Publish to PyPI
   - Announce changes

---

## ✅ SUCCESS CRITERIA

1. **MCP Tools Work**
   - ✅ `list_available_personas()` returns JSON with all 23 personas
   - ✅ `get_persona_content("security-sentinel")` returns full SKILL.md
   - ✅ `suggest_personas_for_query()` returns relevant suggestions
   - ✅ `get_session_context()` returns session memory
   - ✅ `record_consultation()` saves to session history

2. **Claude Can Use Tools**
   - ✅ Claude Code can discover personas via `list_available_personas()`
   - ✅ Claude Code can get persona content via `get_persona_content()`
   - ✅ Claude Code can analyze queries using persona content
   - ✅ Claude Code can synthesize multiple perspectives

3. **No More Placeholders**
   - ✅ No tool returns "[This would be generated...]"
   - ✅ All tools return real, usable content
   - ✅ Claude gets actual analysis capability

4. **Session Management Works**
   - ✅ Session context influences analysis
   - ✅ Consultations are recorded
   - ✅ Analytics track persona usage

---

## 🚀 NEXT STEPS

1. **Review this design** - Confirm Option B approach
2. **Start Phase 1** - Implement new MCP tools
3. **Test with Claude Code** - Validate end-to-end
4. **Ship v0.6.0** - Release with new architecture

---

**Made with 🎭 by the Sensei Engineering Team**
*Architecture Design: 2025-01-23*
