#
tokens: 11042/50000 7/7 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── examples
│   ├── crash.c
│   └── USAGE.md
├── install.sh
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# MCP GDB Server

A Model Context Protocol (MCP) server that provides GDB debugging functionality for use with Claude or other AI assistants.

## Features

- Start and manage GDB debugging sessions
- Load programs and core dumps for analysis
- Set breakpoints, step through code, and examine memory
- View call stacks, variables, and registers
- Execute arbitrary GDB commands

## Installation

```bash
# Clone the repository
git clone https://github.com/signal-slot/mcp-gdb.git
cd mcp-gdb

# Install dependencies
npm install

# Build the project
npm run build
```

## Usage

### Using with Claude or other MCP-enabled assistants

1. Configure the MCP settings in the Claude desktop app or browser extension to include this server:

```json
{
  "mcpServers": {
    "gdb": {
      "command": "node",
      "args": ["/path/to/mcp-gdb/build/index.js"],
      "disabled": false
    }
  }
}
```

2. Restart Claude or refresh the page.

3. Now you can use the GDB tools in your conversations with Claude.

### Example Commands

Here are some examples of using the GDB MCP server through Claude:

#### Starting a GDB session
```
Use gdb_start to start a new debugging session
```

#### Loading a program
```
Use gdb_load to load /path/to/my/program with the sessionId that was returned from gdb_start
```

#### Setting a breakpoint
```
Use gdb_set_breakpoint to set a breakpoint at main in the active GDB session
```

#### Running the program
```
Use gdb_continue to start execution
```

#### Examining variables
```
Use gdb_print to evaluate the expression "my_variable" in the current context
```

#### Getting a backtrace
```
Use gdb_backtrace to see the current call stack
```

#### Terminating the session
```
Use gdb_terminate to end the debugging session
```

## Supported GDB Commands

- `gdb_start`: Start a new GDB session
- `gdb_load`: Load a program into GDB
- `gdb_command`: Execute an arbitrary GDB command
- `gdb_terminate`: Terminate a GDB session
- `gdb_list_sessions`: List all active GDB sessions
- `gdb_attach`: Attach to a running process
- `gdb_load_core`: Load a core dump file
- `gdb_set_breakpoint`: Set a breakpoint
- `gdb_continue`: Continue program execution
- `gdb_step`: Step program execution
- `gdb_next`: Step over function calls
- `gdb_finish`: Execute until the current function returns
- `gdb_backtrace`: Show call stack
- `gdb_print`: Print value of expression
- `gdb_examine`: Examine memory
- `gdb_info_registers`: Display registers

## License

MIT

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "build",
    "declaration": true,
    "sourceMap": true,
    "resolveJsonModule": true,
    "noImplicitAny": false,
    "allowSyntheticDefaultImports": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build"]
}

```

--------------------------------------------------------------------------------
/examples/crash.c:
--------------------------------------------------------------------------------

```cpp
#include <stdio.h>
#include <stdlib.h>

void function_that_crashes() {
    // Access a null pointer to cause a segmentation fault
    int *ptr = NULL;
    *ptr = 42;  // This will cause a crash
}

void function_with_args(int a, int b) {
    printf("Arguments: a=%d, b=%d\n", a, b);
    if (a > 10) {
        function_that_crashes();
    }
}

int main(int argc, char **argv) {
    printf("Starting the program...\n");
    
    // Print command line arguments
    printf("Got %d arguments\n", argc);
    for (int i = 0; i < argc; i++) {
        printf("Argument %d: %s\n", i, argv[i]);
    }
    
    int number = 5;
    
    if (argc > 1) {
        number = atoi(argv[1]);
    }
    
    printf("Working with number: %d\n", number);
    
    function_with_args(number, number * 2);
    
    printf("Program completed successfully\n");
    return 0;
}

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "mcp-gdb",
  "version": "0.1.1",
  "description": "MCP server for GDB debugging functionality",
  "type": "module",
  "main": "build/index.js",
  "scripts": {
    "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
    "start": "node build/index.js",
    "dev": "tsc-watch --onSuccess \"node build/index.js\"",
    "lint": "eslint src/**/*.ts",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "gdb",
    "debug",
    "mcp"
  ],
  "author": "Tasuku Suzuki",
  "license": "MIT",
  "devDependencies": {
    "@types/node": "^20.10.5",
    "@typescript-eslint/eslint-plugin": "^6.15.0",
    "@typescript-eslint/parser": "^6.15.0",
    "eslint": "^8.56.0",
    "tsc-watch": "^6.0.4",
    "typescript": "^5.3.3"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.7.0"
  },
  "directories": {
    "example": "examples"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/signal-slot/mcp-gdb.git"
  },
  "types": "./build/index.d.ts",
  "bugs": {
    "url": "https://github.com/signal-slot/mcp-gdb/issues"
  },
  "homepage": "https://github.com/signal-slot/mcp-gdb#readme"
}

```

--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash

# MCP GDB Server Installer Script

set -e

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
BUILD_DIR="$SCRIPT_DIR/build"
GDB_PATH=$(which gdb 2>/dev/null || echo "")

echo "MCP GDB Server Installer"
echo "========================"
echo

# Check if GDB is installed
if [ -z "$GDB_PATH" ]; then
    echo "⚠️ Warning: GDB is not found in your PATH. You need to install GDB before using this MCP server."
    echo "On Ubuntu/Debian: sudo apt-get install gdb"
    echo "On Fedora/RHEL: sudo dnf install gdb"
    echo "On Arch Linux: sudo pacman -S gdb"
    echo "On macOS: brew install gdb"
    echo
    read -p "Do you want to continue with the installation? (y/n) " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        exit 1
    fi
fi

# Install dependencies
echo "Installing dependencies..."
npm install

# Build the project
echo "Building the MCP GDB server..."
npm run build

# Get the absolute path to the build directory
ABSOLUTE_PATH=$(cd "$BUILD_DIR" && pwd)

# Generate MCP settings configuration snippet
echo
echo "MCP GDB Server has been built successfully!"
echo
echo "To use it with Claude or other MCP-enabled assistants, add the following to your MCP settings configuration:"
echo
echo "{" 
echo "  \"mcpServers\": {"
echo "    \"gdb\": {"
echo "      \"command\": \"node\","
echo "      \"args\": [\"$ABSOLUTE_PATH/index.js\"],"
echo "      \"disabled\": false"
echo "    }"
echo "  }"
echo "}"
echo
echo "For Claude Desktop, this file is typically located at:"
echo "- Linux: ~/.config/Claude/claude_desktop_config.json"
echo "- macOS: ~/Library/Application Support/Claude/claude_desktop_config.json"
echo "- Windows: %APPDATA%\\Claude\\claude_desktop_config.json"
echo
echo "For Claude in VSCode, this file is typically located at:"
echo "- Linux: ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json"
echo "- macOS: ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json"
echo "- Windows: %APPDATA%\\Code\\User\\globalStorage\\saoudrizwan.claude-dev\\settings\\cline_mcp_settings.json"
echo
echo "After adding the configuration, restart Claude or reload the extension for the changes to take effect."
echo
echo "To test the MCP GDB server, compile and debug the example program:"
echo "  cd examples"
echo "  gcc -g crash.c -o crash"
echo
echo "Then follow the instructions in examples/USAGE.md to debug the program using Claude."
echo

# Create example directory and compile the example file
if [ -d "$SCRIPT_DIR/examples" ]; then
    echo "Would you like to compile the example program now? (y/n) "
    read -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        cd "$SCRIPT_DIR/examples"
        echo "Compiling example program..."
        gcc -g crash.c -o crash
        echo "Example program compiled successfully!"
    fi
fi

echo "Installation complete!"

```

