Last active
July 14, 2026 07:54
-
-
Save nisanthchunduru/e9a462230c682d4bfee7e9b5c61b1b1e to your computer and use it in GitHub Desktop.
Codex Slack Proxy MCP server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ~/.codex/config.toml | |
| # ... | |
| ``` | |
| [mcp_servers.slack-mcp] | |
| command = "node" | |
| args = ["/Users/nisanth/repos/CodexSlackMCPProxyServer/src/index.js"] | |
| ``` | |
| # ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| import { spawn } from "node:child_process"; | |
| import { homedir } from "node:os"; | |
| import { join } from "node:path"; | |
| import { transformJsonRpcLine } from "./transform.js"; | |
| const command = | |
| process.env.SLACK_MCP_COMMAND ?? join(homedir(), ".toolbox", "bin", "aim"); | |
| const args = ["mcp", "start-server", "slack-mcp"]; | |
| const debug = process.env.CODEX_SLACK_MCP_DEBUG === "1"; | |
| const child = spawn(command, args, { | |
| env: process.env, | |
| stdio: ["pipe", "pipe", "pipe"], | |
| }); | |
| let forwardedSignal; | |
| process.stdin.pipe(child.stdin); | |
| child.stderr.pipe(process.stderr); | |
| let stdoutBuffer = ""; | |
| function writeLine(line, newline = "") { | |
| const transformed = transformJsonRpcLine(line); | |
| if (debug && transformed.stripped > 0) { | |
| process.stderr.write( | |
| `[codex-slack-mcp-server] stripped ${transformed.stripped} content annotation(s)\n`, | |
| ); | |
| } | |
| process.stdout.write(transformed.line + newline); | |
| } | |
| child.stdout.setEncoding("utf8"); | |
| child.stdout.on("data", (chunk) => { | |
| stdoutBuffer += chunk; | |
| let newlineIndex; | |
| while ((newlineIndex = stdoutBuffer.indexOf("\n")) !== -1) { | |
| const rawLine = stdoutBuffer.slice(0, newlineIndex); | |
| stdoutBuffer = stdoutBuffer.slice(newlineIndex + 1); | |
| const hasCarriageReturn = rawLine.endsWith("\r"); | |
| const line = hasCarriageReturn ? rawLine.slice(0, -1) : rawLine; | |
| writeLine(line, hasCarriageReturn ? "\r\n" : "\n"); | |
| } | |
| }); | |
| child.stdout.on("end", () => { | |
| if (stdoutBuffer) { | |
| writeLine(stdoutBuffer); | |
| stdoutBuffer = ""; | |
| } | |
| }); | |
| child.on("error", (error) => { | |
| process.stderr.write( | |
| `[codex-slack-mcp-server] failed to start Slack MCP: ${error.message}\n`, | |
| ); | |
| process.exitCode = 1; | |
| }); | |
| child.on("exit", (code, signal) => { | |
| if (forwardedSignal) { | |
| process.removeAllListeners(forwardedSignal); | |
| process.kill(process.pid, forwardedSignal); | |
| return; | |
| } | |
| if (signal) { | |
| process.removeAllListeners(signal); | |
| process.kill(process.pid, signal); | |
| return; | |
| } | |
| process.exitCode = code ?? 1; | |
| }); | |
| for (const signal of ["SIGINT", "SIGTERM"]) { | |
| process.on(signal, () => { | |
| if (!child.killed) { | |
| forwardedSignal = signal; | |
| child.kill(signal); | |
| } | |
| }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export function stripContentAnnotations(message) { | |
| const content = message?.result?.content; | |
| if (!Array.isArray(content)) { | |
| return 0; | |
| } | |
| let stripped = 0; | |
| for (const item of content) { | |
| if ( | |
| item && | |
| typeof item === "object" && | |
| Object.prototype.hasOwnProperty.call(item, "annotations") | |
| ) { | |
| delete item.annotations; | |
| stripped += 1; | |
| } | |
| } | |
| return stripped; | |
| } | |
| export function transformJsonRpcLine(line) { | |
| if (!line.trim()) { | |
| return { line, stripped: 0 }; | |
| } | |
| try { | |
| const message = JSON.parse(line); | |
| const stripped = stripContentAnnotations(message); | |
| return { | |
| line: stripped > 0 ? JSON.stringify(message) : line, | |
| stripped, | |
| }; | |
| } catch { | |
| return { line, stripped: 0 }; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment