claude-senator-mcp

Vvkmnn/claude-senator-mcp

3.2

If you are the rightful owner of claude-senator-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.

Claude Senator is a Model Context Protocol (MCP) server designed for inter-Claude communication and context sharing, enabling collaboration and conversation forking among Claude instances.

Tools
4
Resources
0
Prompts
0

claude-senator-mcp

❌ under construction: This project is under heavy construction and is not intended for public use / nor has it been published to npm. Information in the README below may be outdated, user discretion is advised.

A Model Context Protocol (MCP) server for inter-Claude communication and context sharing. Enables Claude instances to collaborate, share context, and fork conversations without interruption.

TypeScript npm version License: MIT Node.js

Philosophy

Simple for humans, rich for Claude.

  • Human: One-line commands that expand into ultra-rich context
  • Claude: Dense collaboration intelligence with smart pointers
  • Architecture: Zero-dependency file-based IPC with beautiful ASCII UI

Install

Requirements:

npm install -g claude-senator

From shell:

claude mcp add claude-senator -- npx claude-senator

From inside Claude (restart required):

Add this to our global mcp config: npx claude-senator

From any manually configurable mcp.json: (Cursor, Windsurf, etc.)

{
  "mcpServers": {
    "claude-senator": {
      "command": "npx",
      "args": ["claude-senator"],
      "env": {}
    }
  }
}

Features

🏛️ Current: Inter-Claude Messaging System

3-Function Interface
# Share context with other Claude instances
claude-senator send_context --target_pid 98471 --context_request "Help with documentation"

# Receive context from other Claude instances
claude-senator receive_context

# Live status of all Claude instances with collaboration recommendations
claude-senator status
Smart Pointer Architecture

Ultra-lightweight context sharing using pointers to existing ~/.claude/projects/ data rather than copying content:

// Instead of copying data (expensive)
const heavyMessage = {
  conversationHistory: [
    /* 1000s of messages */
  ],
  fileContents: [
    /* large file contents */
  ],
};

// We use smart pointers (lightweight)
const smartMessage = {
  ctx_pointers: {
    projects_dir: `~/.claude/projects/${projectEncoded}`,
    conversation_history: this.getConversationPointer(),
    git_context: this.getGitContextString(),
    active_files: this.getActiveFilesArray(),
  },
};
Beautiful ASCII UI
╔═ 🏛️ ═══════════════════════════════════════════════════════════════════
║ → Claude 98471"Help with documentation..." • ~/.claude pointers sent
║ 🔄 Context shared • Ready for collaboration
╚═ 🚀 2 contexts processed • Rich collaboration network active

🔄 New: Context Forking System

Problem

You have Claude deep in work (318s, 9.3k tokens) and want to ask questions without interrupting.

Solution

Context forking creates new Claude instances with inherited context while preserving the working Claude's state.

# Fork context from working Claude
claude-senator fork_claude --source_pid 98471 --query "What's the documentation structure?"

# Result: New session with full context + your question
# Working Claude continues uninterrupted

Technical Architecture

Directory Structure

/tmp/claude-senator/
├── instances/          # Each Claude writes {pid}.json with status/info
├── messages/           # Individual message files in JSONL format
└── commands/           # Command injection files for input manipulation

Smart Pointer System

References existing ~/.claude/projects/ data instead of copying:

interface ContextPointers {
  projects_dir: string; // `~/.claude/projects/${encoded_path}`
  conversation_history: string; // Recent conversation file path
  git_context: string; // Compact git state (branch@commit+dirty)
  active_files: string[]; // Recently modified files
  current_task: string; // What Claude is working on
  collaboration_intent: string; // Why reaching out to other Claude
}

Message Format

Ultra-dense messaging with context reconstruction:

interface InterClaudeMessage {
  id: string;
  from: number; // Sender Claude PID
  to: number | 'all'; // Target Claude PID or broadcast
  type: 'ultra_dense_message';
  content: string; // Human-readable request
  timestamp: number;
  options: {
    claudeContext: {
      h: string; // Human message
      pid: number; // Claude PID
      ts: number; // Timestamp
      cwd: string; // Working directory
      ctx_pointers: ContextPointers; // Smart pointers to data
    };
  };
}

Implementation Details

Current Messaging System

SessionManager Core Methods
createMessage(humanMessage: string)

Creates ultra-dense context messages with smart pointers:

  • Purpose: Lightweight context sharing
  • Input: Human message string
  • Output: Smart pointer context object with collaboration intelligence
  • Used by: send_context tool
