claude-senator-mcp

claude-senator-mcp

An MCP server that enables inter-Claude communication and context sharing for seamless collaboration and conversation forking between multiple AI instances. It uses a smart pointer architecture to efficiently share project data and conversation history without interrupting ongoing tasks.

Category
Visit Server

README

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.

<!-- Claude Senator -->

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

MIT


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.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured