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

```
├── .gitignore
├── LICENSE
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Dependencies
node_modules/

# Build output
build/
dist/

# Environment variables
.env
.env.local
.env.*.local

# IDE files
.vscode/
.idea/
*.iml

# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# System files
.DS_Store
Thumbs.db

```

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

```markdown
# WinTerm MCP

A Model Context Protocol server that provides programmatic access to the Windows terminal. This server enables AI models to interact with the Windows command line interface through a set of standardized tools.

## Features

- **Write to Terminal**: Execute commands or write text to the Windows terminal
- **Read Terminal Output**: Retrieve output from previously executed commands
- **Send Control Characters**: Send control signals (e.g., Ctrl+C) to the terminal
- **Windows-Native**: Built specifically for Windows command line interaction

## Installation

1. **Clone the Repository**:
   ```bash
   git clone https://github.com/capecoma/winterm-mcp.git
   cd winterm-mcp
   ```

2. **Install Dependencies**:
   ```bash
   npm install
   ```

3. **Build the Project**:
   ```bash
   npm run build
   ```

4. **Configure Claude Desktop**:

Add the server config to `%APPDATA%/Claude/claude_desktop_config.json`:

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

Note: Replace "path/to/build/index.js" with the actual path to your built index.js file.

## Available Tools

### write_to_terminal
Writes text or commands to the terminal.
```json
{
  "command": "echo Hello, World!"
}
```

### read_terminal_output
Reads the specified number of lines from terminal output.
```json
{
  "linesOfOutput": 5
}
```

### send_control_character
Sends a control character to the terminal (e.g., Ctrl+C).
```json
{
  "letter": "C"
}
```

## Development

For development with auto-rebuild:
```bash
npm run dev
```

## License

MIT License - see [LICENSE](LICENSE) file.

```

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

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ES2020",
    "moduleResolution": "node",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

```

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

```json
{
  "name": "winterm-mcp",
  "version": "1.0.0",
  "description": "Windows Terminal MCP Server - A Model Context Protocol server for Windows terminal interaction",
  "type": "module",
  "main": "build/index.js",
  "scripts": {
    "build": "npx tsc",
    "start": "node build/index.js",
    "dev": "npx tsc -w"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/capecoma/winterm-mcp.git"
  },
  "keywords": [
    "mcp",
    "terminal",
    "windows",
    "claude",
    "automation"
  ],
  "author": "capecoma",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/capecoma/winterm-mcp/issues"
  },
  "homepage": "https://github.com/capecoma/winterm-mcp#readme",
  "dependencies": {
    "@modelcontextprotocol/sdk": "latest",
    "@types/node": "^20.0.0",
    "typescript": "^5.0.0"
  }
}

```

--------------------------------------------------------------------------------
/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, exec } from 'child_process';
import * as os from 'os';

class WindowsTerminalServer {
  private server: Server;
  private outputBuffer: string[] = [];

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

    this.setupToolHandlers();
    
    this.server.onerror = (error) => console.error('[MCP Error]', error);
    process.on('SIGINT', async () => {
      await this.cleanup();
      process.exit(0);
    });
  }

  private setupToolHandlers() {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'write_to_terminal',
          description: 'Write text or commands to the terminal',
          inputSchema: {
            type: 'object',
            properties: {
              command: {
                type: 'string',
                description: 'The text or command to write to the terminal',
              },
            },
            required: ['command'],
          },
        },
        {
          name: 'read_terminal_output',
          description: 'Read the output from the terminal',
          inputSchema: {
            type: 'object',
            properties: {
              linesOfOutput: {
                type: 'number',
                description: 'Number of lines of output to read',
              },
            },
            required: ['linesOfOutput'],
          },
        },
        {
          name: 'send_control_character',
          description: 'Send a control character to the terminal',
          inputSchema: {
            type: 'object',
            properties: {
              letter: {
                type: 'string',
                description: 'The letter corresponding to the control character (e.g., "C" for Ctrl+C)',
              },
            },
            required: ['letter'],
          },
        },
      ],
    }));

    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      switch (request.params.name) {
        case 'write_to_terminal': {
          const { command } = request.params.arguments as { command: string };
          return new Promise((resolve, reject) => {
            const shell = os.platform() === 'win32' ? 'cmd.exe' : 'bash';
            const shellArgs = os.platform() === 'win32' ? ['/c', command] : ['-c', command];
            
            const proc = spawn(shell, shellArgs);
            let output = '';

            proc.stdout.on('data', (data) => {
              output += data.toString();
              this.outputBuffer.push(...data.toString().split('\n'));
            });

            proc.stderr.on('data', (data) => {
              output += data.toString();
              this.outputBuffer.push(...data.toString().split('\n'));
            });

            proc.on('close', (code) => {
              resolve({
                content: [
                  {
                    type: 'text',
                    text: `Command executed with exit code ${code}. Output:\n${output}`,
                  },
                ],
              });
            });

            proc.on('error', (err) => {
              reject(new McpError(ErrorCode.InternalError, err.message));
            });
          });
        }

        case 'read_terminal_output': {
          const { linesOfOutput } = request.params.arguments as { linesOfOutput: number };
          const output = this.outputBuffer.slice(-linesOfOutput).join('\n');
          return {
            content: [
              {
                type: 'text',
                text: output,
              },
            ],
          };
        }

        case 'send_control_character': {
          const { letter } = request.params.arguments as { letter: string };
          // On Windows, we'll use taskkill to simulate Ctrl+C
          if (letter.toUpperCase() === 'C' && os.platform() === 'win32') {
            exec('taskkill /im node.exe /f');
          }
          return {
            content: [
              {
                type: 'text',
                text: `Sent Ctrl+${letter.toUpperCase()} signal`,
              },
            ],
          };
        }

        default:
          throw new McpError(
            ErrorCode.MethodNotFound,
            `Unknown tool: ${request.params.name}`
          );
      }
    });
  }

  private async cleanup() {
    await this.server.close();
  }

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

const server = new WindowsTerminalServer();
server.run().catch(console.error);

```