#
tokens: 2876/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

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

# Files

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

```
 1 | # Dependencies
 2 | node_modules/
 3 | 
 4 | # Build output
 5 | build/
 6 | dist/
 7 | 
 8 | # Environment variables
 9 | .env
10 | .env.local
11 | .env.*.local
12 | 
13 | # IDE files
14 | .vscode/
15 | .idea/
16 | *.iml
17 | 
18 | # Logs
19 | *.log
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 | 
24 | # System files
25 | .DS_Store
26 | Thumbs.db
27 | 
```

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

```markdown
 1 | # WinTerm MCP
 2 | 
 3 | 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.
 4 | 
 5 | ## Features
 6 | 
 7 | - **Write to Terminal**: Execute commands or write text to the Windows terminal
 8 | - **Read Terminal Output**: Retrieve output from previously executed commands
 9 | - **Send Control Characters**: Send control signals (e.g., Ctrl+C) to the terminal
10 | - **Windows-Native**: Built specifically for Windows command line interaction
11 | 
12 | ## Installation
13 | 
14 | 1. **Clone the Repository**:
15 |    ```bash
16 |    git clone https://github.com/capecoma/winterm-mcp.git
17 |    cd winterm-mcp
18 |    ```
19 | 
20 | 2. **Install Dependencies**:
21 |    ```bash
22 |    npm install
23 |    ```
24 | 
25 | 3. **Build the Project**:
26 |    ```bash
27 |    npm run build
28 |    ```
29 | 
30 | 4. **Configure Claude Desktop**:
31 | 
32 | Add the server config to `%APPDATA%/Claude/claude_desktop_config.json`:
33 | 
34 | ```json
35 | {
36 |   "mcpServers": {
37 |     "github.com/capecoma/winterm-mcp": {
38 |       "command": "node",
39 |       "args": ["path/to/build/index.js"],
40 |       "disabled": false,
41 |       "autoApprove": []
42 |     }
43 |   }
44 | }
45 | ```
46 | 
47 | Note: Replace "path/to/build/index.js" with the actual path to your built index.js file.
48 | 
49 | ## Available Tools
50 | 
51 | ### write_to_terminal
52 | Writes text or commands to the terminal.
53 | ```json
54 | {
55 |   "command": "echo Hello, World!"
56 | }
57 | ```
58 | 
59 | ### read_terminal_output
60 | Reads the specified number of lines from terminal output.
61 | ```json
62 | {
63 |   "linesOfOutput": 5
64 | }
65 | ```
66 | 
67 | ### send_control_character
68 | Sends a control character to the terminal (e.g., Ctrl+C).
69 | ```json
70 | {
71 |   "letter": "C"
72 | }
73 | ```
74 | 
75 | ## Development
76 | 
77 | For development with auto-rebuild:
78 | ```bash
79 | npm run dev
80 | ```
81 | 
82 | ## License
83 | 
84 | MIT License - see [LICENSE](LICENSE) file.
85 | 
```

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

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "ES2020",
 5 |     "moduleResolution": "node",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

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

```json
 1 | {
 2 |   "name": "winterm-mcp",
 3 |   "version": "1.0.0",
 4 |   "description": "Windows Terminal MCP Server - A Model Context Protocol server for Windows terminal interaction",
 5 |   "type": "module",
 6 |   "main": "build/index.js",
 7 |   "scripts": {
 8 |     "build": "npx tsc",
 9 |     "start": "node build/index.js",
10 |     "dev": "npx tsc -w"
11 |   },
12 |   "repository": {
13 |     "type": "git",
14 |     "url": "git+https://github.com/capecoma/winterm-mcp.git"
15 |   },
16 |   "keywords": [
17 |     "mcp",
18 |     "terminal",
19 |     "windows",
20 |     "claude",
21 |     "automation"
22 |   ],
23 |   "author": "capecoma",
24 |   "license": "MIT",
25 |   "bugs": {
26 |     "url": "https://github.com/capecoma/winterm-mcp/issues"
27 |   },
28 |   "homepage": "https://github.com/capecoma/winterm-mcp#readme",
29 |   "dependencies": {
30 |     "@modelcontextprotocol/sdk": "latest",
31 |     "@types/node": "^20.0.0",
32 |     "typescript": "^5.0.0"
33 |   }
34 | }
35 | 
```

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

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import {
  5 |   CallToolRequestSchema,
  6 |   ErrorCode,
  7 |   ListToolsRequestSchema,
  8 |   McpError,
  9 | } from '@modelcontextprotocol/sdk/types.js';
 10 | import { spawn, exec } from 'child_process';
 11 | import * as os from 'os';
 12 | 
 13 | class WindowsTerminalServer {
 14 |   private server: Server;
 15 |   private outputBuffer: string[] = [];
 16 | 
 17 |   constructor() {
 18 |     this.server = new Server(
 19 |       {
 20 |         name: 'windows-terminal-mcp',
 21 |         version: '1.0.0',
 22 |       },
 23 |       {
 24 |         capabilities: {
 25 |           tools: {},
 26 |         },
 27 |       }
 28 |     );
 29 | 
 30 |     this.setupToolHandlers();
 31 |     
 32 |     this.server.onerror = (error) => console.error('[MCP Error]', error);
 33 |     process.on('SIGINT', async () => {
 34 |       await this.cleanup();
 35 |       process.exit(0);
 36 |     });
 37 |   }
 38 | 
 39 |   private setupToolHandlers() {
 40 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
 41 |       tools: [
 42 |         {
 43 |           name: 'write_to_terminal',
 44 |           description: 'Write text or commands to the terminal',
 45 |           inputSchema: {
 46 |             type: 'object',
 47 |             properties: {
 48 |               command: {
 49 |                 type: 'string',
 50 |                 description: 'The text or command to write to the terminal',
 51 |               },
 52 |             },
 53 |             required: ['command'],
 54 |           },
 55 |         },
 56 |         {
 57 |           name: 'read_terminal_output',
 58 |           description: 'Read the output from the terminal',
 59 |           inputSchema: {
 60 |             type: 'object',
 61 |             properties: {
 62 |               linesOfOutput: {
 63 |                 type: 'number',
 64 |                 description: 'Number of lines of output to read',
 65 |               },
 66 |             },
 67 |             required: ['linesOfOutput'],
 68 |           },
 69 |         },
 70 |         {
 71 |           name: 'send_control_character',
 72 |           description: 'Send a control character to the terminal',
 73 |           inputSchema: {
 74 |             type: 'object',
 75 |             properties: {
 76 |               letter: {
 77 |                 type: 'string',
 78 |                 description: 'The letter corresponding to the control character (e.g., "C" for Ctrl+C)',
 79 |               },
 80 |             },
 81 |             required: ['letter'],
 82 |           },
 83 |         },
 84 |       ],
 85 |     }));
 86 | 
 87 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
 88 |       switch (request.params.name) {
 89 |         case 'write_to_terminal': {
 90 |           const { command } = request.params.arguments as { command: string };
 91 |           return new Promise((resolve, reject) => {
 92 |             const shell = os.platform() === 'win32' ? 'cmd.exe' : 'bash';
 93 |             const shellArgs = os.platform() === 'win32' ? ['/c', command] : ['-c', command];
 94 |             
 95 |             const proc = spawn(shell, shellArgs);
 96 |             let output = '';
 97 | 
 98 |             proc.stdout.on('data', (data) => {
 99 |               output += data.toString();
100 |               this.outputBuffer.push(...data.toString().split('\n'));
101 |             });
102 | 
103 |             proc.stderr.on('data', (data) => {
104 |               output += data.toString();
105 |               this.outputBuffer.push(...data.toString().split('\n'));
106 |             });
107 | 
108 |             proc.on('close', (code) => {
109 |               resolve({
110 |                 content: [
111 |                   {
112 |                     type: 'text',
113 |                     text: `Command executed with exit code ${code}. Output:\n${output}`,
114 |                   },
115 |                 ],
116 |               });
117 |             });
118 | 
119 |             proc.on('error', (err) => {
120 |               reject(new McpError(ErrorCode.InternalError, err.message));
121 |             });
122 |           });
123 |         }
124 | 
125 |         case 'read_terminal_output': {
126 |           const { linesOfOutput } = request.params.arguments as { linesOfOutput: number };
127 |           const output = this.outputBuffer.slice(-linesOfOutput).join('\n');
128 |           return {
129 |             content: [
130 |               {
131 |                 type: 'text',
132 |                 text: output,
133 |               },
134 |             ],
135 |           };
136 |         }
137 | 
138 |         case 'send_control_character': {
139 |           const { letter } = request.params.arguments as { letter: string };
140 |           // On Windows, we'll use taskkill to simulate Ctrl+C
141 |           if (letter.toUpperCase() === 'C' && os.platform() === 'win32') {
142 |             exec('taskkill /im node.exe /f');
143 |           }
144 |           return {
145 |             content: [
146 |               {
147 |                 type: 'text',
148 |                 text: `Sent Ctrl+${letter.toUpperCase()} signal`,
149 |               },
150 |             ],
151 |           };
152 |         }
153 | 
154 |         default:
155 |           throw new McpError(
156 |             ErrorCode.MethodNotFound,
157 |             `Unknown tool: ${request.params.name}`
158 |           );
159 |       }
160 |     });
161 |   }
162 | 
163 |   private async cleanup() {
164 |     await this.server.close();
165 |   }
166 | 
167 |   async run() {
168 |     const transport = new StdioServerTransport();
169 |     await this.server.connect(transport);
170 |     console.error('Windows Terminal MCP server running on stdio');
171 |   }
172 | }
173 | 
174 | const server = new WindowsTerminalServer();
175 | server.run().catch(console.error);
176 | 
```