--------------------------------------------------------------------------------
/examples/USAGE.md:
--------------------------------------------------------------------------------

```markdown
# Using the MCP GDB Server: Example Usage

This guide demonstrates how to use the MCP GDB server to debug the included `crash.c` example.

## Compiling the Example

First, compile the example with debug symbols:

```bash
cd examples
gcc -g crash.c -o crash
```

## Debugging Session Example

Here's a step-by-step guide showing how to debug the crash.c program using the MCP GDB server through Claude.

### 1. Start a GDB Session

Ask Claude to start a new GDB session:

```
I need to debug a program that's crashing. Can you start a new GDB session for me?
```

Claude will use the `gdb_start` tool:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_start</tool_name>
<arguments>
{}
</arguments>
</use_mcp_tool>
```

Claude will receive a response with a session ID (e.g., "1616161616161").

### 2. Load the Program

Now, ask Claude to load the program:

```
Can you load the crash executable I compiled in the examples directory?
```

Claude will use the `gdb_load` tool:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_load</tool_name>
<arguments>
{
  "sessionId": "1616161616161",
  "program": "/path/to/mcp-gdb/examples/crash"
}
</arguments>
</use_mcp_tool>
```

### 3. Set Breakpoints

Set a breakpoint at the main function:

```
Please set a breakpoint at the main function.
```

Claude will use `gdb_set_breakpoint`:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_set_breakpoint</tool_name>
<arguments>
{
  "sessionId": "1616161616161",
  "location": "main"
}
</arguments>
</use_mcp_tool>
```

Let's also set a breakpoint at the function that might crash:

```
Can you also set a breakpoint at function_with_args?
```

Claude will set another breakpoint:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_set_breakpoint</tool_name>
<arguments>
{
  "sessionId": "1616161616161",
  "location": "function_with_args"
}
</arguments>
</use_mcp_tool>
```

### 4. Start the Program

Start the program with an argument that will cause a crash (any number > 10):

```
Please run the program with an argument of 15, which should trigger the crash.
```

Claude will use `gdb_command` to set the arguments and then run the program:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_command</tool_name>
<arguments>
{
  "sessionId": "1616161616161",
  "command": "set args 15"
}
</arguments>
</use_mcp_tool>
```

Then Claude will start the program:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_continue</tool_name>
<arguments>
{
  "sessionId": "1616161616161"
}
</arguments>
</use_mcp_tool>
```

The program will hit the first breakpoint at `main`.

### 5. Step Through the Program

Ask Claude to step through the execution:

```
Please step through the program execution so we can see what's happening.
```

Claude will use `gdb_next` to step through the code:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_next</tool_name>
<arguments>
{
  "sessionId": "1616161616161"
}
</arguments>
</use_mcp_tool>
```

Repeat this command to step through the program.

### 6. Examine Variables

At any point, you can ask Claude to print the value of variables:

```
What is the value of the 'number' variable?
```

Claude will use `gdb_print`:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_print</tool_name>
<arguments>
{
  "sessionId": "1616161616161",
  "expression": "number"
}
</arguments>
</use_mcp_tool>
```

### 7. Continue to Crash

Continue execution until the program crashes:

```
Please continue execution until we hit the crash.
```

Claude will use `gdb_continue`:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_continue</tool_name>
<arguments>
{
  "sessionId": "1616161616161"
}
</arguments>
</use_mcp_tool>
```

The program will hit the second breakpoint and then crash when trying to dereference a NULL pointer.

### 8. Analyze the Crash

When the program crashes, examine the backtrace to see where it occurred:

```
Can you show me the backtrace of the crash?
```

Claude will use `gdb_backtrace`:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_backtrace</tool_name>
<arguments>
{
  "sessionId": "1616161616161"
}
</arguments>
</use_mcp_tool>
```

The backtrace will show that the crash occurred in `function_that_crashes` when trying to dereference a NULL pointer.

### 9. Terminate the Session

When you're done debugging, terminate the GDB session:

```
Please terminate the GDB session.
```

Claude will use `gdb_terminate`:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_terminate</tool_name>
<arguments>
{
  "sessionId": "1616161616161"
}
</arguments>
</use_mcp_tool>
```

