# 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);
```