otak-mcp-shell
Version:
Windows PowerShell MCP server with system directory protection and SSE/HTTP streaming support
171 lines (145 loc) • 5.21 kB
JavaScript
const path = require('path');
const fs = require('fs');
const os = require('os');
// Windows プラットフォームチェック
if (os.platform() !== 'win32') {
console.error('❌ Windows service installation is only supported on Windows platform.');
console.error('Current platform:', os.platform());
process.exit(1);
}
// node-windowsの動的読み込み
let Service;
try {
Service = require('node-windows').Service;
} catch (error) {
console.error('❌ node-windows module is not available.');
console.error('Please install it manually: npm install -g node-windows');
console.error('Original error:', error.message);
process.exit(1);
}
// 設定読み込み
function loadConfig() {
const args = process.argv.slice(2);
let config = {
allowedDirectory: path.join(os.homedir(), 'Desktop', 'Otak'),
serviceName: 'OtakMCPShell',
displayName: 'Otak MCP Shell Server',
description: 'Windows PowerShell MCP server with system directory protection',
serverType: 'stdio' // stdio, http, mcp
};
// 環境変数から設定を読み込み
if (process.env.SERVICE_TYPE) config.serverType = process.env.SERVICE_TYPE;
if (process.env.ALLOWED_DIR) config.allowedDirectory = process.env.ALLOWED_DIR;
if (process.env.SERVICE_NAME) config.serviceName = process.env.SERVICE_NAME;
if (process.env.DISPLAY_NAME) config.displayName = process.env.DISPLAY_NAME;
// コマンドライン引数を解析
for (let i = 0; i < args.length; i += 2) {
const key = args[i];
const value = args[i + 1];
if (!value) continue;
switch (key) {
case '--type':
case '-t':
config.serverType = value;
break;
case '--dir':
case '-d':
config.allowedDirectory = value;
break;
case '--name':
case '-n':
config.serviceName = value;
break;
case '--display':
config.displayName = value;
break;
}
}
// サーバータイプに応じてサービス名を自動調整
if (config.serverType !== 'stdio' && !process.env.SERVICE_NAME && !args.includes('--name') && !args.includes('-n')) {
const typeMap = { http: 'HTTP', mcp: 'MCP' };
config.serviceName = `OtakMCPShell${typeMap[config.serverType] || ''}`;
config.displayName = `Otak MCP Shell ${typeMap[config.serverType] || ''} Server`;
}
return config;
}
// サービスのスクリプトファイルを選択
function getServiceScript(serverType) {
const scripts = {
stdio: path.join(__dirname, '..', 'dist', 'index.js'),
http: path.join(__dirname, '..', 'dist', 'http-server.js'),
mcp: path.join(__dirname, '..', 'dist', 'mcp-http-server.js')
};
if (!scripts[serverType]) {
console.error(`Unknown server type: ${serverType}`);
console.error('Available types: stdio, http, mcp');
process.exit(1);
}
return scripts[serverType];
}
function main() {
const config = loadConfig();
console.log('Installing Otak MCP Shell Windows Service...');
console.log('Configuration:', JSON.stringify(config, null, 2));
const serviceScript = getServiceScript(config.serverType);
// スクリプトファイルの存在確認
if (!fs.existsSync(serviceScript)) {
console.error(`Service script not found: ${serviceScript}`);
console.error('Please run "npm run build" first.');
process.exit(1);
}
// サービス作成
const svc = new Service({
name: config.serviceName,
description: config.description,
script: serviceScript,
env: config.serverType !== 'stdio' ? [
{
name: 'NODE_ENV',
value: 'production'
},
{
name: 'ALLOWED_DIRECTORY',
value: config.allowedDirectory
}
] : undefined,
scriptOptions: config.serverType === 'stdio' ?
[JSON.stringify({ allowedDirectory: config.allowedDirectory })] :
undefined,
nodeOptions: [
'--max-old-space-size=4096'
]
});
// サービスイベントハンドラー
svc.on('install', () => {
console.log(`✅ Service "${config.displayName}" installed successfully!`);
console.log(` Service Name: ${config.serviceName}`);
console.log(` Script: ${serviceScript}`);
console.log(` Allowed Directory: ${config.allowedDirectory}`);
console.log('');
console.log('Service management commands:');
console.log(` Start: net start ${config.serviceName}`);
console.log(` Stop: net stop ${config.serviceName}`);
console.log(` Remove: node scripts/uninstall-service.js`);
// サービスを開始
svc.start();
});
svc.on('start', () => {
console.log(`🚀 Service "${config.displayName}" started successfully!`);
});
svc.on('alreadyinstalled', () => {
console.log(`⚠️ Service "${config.displayName}" is already installed.`);
console.log('To reinstall, first run: node scripts/uninstall-service.js');
});
svc.on('error', (err) => {
console.error('❌ Service installation failed:', err);
process.exit(1);
});
// サービスインストール実行
svc.install();
}
if (require.main === module) {
main();
}
module.exports = { loadConfig, getServiceScript };