## Using with Core Dumps

If the program has already crashed and generated a core dump, you can load it for analysis:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_start</tool_name>
<arguments>
{}
</arguments>
</use_mcp_tool>
```

Then load the program and core dump:

```
<use_mcp_tool>
<server_name>gdb</server_name>
<tool_name>gdb_load_core</tool_name>
<arguments>
{
  "sessionId": "1616161616161",
  "program": "/path/to/mcp-gdb/examples/crash",
  "corePath": "/path/to/core.dump"
}
</arguments>
</use_mcp_tool>
```

Then you can analyze the crash just as if you had caught it in real-time.

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ErrorCode,
  ListToolsRequestSchema,
  McpError
} from '@modelcontextprotocol/sdk/types.js';
import { spawn, ChildProcess } from 'child_process';
import * as readline from 'readline';
import * as fs from 'fs';
import * as path from 'path';

// Interface for GDB session
interface GdbSession {
  process: ChildProcess;
  rl: readline.Interface;
  ready: boolean;
  id: string;
  target?: string;
  workingDir?: string;
}

// Map to store active GDB sessions
const activeSessions = new Map<string, GdbSession>();

class GdbServer {
  private server: Server;

  constructor() {
    this.server = new Server(
      {
        name: 'mcp-gdb-server',
        version: '0.1.0',
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    this.setupToolHandlers();
    
    // Error handling
    this.server.onerror = (error) => console.error('[MCP Error]', error);
    process.on('SIGINT', async () => {
      // Clean up all active GDB sessions
      for (const [id, session] of activeSessions.entries()) {
        await this.terminateGdbSession(id);
      }
      await this.server.close();
      process.exit(0);
    });
  }

  private setupToolHandlers() {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'gdb_start',
          description: 'Start a new GDB session',
          inputSchema: {
            type: 'object',
            properties: {
              gdbPath: {
                type: 'string',
                description: 'Path to the GDB executable (optional, defaults to "gdb")'
              },
              workingDir: {
                type: 'string',
                description: 'Working directory for GDB (optional)'
              }
            }
          }
        },
        {
          name: 'gdb_load',
          description: 'Load a program into GDB',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              program: {
                type: 'string',
                description: 'Path to the program to debug'
              },
              arguments: {
                type: 'array',
                items: {
                  type: 'string'
                },
                description: 'Command-line arguments for the program (optional)'
              }
            },
            required: ['sessionId', 'program']
          }
        },
        {
          name: 'gdb_command',
          description: 'Execute a GDB command',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              command: {
                type: 'string',
                description: 'GDB command to execute'
              }
            },
            required: ['sessionId', 'command']
          }
        },
        {
          name: 'gdb_terminate',
          description: 'Terminate a GDB session',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              }
            },
            required: ['sessionId']
          }
        },
        {
          name: 'gdb_list_sessions',
          description: 'List all active GDB sessions',
          inputSchema: {
            type: 'object',
            properties: {}
          }
        },
        {
          name: 'gdb_attach',
          description: 'Attach to a running process',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              pid: {
                type: 'number',
                description: 'Process ID to attach to'
              }
            },
            required: ['sessionId', 'pid']
          }
        },
        {
          name: 'gdb_load_core',
          description: 'Load a core dump file',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              program: {
                type: 'string',
                description: 'Path to the program executable'
              },
              corePath: {
                type: 'string',
                description: 'Path to the core dump file'
              }
            },
            required: ['sessionId', 'program', 'corePath']
          }
        },
        {
          name: 'gdb_set_breakpoint',
          description: 'Set a breakpoint',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              location: {
                type: 'string',
                description: 'Breakpoint location (e.g., function name, file:line)'
              },
              condition: {
                type: 'string',
                description: 'Breakpoint condition (optional)'
              }
            },
            required: ['sessionId', 'location']
          }
        },
        {
          name: 'gdb_continue',
          description: 'Continue program execution',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              }
            },
            required: ['sessionId']
          }
        },
        {
          name: 'gdb_step',
          description: 'Step program execution',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              instructions: {
                type: 'boolean',
                description: 'Step by instructions instead of source lines (optional)'
              }
            },
            required: ['sessionId']
          }
        },
        {
          name: 'gdb_next',
          description: 'Step over function calls',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              instructions: {
                type: 'boolean',
                description: 'Step by instructions instead of source lines (optional)'
              }
            },
            required: ['sessionId']
          }
        },
        {
          name: 'gdb_finish',
          description: 'Execute until the current function returns',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              }
            },
            required: ['sessionId']
          }
        },
        {
          name: 'gdb_backtrace',
          description: 'Show call stack',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              full: {
                type: 'boolean',
                description: 'Show variables in each frame (optional)'
              },
              limit: {
                type: 'number',
                description: 'Maximum number of frames to show (optional)'
              }
            },
            required: ['sessionId']
          }
        },
        {
          name: 'gdb_print',
          description: 'Print value of expression',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              expression: {
                type: 'string',
                description: 'Expression to evaluate'
              }
            },
            required: ['sessionId', 'expression']
          }
        },
        {
          name: 'gdb_examine',
          description: 'Examine memory',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              expression: {
                type: 'string',
                description: 'Memory address or expression'
              },
              format: {
                type: 'string',
                description: 'Display format (e.g., "x" for hex, "i" for instruction)'
              },
              count: {
                type: 'number',
                description: 'Number of units to display'
              }
            },
            required: ['sessionId', 'expression']
          }
        },
        {
          name: 'gdb_info_registers',
          description: 'Display registers',
          inputSchema: {
            type: 'object',
            properties: {
              sessionId: {
                type: 'string',
                description: 'GDB session ID'
              },
              register: {
                type: 'string',
                description: 'Specific register to display (optional)'
              }
            },
            required: ['sessionId']
          }
        }
      ],
    }));

    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      // Route the tool call to the appropriate handler based on the tool name
      switch (request.params.name) {
        case 'gdb_start':
          return await this.handleGdbStart(request.params.arguments);
        case 'gdb_load':
          return await this.handleGdbLoad(request.params.arguments);
        case 'gdb_command':
          return await this.handleGdbCommand(request.params.arguments);
        case 'gdb_terminate':
          return await this.handleGdbTerminate(request.params.arguments);
        case 'gdb_list_sessions':
          return await this.handleGdbListSessions();
        case 'gdb_attach':
          return await this.handleGdbAttach(request.params.arguments);
        case 'gdb_load_core':
          return await this.handleGdbLoadCore(request.params.arguments);
        case 'gdb_set_breakpoint':
          return await this.handleGdbSetBreakpoint(request.params.arguments);
        case 'gdb_continue':
          return await this.handleGdbContinue(request.params.arguments);
        case 'gdb_step':
          return await this.handleGdbStep(request.params.arguments);
        case 'gdb_next':
          return await this.handleGdbNext(request.params.arguments);
        case 'gdb_finish':
          return await this.handleGdbFinish(request.params.arguments);
        case 'gdb_backtrace':
          return await this.handleGdbBacktrace(request.params.arguments);
        case 'gdb_print':
          return await this.handleGdbPrint(request.params.arguments);
        case 'gdb_examine':
          return await this.handleGdbExamine(request.params.arguments);
        case 'gdb_info_registers':
          return await this.handleGdbInfoRegisters(request.params.arguments);
        default:
          throw new McpError(
            ErrorCode.MethodNotFound,
            `Unknown tool: ${request.params.name}`
          );
      }
    });
  }

  private async handleGdbStart(args: any) {
    const gdbPath = args.gdbPath || 'gdb';
    const workingDir = args.workingDir || process.cwd();
    
    // Create a unique session ID
    const sessionId = Date.now().toString();
    
    try {
      // Start GDB process with MI mode enabled for machine interface
      const gdbProcess = spawn(gdbPath, ['--interpreter=mi'], {
        cwd: workingDir,
        env: process.env,
        stdio: ['pipe', 'pipe', 'pipe']
      });
      
      // Create readline interface for reading GDB output
      const rl = readline.createInterface({
        input: gdbProcess.stdout,
        terminal: false
      });
      
      // Create new GDB session
      const session: GdbSession = {
        process: gdbProcess,
        rl,
        ready: false,
        id: sessionId,
        workingDir
      };
      
      // Store session in active sessions map
      activeSessions.set(sessionId, session);
      
      // Collect GDB output until ready
      let outputBuffer = '';
      
      // Wait for GDB to be ready (when it outputs the initial prompt)
      await new Promise<void>((resolve, reject) => {
        const timeout = setTimeout(() => {
          reject(new Error('GDB start timeout'));
        }, 10000); // 10 second timeout
        
        rl.on('line', (line) => {
          // Append line to output buffer
          outputBuffer += line + '\n';
          
          // Check if GDB is ready (outputs prompt)
          if (line.includes('(gdb)') || line.includes('^done')) {
            clearTimeout(timeout);
            session.ready = true;
            resolve();
          }
        });
        
        gdbProcess.stderr.on('data', (data) => {
          outputBuffer += `[stderr] ${data.toString()}\n`;
        });
        
        gdbProcess.on('error', (err) => {
          clearTimeout(timeout);
          reject(err);
        });
        
        gdbProcess.on('exit', (code) => {
          clearTimeout(timeout);
          if (!session.ready) {
            reject(new Error(`GDB process exited with code ${code}`));
          }
        });
      });
      
      return {
        content: [
          {
            type: 'text',
            text: `GDB session started with ID: ${sessionId}\n\nOutput:\n${outputBuffer}`
          }
        ]
      };
    } catch (error) {
      // Clean up if an error occurs
      if (activeSessions.has(sessionId)) {
        const session = activeSessions.get(sessionId)!;
        session.process.kill();
        session.rl.close();
        activeSessions.delete(sessionId);
      }
      
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to start GDB: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbLoad(args: any) {
    const { sessionId, program, arguments: programArgs = [] } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // Normalize path if working directory is set
      const normalizedPath = session.workingDir && !path.isAbsolute(program) 
        ? path.resolve(session.workingDir, program)
        : program;
      
      // Update session target
      session.target = normalizedPath;
      
      // Execute file command to load program
      const loadCommand = `file "${normalizedPath}"`;
      const loadOutput = await this.executeGdbCommand(session, loadCommand);
      
      // Set program arguments if provided
      let argsOutput = '';
      if (programArgs.length > 0) {
        const argsCommand = `set args ${programArgs.join(' ')}`;
        argsOutput = await this.executeGdbCommand(session, argsCommand);
      }
      
      return {
        content: [
          {
            type: 'text',
            text: `Program loaded: ${normalizedPath}\n\nOutput:\n${loadOutput}${argsOutput ? '\n' + argsOutput : ''}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to load program: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbCommand(args: any) {
    const { sessionId, command } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      const output = await this.executeGdbCommand(session, command);
      
      return {
        content: [
          {
            type: 'text',
            text: `Command: ${command}\n\nOutput:\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to execute command: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbTerminate(args: any) {
    const { sessionId } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    try {
      await this.terminateGdbSession(sessionId);
      
      return {
        content: [
          {
            type: 'text',
            text: `GDB session terminated: ${sessionId}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to terminate GDB session: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbListSessions() {
    const sessions = Array.from(activeSessions.entries()).map(([id, session]) => ({
      id,
      target: session.target || 'No program loaded',
      workingDir: session.workingDir || process.cwd()
    }));
    
    return {
      content: [
        {
          type: 'text',
          text: `Active GDB Sessions (${sessions.length}):\n\n${JSON.stringify(sessions, null, 2)}`
        }
      ]
    };
  }

  private async handleGdbAttach(args: any) {
    const { sessionId, pid } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      const output = await this.executeGdbCommand(session, `attach ${pid}`);
      
      return {
        content: [
          {
            type: 'text',
            text: `Attached to process ${pid}\n\nOutput:\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to attach to process: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbLoadCore(args: any) {
    const { sessionId, program, corePath } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // First load the program
      const fileOutput = await this.executeGdbCommand(session, `file "${program}"`);
      
      // Then load the core file
      const coreOutput = await this.executeGdbCommand(session, `core-file "${corePath}"`);
      
      // Get backtrace to show initial state
      const backtraceOutput = await this.executeGdbCommand(session, "backtrace");
      
      return {
        content: [
          {
            type: 'text',
            text: `Core file loaded: ${corePath}\n\nOutput:\n${fileOutput}\n${coreOutput}\n\nBacktrace:\n${backtraceOutput}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to load core file: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbSetBreakpoint(args: any) {
    const { sessionId, location, condition } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // Set breakpoint
      let command = `break ${location}`;
      const output = await this.executeGdbCommand(session, command);
      
      // Set condition if provided
      let conditionOutput = '';
      if (condition) {
        // Extract breakpoint number from output (assumes format like "Breakpoint 1 at...")
        const match = output.match(/Breakpoint (\d+)/);
        if (match && match[1]) {
          const bpNum = match[1];
          const conditionCommand = `condition ${bpNum} ${condition}`;
          conditionOutput = await this.executeGdbCommand(session, conditionCommand);
        }
      }
      
      return {
        content: [
          {
            type: 'text',
            text: `Breakpoint set at: ${location}${condition ? ` with condition: ${condition}` : ''}\n\nOutput:\n${output}${conditionOutput ? '\n' + conditionOutput : ''}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to set breakpoint: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbContinue(args: any) {
    const { sessionId } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      const output = await this.executeGdbCommand(session, "continue");
      
      return {
        content: [
          {
            type: 'text',
            text: `Continued execution\n\nOutput:\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to continue execution: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbStep(args: any) {
    const { sessionId, instructions = false } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // Use stepi for instruction-level stepping, otherwise step
      const command = instructions ? "stepi" : "step";
      const output = await this.executeGdbCommand(session, command);
      
      return {
        content: [
          {
            type: 'text',
            text: `Stepped ${instructions ? 'instruction' : 'line'}\n\nOutput:\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to step: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbNext(args: any) {
    const { sessionId, instructions = false } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // Use nexti for instruction-level stepping, otherwise next
      const command = instructions ? "nexti" : "next";
      const output = await this.executeGdbCommand(session, command);
      
      return {
        content: [
          {
            type: 'text',
            text: `Stepped over ${instructions ? 'instruction' : 'function call'}\n\nOutput:\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to step over: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbFinish(args: any) {
    const { sessionId } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      const output = await this.executeGdbCommand(session, "finish");
      
      return {
        content: [
          {
            type: 'text',
            text: `Finished current function\n\nOutput:\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to finish function: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbBacktrace(args: any) {
    const { sessionId, full = false, limit } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // Build backtrace command with options
      let command = full ? "backtrace full" : "backtrace";
      if (typeof limit === 'number') {
        command += ` ${limit}`;
      }
      
      const output = await this.executeGdbCommand(session, command);
      
      return {
        content: [
          {
            type: 'text',
            text: `Backtrace${full ? ' (full)' : ''}${limit ? ` (limit: ${limit})` : ''}:\n\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to get backtrace: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbPrint(args: any) {
    const { sessionId, expression } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      const output = await this.executeGdbCommand(session, `print ${expression}`);
      
      return {
        content: [
          {
            type: 'text',
            text: `Print ${expression}:\n\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to print expression: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbExamine(args: any) {
    const { sessionId, expression, format = 'x', count = 1 } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // Format examine command: x/[count][format] [expression]
      const command = `x/${count}${format} ${expression}`;
      const output = await this.executeGdbCommand(session, command);
      
      return {
        content: [
          {
            type: 'text',
            text: `Examine ${expression} (format: ${format}, count: ${count}):\n\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to examine memory: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  private async handleGdbInfoRegisters(args: any) {
    const { sessionId, register } = args;
    
    if (!activeSessions.has(sessionId)) {
      return {
        content: [
          {
            type: 'text',
            text: `No active GDB session with ID: ${sessionId}`
          }
        ],
        isError: true
      };
    }
    
    const session = activeSessions.get(sessionId)!;
    
    try {
      // Build info registers command, optionally with specific register
      const command = register ? `info registers ${register}` : `info registers`;
      const output = await this.executeGdbCommand(session, command);
      
      return {
        content: [
          {
            type: 'text',
            text: `Register info${register ? ` for ${register}` : ''}:\n\n${output}`
          }
        ]
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      return {
        content: [
          {
            type: 'text',
            text: `Failed to get register info: ${errorMessage}`
          }
        ],
        isError: true
      };
    }
  }

  /**
   * Execute a GDB command and wait for the response
   */
  private executeGdbCommand(session: GdbSession, command: string): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      if (!session.ready) {
        reject(new Error('GDB session is not ready'));
        return;
      }
      
      // Write command to GDB's stdin
      if (session.process.stdin) {
        session.process.stdin.write(command + '\n');
      } else {
        reject(new Error('GDB stdin is not available'));
        return;
      }
      
      let output = '';
      let responseComplete = false;
      
      // Create a one-time event handler for GDB output
      const onLine = (line: string) => {
        output += line + '\n';
        
        // Check if this line indicates the end of the GDB response
        if (line.includes('(gdb)') || line.includes('^done') || line.includes('^error')) {
          responseComplete = true;
          
          // If we've received the complete response, resolve the promise
          if (responseComplete) {
            // Remove the listener to avoid memory leaks
            session.rl.removeListener('line', onLine);
            resolve(output);
          }
        }
      };
      
      // Add the line handler to the readline interface
      session.rl.on('line', onLine);
      
      // Set a timeout to prevent hanging
      const timeout = setTimeout(() => {
        session.rl.removeListener('line', onLine);
        reject(new Error('GDB command timed out'));
      }, 10000); // 10 second timeout
      
      // Handle GDB errors
      const errorHandler = (data: Buffer) => {
        const errorText = data.toString();
        output += `[stderr] ${errorText}\n`;
      };
      
      // Add error handler
      if (session.process.stderr) {
        session.process.stderr.once('data', errorHandler);
      }
      
      // Clean up event handlers when the timeout expires
      timeout.unref();
    });
  }

  /**
   * Terminate a GDB session
   */
  private async terminateGdbSession(sessionId: string): Promise<void> {
    if (!activeSessions.has(sessionId)) {
      throw new Error(`No active GDB session with ID: ${sessionId}`);
    }
    
    const session = activeSessions.get(sessionId)!;
    
    // Send quit command to GDB
    try {
      await this.executeGdbCommand(session, 'quit');
    } catch (error) {
      // Ignore errors from quit command, we'll force kill if needed
    }
    
    // Force kill the process if it's still running
    if (!session.process.killed) {
      session.process.kill();
    }
    
    // Close the readline interface
    session.rl.close();
    
    // Remove from active sessions
    activeSessions.delete(sessionId);
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('GDB MCP server running on stdio');
  }
}

// Create and run the server
const server = new GdbServer();
server.run().catch((error) => {
  console.error('Failed to start GDB MCP server:', error);
  process.exit(1);
});

```