From c79fd4cb4093b00796c04a3fc269ab486d99fc56 Mon Sep 17 00:00:00 2001 From: "courtmanr@gmail.com" Date: Mon, 24 Nov 2025 23:13:42 +0000 Subject: [PATCH] chore: remove mcp-server directory Remove MCP (Model Context Protocol) server integration. This was an AI assistant tool that doesn't belong in the main repository. --- mcp-server/README.md | 65 ----------------- mcp-server/src/index.ts | 150 --------------------------------------- mcp-server/tsconfig.json | 20 ------ 3 files changed, 235 deletions(-) delete mode 100644 mcp-server/README.md delete mode 100644 mcp-server/src/index.ts delete mode 100644 mcp-server/tsconfig.json diff --git a/mcp-server/README.md b/mcp-server/README.md deleted file mode 100644 index d4deba7a8..000000000 --- a/mcp-server/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Pulse Codex MCP Server - -An MCP (Model Context Protocol) server that provides OpenAI Codex integration for Claude Code. - -## Features - -- **codex** - Ask questions to OpenAI Codex AI assistant -- **codex_clear_session** - Clear stored session context -- Automatic session management across conversation turns -- Clean response extraction (no token counts or debug info) - -## Installation - -### 1. Build the Server - -```bash -cd /opt/pulse/mcp-server -npm install -npm run build -``` - -### 2. Add to Claude Code - -```bash -claude mcp add --transport stdio pulse-codex -- node /opt/pulse/mcp-server/dist/index.js -``` - -## Usage - -### In Claude Code Conversations - -**Ask a question:** -``` -Use the codex tool to evaluate whether we should use X or Y for Z scenario -``` - -**Continue a conversation:** -``` -Use the codex tool with conversationId "my-conversation" to dig deeper into that approach -``` - -**Start fresh:** -``` -Use the codex_clear_session tool with conversationId "my-conversation" -``` - -## How It Works - -- Each conversation is identified by a `conversationId` -- The server automatically maintains codex session IDs for each conversation -- Responses are clean (just the answer, no metadata) -- Sessions persist across multiple tool calls with the same conversationId - -## Development - -Watch mode for development: -```bash -npm run dev -``` - -## Architecture - -- **TypeScript** - Type-safe MCP server implementation -- **@modelcontextprotocol/sdk** - Official MCP SDK -- **stdio transport** - Communicates with Claude Code via standard input/output diff --git a/mcp-server/src/index.ts b/mcp-server/src/index.ts deleted file mode 100644 index d9e12d6fd..000000000 --- a/mcp-server/src/index.ts +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env node - -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { z } from "zod"; -import { exec } from "child_process"; -import { promisify } from "util"; -import { writeFile, readFile } from "fs/promises"; -import { tmpdir } from "os"; -import { join } from "path"; -import { randomBytes } from "crypto"; - -const execAsync = promisify(exec); - -// Session management -const sessions = new Map(); // Map conversation ID to codex session ID - -// Create the MCP server -const server = new McpServer({ - name: "pulse-codex", - version: "1.0.0", -}); - -// Register the codex tool for both questions and implementation -server.registerTool( - "codex", - { - title: "Codex AI Assistant", - description: "Ask OpenAI Codex to implement changes or answer questions. Codex has full filesystem access and can create/modify files directly. Use this for architectural decisions, code review, technical consultation, and implementation tasks.", - inputSchema: { - question: z.string().describe("The question or implementation task for Codex"), - conversationId: z.string().optional().describe("Optional conversation ID to maintain context across calls"), - }, - }, - async ({ question, conversationId }) => { - const convId = conversationId || `conv-${Date.now()}-${process.pid}`; - const uniqueId = `${Date.now()}-${process.pid}-${randomBytes(4).toString('hex')}`; - const tempFile = join(tmpdir(), `codex-${uniqueId}.txt`); - - try { - // Check if we have an existing codex session for this conversation - const existingSessionId = sessions.get(convId); - - // Write question to a temp file to avoid shell escaping issues - const questionFile = join(tmpdir(), `codex-q-${uniqueId}.txt`); - await writeFile(questionFile, question, "utf-8"); - - let command: string; - if (existingSessionId) { - // Resume existing session - command = `codex exec --yolo -o "${tempFile}" resume "${existingSessionId}" < "${questionFile}"`; - } else { - // Start new session - command = `codex exec --yolo -o "${tempFile}" < "${questionFile}"`; - } - - // Execute codex and capture stderr for session ID only - // Note: stderr contains all reasoning output, but we only need the session ID - const { stdout, stderr } = await execAsync(command, { - timeout: 1800000, // 30 minute timeout (codex can take a very long time for complex queries) - maxBuffer: 10 * 1024 * 1024, // 10MB buffer - }); - - // Extract only the session ID from stderr - const sessionIdMatch = stderr.match(/session id:\s*([a-f0-9-]+)/); - const sessionId = sessionIdMatch ? sessionIdMatch[1] : ""; - - // Store session for this conversation - if (sessionId && !existingSessionId) { - sessions.set(convId, sessionId); - } - - // Read the response from the output file - const response = await readFile(tempFile, "utf-8"); - - return { - content: [ - { - type: "text", - text: `${response.trim()}\n\n---\nSession ID: ${sessionId}\nConversation ID: ${convId}`, - }, - ], - }; - } catch (error) { - // Log full error to stderr for debugging - console.error("Codex execution error:", error); - - // Extract only the relevant error info, not the full stderr with reasoning - let errorMessage = "Unknown error"; - if (error instanceof Error) { - // For exec errors, the message contains both stdout and stderr - // We want to extract just the actual error, not all the reasoning output - const lines = error.message.split('\n'); - // Look for actual error messages (usually start with "Error:" or contain "failed") - const relevantLines = lines.filter(line => - line.includes('Error:') || - line.includes('failed') || - line.includes('not found') || - line.includes('permission denied') || - line.includes('exit code') - ); - errorMessage = relevantLines.length > 0 ? relevantLines.join('\n') : error.message; - } - throw new Error(`Failed to execute codex: ${errorMessage}`); - } - } -); - -// Register a tool to clear session history -server.registerTool( - "codex_clear_session", - { - title: "Clear Codex Session", - description: "Clear the stored codex session for a conversation, starting fresh", - inputSchema: { - conversationId: z.string().describe("The conversation ID to clear"), - }, - }, - async ({ conversationId }) => { - const existed = sessions.has(conversationId); - sessions.delete(conversationId); - - const message = existed - ? `Session cleared for conversation ${conversationId}` - : `No session found for conversation ${conversationId}`; - - return { - content: [ - { - type: "text", - text: message, - }, - ], - }; - } -); - -// Connect to stdio transport -async function main() { - const transport = new StdioServerTransport(); - await server.connect(transport); - - // Log to stderr so it doesn't interfere with MCP protocol - console.error("Pulse Codex MCP Server running on stdio"); -} - -main().catch((error) => { - console.error("Fatal error:", error); - process.exit(1); -}); diff --git a/mcp-server/tsconfig.json b/mcp-server/tsconfig.json deleted file mode 100644 index 6ba475493..000000000 --- a/mcp-server/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "lib": ["ES2022"], - "moduleResolution": "node", - "rootDir": "./src", - "outDir": "./dist", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -}