mlgym-deploy 3.3.1 → 3.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +27 -18
  2. package/package.json +1 -4
package/index.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  } from '@modelcontextprotocol/sdk/types.js';
9
9
  import axios from 'axios';
10
10
  import fs from 'fs/promises';
11
+ import fsSync from 'fs';
11
12
  import path from 'path';
12
13
  import os from 'os';
13
14
  import { exec } from 'child_process';
@@ -17,7 +18,7 @@ import crypto from 'crypto';
17
18
  const execAsync = promisify(exec);
18
19
 
19
20
  // Current version of this MCP server - INCREMENT FOR WORKFLOW FIXES
20
- const CURRENT_VERSION = '3.3.1'; // Updated help with plain English examples showing what users say vs tool calls
21
+ const CURRENT_VERSION = '3.3.5'; // Fixed mlgym_deploy_logs project lookup (data.projects data) by importing fsSync for synchronous file operations
21
22
  const PACKAGE_NAME = 'mlgym-deploy';
22
23
 
23
24
  // Debug logging configuration - ENABLED BY DEFAULT
@@ -1302,9 +1303,9 @@ async function initProject(args) {
1302
1303
 
1303
1304
  for (const filename of composeFiles) {
1304
1305
  const composePath = path.join(local_path, filename);
1305
- if (fs.existsSync(composePath)) {
1306
+ if (fsSync.existsSync(composePath)) {
1306
1307
  try {
1307
- composeContent = fs.readFileSync(composePath, 'utf8');
1308
+ composeContent = fsSync.readFileSync(composePath, 'utf8');
1308
1309
  log.info(`MCP >>> [initProject] Read ${filename}: ${composeContent.length} bytes`);
1309
1310
  break;
1310
1311
  } catch (err) {
@@ -1363,6 +1364,10 @@ async function initProject(args) {
1363
1364
  console.error('⚠️ Warning: Failed to add administrator as member:', memberErr.message);
1364
1365
  }
1365
1366
 
1367
+ // Wait for GitLab project to be fully created and accessible
1368
+ console.error('Waiting for GitLab project creation to complete (20 seconds)...');
1369
+ await new Promise(resolve => setTimeout(resolve, 20000));
1370
+
1366
1371
  // Initialize local git repository if needed
1367
1372
  const absolutePath = path.resolve(local_path);
1368
1373
  try {
@@ -1401,9 +1406,9 @@ async function initProject(args) {
1401
1406
  console.error('Note: ssh-agent not available, relying on SSH config');
1402
1407
  }
1403
1408
 
1404
- // Wait for GitLab SSH key propagation (10 seconds)
1405
- console.error('Waiting for GitLab SSH key propagation (10 seconds)...');
1406
- await new Promise(resolve => setTimeout(resolve, 10000));
1409
+ // Wait for GitLab SSH key propagation (20 seconds)
1410
+ console.error('Waiting for GitLab SSH key propagation (30 seconds)...');
1411
+ await new Promise(resolve => setTimeout(resolve, 30000));
1407
1412
 
1408
1413
  // Test SSH connectivity
1409
1414
  console.error('Testing SSH connection to GitLab...');
@@ -1472,7 +1477,11 @@ async function initProject(args) {
1472
1477
  log.debug('MCP >>> [initProject] Git remote URL:', gitUrl);
1473
1478
  gitSteps.push('Pushing to GitLab to trigger deployment');
1474
1479
  console.error('Executing: git push -u mlgym main');
1475
- await execAsync('git push -u mlgym main', { cwd: absolutePath });
1480
+ const authInfo = await loadAuth();
1481
+ const sanitizedEmail = authInfo.email.replace('@', '_at_').replace(/[^a-zA-Z0-9_-]/g, '_');
1482
+ const sshKeyPath = path.join(os.homedir(), '.ssh', `mlgym_${sanitizedEmail}`);
1483
+ const gitSshCmd = `ssh -i "${sshKeyPath}"`;
1484
+ await execAsync('git push -u mlgym main', { cwd: absolutePath, env: { ...process.env, GIT_SSH_COMMAND: gitSshCmd } });
1476
1485
  gitSteps.push('✅ Successfully pushed to GitLab');
1477
1486
  pushSucceeded = true;
1478
1487
  log.success('MCP >>> [initProject] ✅ Git push completed successfully!');
@@ -1496,7 +1505,7 @@ async function initProject(args) {
1496
1505
  for (let i = 0; i < 12; i++) {
1497
1506
  await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
1498
1507
 
1499
- const statusResult = await apiRequest('GET', `/api/v1/projects/${project.id}/deployment`, null, true);
1508
+ const statusResult = await apiRequest('GET', `/api/v1/projects/${project.id}/deployments`, null, true);
1500
1509
  if (statusResult.success && statusResult.data) {
1501
1510
  const status = statusResult.data.status;
1502
1511
  console.error(`Deployment status: ${status}`);
@@ -2014,10 +2023,10 @@ async function deployProject(args) {
2014
2023
  if (strategy.type === 'docker-compose') {
2015
2024
  const composePath = path.join(local_path, 'docker-compose.yml');
2016
2025
  const composePathYAML = path.join(local_path, 'docker-compose.yaml');
2017
- const actualPath = fs.existsSync(composePath) ? composePath : composePathYAML;
2026
+ const actualPath = fsSync.existsSync(composePath) ? composePath : composePathYAML;
2018
2027
 
2019
- if (fs.existsSync(actualPath)) {
2020
- const content = fs.readFileSync(actualPath, 'utf8');
2028
+ if (fsSync.existsSync(actualPath)) {
2029
+ const content = fsSync.readFileSync(actualPath, 'utf8');
2021
2030
  const validation = validateAndFixDockerCompose(content);
2022
2031
 
2023
2032
  if (!validation.isValid) {
@@ -2028,11 +2037,11 @@ async function deployProject(args) {
2028
2037
 
2029
2038
  // Auto-fix the issues
2030
2039
  log.info('MCP >>> Auto-fixing docker-compose.yml port mappings...');
2031
- fs.writeFileSync(actualPath, validation.fixedContent);
2040
+ fsSync.writeFileSync(actualPath, validation.fixedContent);
2032
2041
 
2033
2042
  // Create backup
2034
2043
  const backupPath = actualPath + '.backup';
2035
- fs.writeFileSync(backupPath, content);
2044
+ fsSync.writeFileSync(backupPath, content);
2036
2045
  log.info(`MCP >>> Created backup at ${backupPath}`);
2037
2046
 
2038
2047
  log.success('MCP >>> Fixed docker-compose.yml:');
@@ -2044,8 +2053,8 @@ async function deployProject(args) {
2044
2053
  } else if (strategy.type === 'dockerfile') {
2045
2054
  const dockerfilePath = path.join(local_path, 'Dockerfile');
2046
2055
 
2047
- if (fs.existsSync(dockerfilePath)) {
2048
- const content = fs.readFileSync(dockerfilePath, 'utf8');
2056
+ if (fsSync.existsSync(dockerfilePath)) {
2057
+ const content = fsSync.readFileSync(dockerfilePath, 'utf8');
2049
2058
  const validation = validateDockerfile(content);
2050
2059
 
2051
2060
  if (!validation.isValid) {
@@ -2073,8 +2082,8 @@ async function deployProject(args) {
2073
2082
  const fixedContent = lines.join('\n');
2074
2083
 
2075
2084
  // Create backup
2076
- fs.writeFileSync(dockerfilePath + '.backup', content);
2077
- fs.writeFileSync(dockerfilePath, fixedContent);
2085
+ fsSync.writeFileSync(dockerfilePath + '.backup', content);
2086
+ fsSync.writeFileSync(dockerfilePath, fixedContent);
2078
2087
 
2079
2088
  log.success('MCP >>> Fixed Dockerfile: added EXPOSE 80');
2080
2089
  }
@@ -2230,7 +2239,7 @@ async function getDeploymentLogs(args) {
2230
2239
  throw new Error(`Failed to get projects: ${projectsResult.error}`);
2231
2240
  }
2232
2241
 
2233
- const project = projectsResult.data.projects?.find(p => p.name === projectName);
2242
+ const project = projectsResult.data?.find(p => p.name === projectName);
2234
2243
  if (!project) {
2235
2244
  throw new Error(`Project "${projectName}" not found in your account`);
2236
2245
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlgym-deploy",
3
- "version": "3.3.1",
3
+ "version": "3.3.5",
4
4
  "description": "MCP server for MLGym - Complete deployment management: deploy, configure, monitor, and rollback applications",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -83,6 +83,3 @@
83
83
  ]
84
84
  }
85
85
  }
86
-
87
-
88
-