private createMessage(humanMessage: string): any {
  const workingDir = process.cwd();
  const claudeDir = join(homedir(), '.claude');
  const projectEncoded = workingDir.replace(/\//g, '-').replace(/^-/, '');
  const pid = process.ppid || process.pid;

  return {
    h: humanMessage,
    pid: pid,
    ts: Date.now(),
    cwd: workingDir,
    ctx_pointers: {
      projects_dir: `~/.claude/projects/${projectEncoded}`,
      conversation_history: this.getConversationPointer(),
      git_context: this.getGitContextString(),
      active_files: this.getActiveFilesArray(),
      current_task: this.getCurrentTaskFromContext(),
      collaboration_intent: this.determineCollaborationIntent(humanMessage)
    }
  };
}
reconstructRichContext(message: any)

Rebuilds full context from smart pointers:

  • Purpose: Context reconstruction on receiving end
  • Input: Message with smart pointers
  • Output: Full context object with conversation history
  • Used by: receive_context tool
private reconstructRichContext(message: any): any {
  const ctx = message.options?.claudeContext;
  if (!ctx?.ctx_pointers) return null;

  const pointers = ctx.ctx_pointers;
  const reconstructed = {
    sender_info: {
      human_message: ctx.h,
      pid: ctx.pid,
      working_directory: ctx.cwd,
      timestamp: ctx.ts
    },
    collaboration_context: {
      current_task: pointers.current_task,
      intent: pointers.collaboration_intent,
      git_state: pointers.git_context,
      active_files: pointers.active_files
    },
    shared_data_access: {
      projects_dir: pointers.projects_dir,
      conversation_history: pointers.conversation_history
    }
  };

  // Load conversation history if pointer exists
  if (pointers.conversation_history) {
    reconstructed.conversation_snippet = this.loadConversationSnippet(pointers.conversation_history);
  }

  return reconstructed;
}
generateRichContextDisplay(instance: any, activity: any)

Creates real-time status with collaboration scoring:

  • Purpose: Live context display without transmission
  • Input: Claude instance data and activity
  • Output: Rich context with collaboration readiness score
  • Used by: status tool
private generateRichContextDisplay(instance: any, activity: any): any {
  const workingDir = instance.cwd || instance.projectPath || '/unknown';
  const encodedPath = String(workingDir).replace(/\//g, '-').replace(/^-/, '');

  const contextPointers = {
    projectsDir: `~/.claude/projects/${encodedPath}`,
    conversationHistory: this.getConversationPointer(workingDir),
    gitContext: this.getGitContextString(workingDir),
    activeFiles: this.getActiveFilesArray(workingDir),
    currentTask: activity.task || 'Active',
    collaborationIntent: this.determineCollaborationReadiness(activity, instance)
  };

  const collaborationMetrics = {
    hasRecentActivity: activity.lastActivity > Date.now() - 300000,
    hasActiveFiles: contextPointers.activeFiles.length > 0,
    hasCleanGitState: !contextPointers.gitContext.includes('dirty'),
    isWorkingOnKnownTask: activity.task && activity.task !== 'Active',
    projectType: this.detectProjectType(workingDir)
  };

  return {
    ...contextPointers,
    collaborationMetrics,
    collaborationReason: this.getCollaborationReason(collaborationMetrics),
    readinessScore: this.calculateReadinessScore(collaborationMetrics)
  };
}
Collaboration Scoring Algorithm
private calculateCollaborationScore(contextData: any): number {
  const metrics = contextData.collaborationMetrics;
  if (!metrics) return 0;

  let score = 0;
  if (metrics.hasRecentActivity) score += 0.3;
  if (metrics.hasActiveFiles) score += 0.2;
  if (metrics.hasCleanGitState) score += 0.2;
  if (metrics.isWorkingOnKnownTask) score += 0.2;
  if (metrics.projectType !== 'unknown') score += 0.1;

  return Math.min(score, 1.0);
}
Context Pointer Helpers
private getConversationPointer(): string | null {
  const claudeDir = join(homedir(), '.claude');
  const projectEncoded = process.cwd().replace(/\//g, '-').replace(/^-/, '');
  const projectDir = join(claudeDir, 'projects', projectEncoded);

  if (existsSync(projectDir)) {
    const files = readdirSync(projectDir).filter(f => f.includes('conversation'));
    if (files.length > 0) {
      return `~/.claude/projects/${projectEncoded}/${files[files.length - 1]}`;
    }
  }
  return null;
}

private getGitContextString(): string {
  try {
    const branch = execSync('git branch --show-current 2>/dev/null', { encoding: 'utf8' }).trim();
    const commit = execSync('git rev-parse --short HEAD 2>/dev/null', { encoding: 'utf8' }).trim();
    const status = execSync('git status --porcelain 2>/dev/null', { encoding: 'utf8' }).trim();
    const dirty = status ? '+dirty' : '';
    return `${branch}@${commit}${dirty}`;
  } catch (error) {
    return 'no-git';
  }
}

private getActiveFilesArray(): string[] {
  try {
    const recentFiles = execSync('git diff --name-only HEAD~1 2>/dev/null', {
      encoding: 'utf8'
    }).trim().split('\n').filter(f => f);
    return recentFiles.slice(0, 5);
  } catch (error) {
    return [];
  }
}

New Context Forking System

Core Implementation
// New MCP tool
{
  name: 'fork_claude',
  description: 'Create new Claude session with full context from target Claude',
  inputSchema: {
    source_pid: { type: 'number', description: 'Claude to copy from' },
    query: { type: 'string', description: 'Your question for the new Claude' }
  }
}

// Implementation
case 'fork_claude': {
  const sourcePid = args?.source_pid as number;
  const query = args?.query as string;

  // Find source Claude's conversation
  const sourceActivity = this.sessionManager.parseLiveActivity(sourcePid);
  const conversationPath = this.findConversationPath(sourcePid);

  // Copy conversation to new session
  const newSessionId = this.createForkedSession(conversationPath, query);

  return {
    content: [{
      type: 'text',
      text: `╔═ 🔄 Context Forked ═══════════════════════════════════════════════════
║ 📸 Copied: ${sourceActivity.task} • Full conversation history
║ 🆕 New session: ${newSessionId}
║ 🎯 Ready for: "${query}"
╚═ ✨ Run: claude --session ${newSessionId} to start new Claude with context`
    }]
  };
}
Session Creation
private createForkedSession(sourcePath: string, newQuery: string): string {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '');
  const newSessionId = `fork_${timestamp}`;
  const newSessionPath = join(homedir(), '.claude', 'sessions', newSessionId);

  // Create new session directory
  mkdirSync(newSessionPath, { recursive: true });

  // Copy conversation history
  if (existsSync(sourcePath)) {
    const conversationContent = readFileSync(sourcePath, 'utf8');
    const newConversationPath = join(newSessionPath, 'conversation.jsonl');
    writeFileSync(newConversationPath, conversationContent);

    // Add new query as next message
    const queryMessage = {
      type: 'user',
      message: { content: newQuery },
      timestamp: Date.now()
    };

    appendFileSync(newConversationPath, '\n' + JSON.stringify(queryMessage));
  }

  return newSessionId;
}

Usage Examples

Basic Messaging Workflow

# 1. Check who's available for collaboration
claude-senator status

# Output:
╔═ 🏛️ ═══════════════════════════════════════════════════════════════════
3 Claudes active • rich context network
║ 🟢 Claude 98471 • rust-project • debugging memory leak • main@a1b2c3
╚═ 🔄 Live status • Smart pointer network active

# 2. Send context to specific Claude
claude-senator send_context --target_pid 98471 --context_request "Need help with async Rust debugging"

# Output:
╔═ 🏛️ ═══════════════════════════════════════════════════════════════════
║ → Claude 98471"Need help with async Rust debugging" • ~/.claude pointers sent
║ 🔄 Context shared • Ready for collaboration
╚═ 🚀 Context transmitted • Collaboration network active

# 3. Receive context from other Claudes
claude-senator receive_context

# Output:
╔═ 🏛️ ═══════════════════════════════════════════════════════════════════
"Debug memory leak in tokio runtime" • debugging_assistance • rust-project
║ 📊 Rich context: git state, active files, current task
╚═ 📨 1 context processed • Ready for collaboration

Context Forking Workflow

# Scenario: Claude deep in documentation work, want to ask questions
claude-senator status

# Output shows Claude 98471 working on documentation (318s, 9.3k tokens)
╔═ 🏛️ ═══════════════════════════════════════════════════════════════════
1 Claude active • rich context network
║ 🟡 Claude 98471 • docs-project • Writing API documentation • main@x1y2z3
╚═ 🔄 Live status • Smart pointer network active

# Fork context without interrupting
claude-senator fork_claude --source_pid 98471 --query "What's the current API documentation structure?"

# Output:
╔═ 🔄 Context Forked ═══════════════════════════════════════════════════════
║ 📸 Copied: Writing API documentation • 9.3k tokens • Full conversation
║ 🆕 New session: fork_20250716_141509
║ 🎯 Ready for: "What's the current API documentation structure?"
╚═ ✨ Run: claude --session fork_20250716_141509 to start new Claude

# Start new Claude with inherited context
claude --session fork_20250716_141509
# New Claude starts with full context + your question already asked

Architecture Benefits

Zero Dependencies

  • No npm packages beyond @modelcontextprotocol/sdk
  • No external services (Redis, databases, etc.)
  • No system dependencies
  • No elevated permissions

Token Efficiency

  • Smart pointers prevent data duplication
  • Context reconstruction on-demand
  • Minimal memory footprint
  • Efficient git state tracking

Scalability

  • 2-20 Claudes: Excellent performance (<10ms operations)
  • 20-100 Claudes: Good performance, minimal filesystem overhead
  • 100+ Claudes: May benefit from SQLite upgrade (see Future section)

Reliability

  • Each Claude owns its files (no shared writes)
  • Automatic cleanup of dead instances
  • Graceful error handling
  • Self-healing directory structure

UI Design Philosophy

3-Line ASCII Format

╔═ 🏛️ ═══════════════════════════════════════════════════════════════════
[CONTENT LINE - exactly fits terminal width]
[STATUS LINE - shows current state and metrics]
╚═ [FOOTER LINE - shows next action or network status]

Truncation Rules

  • Content truncated to fit terminal width
  • Important information prioritized
  • Emoji indicators for quick scanning
  • Consistent spacing and alignment

Tool-Specific Emoji

  • 🏛️ Always at top (Claude Senator identity)
  • 🔄 Context sharing operations
  • 📨 Message receiving
  • 🔄 Context forking
  • 🚀 Network activity

File Structure

Core Files

src/
├── index.ts          # MCP server and tool handlers
├── session.ts        # SessionManager - core messaging logic
├── memory.ts         # MemoryManager - conversation search
├── injection.ts      # CommandInjector - input manipulation
└── types.ts          # TypeScript interfaces

Key Classes

SessionManager (src/session.ts)
  • Purpose: Core messaging and context management
  • Key methods: createMessage, reconstructRichContext, generateRichContextDisplay
  • Handles: Smart pointers, context reconstruction, collaboration scoring
MemoryManager (src/memory.ts)
  • Purpose: Conversation history search and analysis
  • Key methods: TBD (future implementation)
  • Handles: Historical context retrieval, memory patterns
CommandInjector (src/injection.ts)
  • Purpose: Input manipulation and command routing
  • Key methods: TBD (future implementation)
  • Handles: Inter-Claude command injection, workflow automation

Future Enhancements

Messaging System Extensions

// Planned tools
{
  name: 'broadcast_context',
  description: 'Send context to all active Claude instances'
}

{
  name: 'handoff_context',
  description: 'Transfer work to another Claude with full context'
}

{
  name: 'sync_context',
  description: 'Synchronize context across multiple Claude instances'
}

Context Forking Improvements

// Selective inheritance
{
  name: 'fork_claude_selective',
  inputSchema: {
    source_pid: number,
    query: string,
    include_conversation: boolean,
    include_files: boolean,
    include_git_state: boolean
  }
}

// Context merging
{
  name: 'merge_context',
  description: 'Merge insights from forked Claude back to parent'
}

Performance Optimizations

  • Context Caching: LRU cache for frequently accessed contexts
  • Compression: Gzip compression for large conversation histories
  • Streaming: Real-time context updates as work progresses
  • SQLite Upgrade: For 100+ concurrent Claude instances

Integration Possibilities

  • IDE Plugins: VS Code, Cursor, Windsurf integration
  • CI/CD: Automated context sharing in build pipelines
  • Monitoring: Real-time collaboration network visualization
  • Analytics: Context sharing patterns and optimization

Project Split Guide

If splitting into separate projects:

Core Messaging (claude-senator-messaging)

  • Files: src/session.ts (lines 1-883, 1075-1451), src/types.ts
  • Dependencies: src/memory.ts for conversation search
  • Features: send_context, receive_context, status
  • Size: ~1400 lines, full messaging system

Context Forking (claude-senator-forking)

  • Files: New implementation in src/forking.ts
  • Dependencies: src/session.ts (conversation finding methods)
  • Features: fork_claude tool
  • Size: ~50 lines, minimal implementation

Shared Infrastructure (claude-senator-core)

  • Files: src/types.ts, directory management utilities
  • Purpose: Common interfaces and utilities
  • Size: ~200 lines, essential types and helpers

Migration Strategy

  1. Extract core types: Move interfaces to shared package
  2. Split session manager: Separate messaging and forking logic
  3. Maintain compatibility: Ensure both systems can coexist
  4. Document interfaces: Clear APIs for integration

Development

git clone https://github.com/yourusername/claude-senator
cd claude-senator
npm install
npm run build
npm test

Contributing

  • Fork the repository and create feature branches
  • Test with multiple Claude instances before submitting PRs
  • Follow TypeScript strict mode and MCP protocol standards
  • Document any new smart pointer patterns

Testing

  • Test messaging between 2-5 Claude instances
  • Verify context reconstruction accuracy
  • Test forking with large conversation histories
  • Validate ASCII UI formatting across terminals

License


Claude Senator enables unprecedented collaboration between Claude instances through smart context sharing and non-disruptive forking. Built for developers who need their AI assistants to work together as seamlessly as they do.