@rishibhushan/jenkins-mcp-server 1.0.7 → 1.1.1

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.
package/README.md CHANGED
@@ -7,6 +7,28 @@ Designed to work seamlessly with automation clients such as:
7
7
  - 🖥️ **Claude Desktop** - AI-powered Jenkins automation
8
8
  - 🔌 **Any MCP-compatible client** - Universal compatibility
9
9
 
10
+ ## ✨ What's New in v1.1.0
11
+
12
+ ### 🚀 Performance Enhancements
13
+ - ⚡ **10x faster** - Client connection caching for repeated operations
14
+ - 📊 **Smart caching** - Job list caching with 30-60s TTL (5-10x improvement)
15
+ - 🎯 **Optimized queries** - Reduced API calls by 33-83%
16
+
17
+ ### 🛡️ Reliability Improvements
18
+ - ✅ **86% validation coverage** - Input validation on 18/21 tools
19
+ - ⏱️ **Configurable timeouts** - No more hanging API calls
20
+ - 💬 **Better error messages** - Clear troubleshooting steps
21
+ - 🏥 **Health check tool** - Instant diagnostics
22
+
23
+ ### 🎛️ Advanced Features
24
+ - 📦 **Batch operations** - Trigger up to 20 builds at once
25
+ - 📈 **Metrics & telemetry** - Track tool usage and performance
26
+ - 🗂️ **Cache management** - Monitor and control caching
27
+ - 📊 **Console improvements** - Line-based truncation with tail mode
28
+ - 🎨 **Structured logging** - Better debugging with JSON logs
29
+
30
+ ---
31
+
10
32
  ## ✨ About codebase
11
33
 
12
34
  - ✅ **Codebase** - cleaner, more maintainable
@@ -15,6 +37,8 @@ Designed to work seamlessly with automation clients such as:
15
37
  - ✅ **Cross-platform** - Seamless support for Windows, macOS, and Linux
16
38
  - ✅ **Logging** - Professional logging with `--verbose` flag
17
39
  - ✅ **Dependency management** - Automatic detection and installation
40
+ - ✅ **Performance** - 10x faster with intelligent caching and optimization
41
+ - ✅ **Reliability** - Comprehensive input validation and error handling
18
42
 
19
43
  ---
20
44
 
@@ -26,25 +50,26 @@ This project includes:
26
50
  - 🔄 Automatic virtual environment creation + dependency installation
27
51
  - 🌐 Corporate proxy/certificate auto-detection support
28
52
  - 🪟 Windows, macOS, and Linux support
29
- - 🛠️ **20 Jenkins management tools**
53
+ - 🛠️ **26 Jenkins management tools** (upgraded from 20!)
30
54
 
31
55
  ### 🧩 Build Operations
32
56
  | Tool Name | Description | Required Fields | Optional Fields |
33
57
  |---|---|---|---|
34
58
  | `trigger-build` | Trigger a Jenkins job build with optional parameters | `job_name` | `parameters` |
35
59
  | `stop-build` | Stop a running Jenkins build | `job_name`, `build_number` | *(none)* |
60
+ | `trigger-multiple-builds` | **NEW!** Trigger builds for multiple jobs at once | `job_names` | `parameters`, `wait_for_start` |
36
61
 
37
62
  ### 📊 Job Information
38
63
  | Tool Name | Description | Required Fields | Optional Fields |
39
64
  |---|---|---|---|
40
- | `list-jobs` | List all Jenkins jobs with optional filtering | *(none)* | `filter` |
41
- | `get-job-details` | Get detailed information about a Jenkins job | `job_name` | *(none)* |
65
+ | `list-jobs` | List all Jenkins jobs with optional filtering **and caching** | *(none)* | `filter`, `use_cache` |
66
+ | `get-job-details` | Get detailed information about a Jenkins job | `job_name` | `max_recent_builds` |
42
67
 
43
68
  ### 🛠️ Build Information
44
69
  | Tool Name | Description | Required Fields | Optional Fields |
45
70
  |---|---|---|---|
46
71
  | `get-build-info` | Get information about a specific build | `job_name`, `build_number` | *(none)* |
47
- | `get-build-console` | Get console output from a build | `job_name`, `build_number` | *(none)* |
72
+ | `get-build-console` | Get console output with **smart truncation** | `job_name`, `build_number` | `max_lines`, `tail_only` |
48
73
  | `get-last-build-number` | Get the last build number for a job | `job_name` | *(none)* |
49
74
  | `get-last-build-timestamp` | Get the timestamp of the last build | `job_name` | *(none)* |
50
75
 
@@ -71,6 +96,17 @@ This project includes:
71
96
  | `get-queue-info` | Get Jenkins build queue info | *(none)* | *(none)* |
72
97
  | `list-nodes` | List all Jenkins nodes | *(none)* | *(none)* |
73
98
  | `get-node-info` | Get information about a Jenkins node | `node_name` | *(none)* |
99
+ | `health-check` | **NEW!** Run diagnostics on Jenkins connection | *(none)* | *(none)* |
100
+
101
+ ### 📊 Monitoring & Management
102
+ | Tool Name | Description | Required Fields | Optional Fields |
103
+ |---|---|---|---|
104
+ | `get-cache-stats` | **NEW!** Get cache statistics and information | *(none)* | *(none)* |
105
+ | `clear-cache` | **NEW!** Clear all cached data | *(none)* | *(none)* |
106
+ | `get-metrics` | **NEW!** Get usage metrics and performance stats | *(none)* | `tool_name` |
107
+ | `configure-webhook` | **NEW!** Configure webhook notifications | `job_name`, `webhook_url`, `events` | *(none)* |
108
+
109
+ For detailed technical documentation, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
74
110
 
75
111
  ---
76
112
 
@@ -162,12 +198,7 @@ Add to your VS Code `settings.json`:
162
198
 
163
199
  ### Option 2: Environment File (.env)
164
200
 
165
- Rename `.env.template` to `.env`
166
- ```bash
167
- cp .env.template .env
168
- ```
169
-
170
- In the `.env` file in your project directory:
201
+ Create a file `.env` in your local:
171
202
 
172
203
  ```bash
173
204
  JENKINS_URL=http://jenkins.example.com:8080
@@ -215,7 +246,11 @@ Settings are loaded in this order (later overrides earlier):
215
246
 
216
247
  ### Option 1: Using npx (No Installation Required)
217
248
  ```bash
249
+ # if .env file is located in the current directory
218
250
  npx @rishibhushan/jenkins-mcp-server --env-file .env
251
+
252
+ # OR if .env file is located in /path/to/.env
253
+ npx @rishibhushan/jenkins-mcp-server --env-file /path/to/.env
219
254
  ```
220
255
 
221
256
  ### Option 2: Global Installation
@@ -713,6 +748,149 @@ pip install -r requirements.txt
713
748
  }
714
749
  }
715
750
  ```
751
+ ---
752
+
753
+ ### Solution 4: Use Global Installation with Direct Python Path
754
+
755
+ If you prefer to use global installation but still face VPN/timeout issues, you can combine both approaches.
756
+
757
+ #### Step 1: Install Globally
758
+
759
+ **Disconnect from VPN first** (to avoid proxy issues during installation):
760
+ ```bash
761
+ # Install globally
762
+ npm install -g @rishibhushan/jenkins-mcp-server
763
+
764
+ # Verify installation
765
+ jenkins-mcp-server --version
766
+ ```
767
+
768
+ #### Step 2: Locate Global Installation Directory
769
+
770
+ **For macOS/Linux:**
771
+ ```bash
772
+ # Find the global npm directory
773
+ npm root -g
774
+
775
+ # This typically returns something like:
776
+ # /usr/local/lib/node_modules
777
+ # or
778
+ # /Users/username/.npm-global/lib/node_modules
779
+
780
+ # Your package will be at:
781
+ # <npm-root>/@rishibhushan/jenkins-mcp-server
782
+ ```
783
+
784
+ **For Windows (PowerShell):**
785
+ ```powershell
786
+ # Find the global npm directory
787
+ npm root -g
788
+
789
+ # This typically returns something like:
790
+ # C:\Users\username\AppData\Roaming\npm\node_modules
791
+
792
+ # Your package will be at:
793
+ # <npm-root>\@rishibhushan\jenkins-mcp-server
794
+ ```
795
+
796
+ #### Step 3: Find the Python Path
797
+
798
+ Once you know the installation directory:
799
+
800
+ **macOS/Linux:**
801
+ ```bash
802
+ # If npm root -g shows: /usr/local/lib/node_modules
803
+ # Your Python path will be:
804
+ /usr/local/lib/node_modules/@rishibhushan/jenkins-mcp-server/.venv/bin/python
805
+
806
+ # Verify it exists:
807
+ ls -la /usr/local/lib/node_modules/@rishibhushan/jenkins-mcp-server/.venv/bin/python
808
+ ```
809
+
810
+ **Windows:**
811
+ ```powershell
812
+ # If npm root -g shows: C:\Users\username\AppData\Roaming\npm\node_modules
813
+ # Your Python path will be:
814
+ C:\Users\username\AppData\Roaming\npm\node_modules\@rishibhushan\jenkins-mcp-server\.venv\Scripts\python.exe
815
+
816
+ # Verify it exists:
817
+ Test-Path "C:\Users\username\AppData\Roaming\npm\node_modules\@rishibhushan\jenkins-mcp-server\.venv\Scripts\python.exe"
818
+ ```
819
+
820
+ #### Step 4: Configure Your MCP Client
821
+
822
+ **For Claude Desktop (macOS/Linux):**
823
+ ```json
824
+ {
825
+ "mcpServers": {
826
+ "jenkins": {
827
+ "command": "/usr/local/lib/node_modules/@rishibhushan/jenkins-mcp-server/.venv/bin/python",
828
+ "args": [
829
+ "-m",
830
+ "jenkins_mcp_server",
831
+ "--env-file",
832
+ "/path/to/your/.env"
833
+ ],
834
+ "env": {
835
+ "PYTHONPATH": "/usr/local/lib/node_modules/@rishibhushan/jenkins-mcp-server/src"
836
+ }
837
+ }
838
+ }
839
+ }
840
+ ```
841
+
842
+ **For Claude Desktop (Windows):**
843
+ ```json
844
+ {
845
+ "mcpServers": {
846
+ "jenkins": {
847
+ "command": "C:\\Users\\username\\AppData\\Roaming\\npm\\node_modules\\@rishibhushan\\jenkins-mcp-server\\.venv\\Scripts\\python.exe",
848
+ "args": [
849
+ "-m",
850
+ "jenkins_mcp_server",
851
+ "--env-file",
852
+ "C:\\path\\to\\your\\.env"
853
+ ],
854
+ "env": {
855
+ "PYTHONPATH": "C:\\Users\\username\\AppData\\Roaming\\npm\\node_modules\\@rishibhushan\\jenkins-mcp-server\\src"
856
+ }
857
+ }
858
+ }
859
+ }
860
+ ```
861
+
862
+ **For Other MCP Clients:**
863
+
864
+ Use the same pattern - replace the `command` with the direct Python path and set the `PYTHONPATH` environment variable.
865
+
866
+ #### Step 5: Test and Use
867
+
868
+ 1. **Connect to your VPN**
869
+ 2. **Restart your MCP client** (Claude Desktop, VS Code, etc.)
870
+ 3. **Verify the connection** works
871
+
872
+ #### Why This Solution Works
873
+
874
+ - ✅ **Persistent installation** - No need to download on each use
875
+ - ✅ **Proper network routing** - Python process inherits VPN routing
876
+ - ✅ **Works across sessions** - Survives VPN connect/disconnect cycles
877
+ - ✅ **Easy updates** - Just run `npm update -g @rishibhushan/jenkins-mcp-server`
878
+ - ✅ **Universal** - Works with any MCP client (Claude, VS Code, etc.)
879
+
880
+ #### Quick Reference Commands
881
+ ```bash
882
+ # Find your global installation
883
+ npm root -g
884
+
885
+ # Update global installation
886
+ npm update -g @rishibhushan/jenkins-mcp-server
887
+
888
+ # Uninstall if needed
889
+ npm uninstall -g @rishibhushan/jenkins-mcp-server
890
+
891
+ # Test the Python path works
892
+ /path/to/global/installation/.venv/bin/python -m jenkins_mcp_server --help
893
+ ```
716
894
 
717
895
  ---
718
896
 
@@ -5,7 +5,8 @@
5
5
  * This wrapper handles:
6
6
  * - Python version detection (cross-platform)
7
7
  * - Virtual environment creation
8
- * - Dependency installation
8
+ * - Smart proxy detection and handling (auto-detects corporate vs public networks)
9
+ * - Dependency installation with retry logic
9
10
  * - Server execution
10
11
  *
11
12
  * Supports: Windows, macOS, Linux
@@ -26,7 +27,9 @@ const colors = {
26
27
  green: '\x1b[32m',
27
28
  yellow: '\x1b[33m',
28
29
  red: '\x1b[31m',
29
- blue: '\x1b[34m'
30
+ blue: '\x1b[34m',
31
+ cyan: '\x1b[36m',
32
+ bold: '\x1b[1m'
30
33
  };
31
34
 
32
35
  function log(message, color = 'reset') {
@@ -40,6 +43,93 @@ function error(message) {
40
43
  console.error(`${colors.red}ERROR: ${message}${colors.reset}`);
41
44
  }
42
45
 
46
+ function warning(message) {
47
+ console.error(`${colors.yellow}WARNING: ${message}${colors.reset}`);
48
+ }
49
+
50
+ function info(message) {
51
+ console.error(`${colors.cyan}ℹ ${message}${colors.reset}`);
52
+ }
53
+
54
+ /**
55
+ * Detect and display proxy configuration
56
+ * @returns {Object} Proxy configuration details
57
+ */
58
+ function detectProxyConfig() {
59
+ const proxyVars = [
60
+ 'HTTP_PROXY', 'http_proxy',
61
+ 'HTTPS_PROXY', 'https_proxy',
62
+ 'ALL_PROXY', 'all_proxy',
63
+ 'NO_PROXY', 'no_proxy'
64
+ ];
65
+
66
+ const activeProxies = {};
67
+ for (const varName of proxyVars) {
68
+ if (process.env[varName]) {
69
+ activeProxies[varName] = process.env[varName];
70
+ }
71
+ }
72
+
73
+ return activeProxies;
74
+ }
75
+
76
+ /**
77
+ * Test if proxy is reachable
78
+ * @param {string} proxyUrl - Proxy URL to test
79
+ * @returns {boolean} True if proxy is reachable
80
+ */
81
+ function testProxyConnectivity(proxyUrl) {
82
+ try {
83
+ // Try to parse proxy URL
84
+ const url = new URL(proxyUrl);
85
+
86
+ // Use curl to test proxy connectivity (cross-platform)
87
+ const testCmd = isWindows
88
+ ? `curl -s -o NUL -w "%{http_code}" --proxy ${proxyUrl} --max-time 5 https://pypi.org/simple/`
89
+ : `curl -s -o /dev/null -w "%{http_code}" --proxy ${proxyUrl} --max-time 5 https://pypi.org/simple/`;
90
+
91
+ const result = spawnSync(isWindows ? 'cmd' : 'sh',
92
+ isWindows ? ['/c', testCmd] : ['-c', testCmd],
93
+ {
94
+ stdio: 'pipe',
95
+ encoding: 'utf-8',
96
+ timeout: 6000
97
+ }
98
+ );
99
+
100
+ const httpCode = result.stdout?.trim();
101
+ return httpCode === '200' || httpCode === '301' || httpCode === '302';
102
+ } catch (e) {
103
+ return false;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Test if PyPI is directly accessible (without proxy)
109
+ * @returns {boolean} True if PyPI is accessible
110
+ */
111
+ function testDirectPyPIAccess() {
112
+ try {
113
+ const testCmd = isWindows
114
+ ? 'curl -s -o NUL -w "%{http_code}" --max-time 5 https://pypi.org/simple/'
115
+ : 'curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://pypi.org/simple/';
116
+
117
+ const result = spawnSync(isWindows ? 'cmd' : 'sh',
118
+ isWindows ? ['/c', testCmd] : ['-c', testCmd],
119
+ {
120
+ stdio: 'pipe',
121
+ encoding: 'utf-8',
122
+ timeout: 6000
123
+ }
124
+ );
125
+
126
+ const httpCode = result.stdout?.trim();
127
+ return httpCode === '200' || httpCode === '301' || httpCode === '302';
128
+ } catch (e) {
129
+ return false;
130
+ }
131
+ }
132
+
43
133
  /**
44
134
  * Check for Python 3 installation
45
135
  * @returns {string} Python command name
@@ -157,7 +247,89 @@ function dependenciesInstalled(pipPath) {
157
247
  }
158
248
 
159
249
  /**
160
- * Install Python dependencies
250
+ * Show helpful guidance for proxy-related installation failures
251
+ */
252
+ function showProxyTroubleshooting(activeProxies, canAccessDirectly, proxyWorks) {
253
+ console.error('\n' + '='.repeat(70));
254
+ console.error(colors.bold + colors.yellow + 'INSTALLATION FAILED - NETWORK CONFIGURATION ISSUE' + colors.reset);
255
+ console.error('='.repeat(70));
256
+
257
+ if (Object.keys(activeProxies).length > 0) {
258
+ console.error('\n📡 Active proxy environment variables found:');
259
+ for (const [key, value] of Object.entries(activeProxies)) {
260
+ console.error(` ${colors.cyan}${key}${colors.reset} = ${value}`);
261
+ }
262
+
263
+ if (!proxyWorks && canAccessDirectly) {
264
+ // Proxy is set but doesn't work, and direct access works
265
+ console.error('\n' + colors.red + '❌ Proxy is NOT reachable' + colors.reset);
266
+ console.error(colors.green + '✓ Direct internet access IS available' + colors.reset);
267
+ console.error('\n' + colors.yellow + '⚠️ You\'re on a PUBLIC network but have proxy settings from a corporate/VPN network!' + colors.reset);
268
+ console.error('\n💡 SOLUTION:\n');
269
+ console.error(colors.bold + 'Remove the proxy settings:' + colors.reset);
270
+ console.error(colors.cyan + ' unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy ALL_PROXY all_proxy' + colors.reset);
271
+ console.error(' Then run the command again.\n');
272
+
273
+ } else if (proxyWorks && !canAccessDirectly) {
274
+ // Proxy works, direct access doesn't
275
+ console.error('\n' + colors.green + '✓ Proxy IS reachable' + colors.reset);
276
+ console.error(colors.red + '❌ Direct internet access is NOT available' + colors.reset);
277
+ console.error('\n' + colors.blue + 'You\'re on a CORPORATE network - proxy is required.' + colors.reset);
278
+ console.error('\n💡 SOLUTION:\n');
279
+ console.error('The proxy should work. The error may be due to:');
280
+ console.error('1. SSL certificate issues - contact your IT department');
281
+ console.error('2. Authentication required - check if proxy needs username/password');
282
+ console.error('3. Specific packages blocked - contact your IT department\n');
283
+
284
+ } else if (!proxyWorks && !canAccessDirectly) {
285
+ // Neither works
286
+ console.error('\n' + colors.red + '❌ Proxy is NOT reachable' + colors.reset);
287
+ console.error(colors.red + '❌ Direct internet access is NOT available' + colors.reset);
288
+ console.error('\n💡 SOLUTIONS:\n');
289
+ console.error('1. Check your internet connection');
290
+ console.error('2. If on corporate network, verify proxy settings with IT');
291
+ console.error('3. Try a different network (mobile hotspot, home WiFi)');
292
+ console.error('4. Check firewall/antivirus settings\n');
293
+
294
+ } else {
295
+ // Both work (unusual case)
296
+ console.error('\n' + colors.green + '✓ Proxy IS reachable' + colors.reset);
297
+ console.error(colors.green + '✓ Direct internet access IS available' + colors.reset);
298
+ console.error('\nThe issue may be:');
299
+ console.error('1. SSL certificate problems');
300
+ console.error('2. Intermittent connectivity');
301
+ console.error('3. Package-specific blocking\n');
302
+ }
303
+
304
+ console.error(colors.bold + 'Additional options:' + colors.reset);
305
+ console.error('• Check system proxy settings:');
306
+ if (!isWindows) {
307
+ console.error(' macOS: System Settings → Network → Advanced → Proxies');
308
+ } else {
309
+ console.error(' Windows: Settings → Network & Internet → Proxy');
310
+ }
311
+ console.error('• Try manual installation (see TROUBLESHOOTING.md)');
312
+
313
+ } else {
314
+ console.error('\n💡 No proxy environment variables detected.\n');
315
+ console.error('POSSIBLE CAUSES:');
316
+ console.error('• Network connectivity issues');
317
+ console.error('• Firewall blocking PyPI access');
318
+ console.error('• DNS resolution problems');
319
+ console.error('• System-level proxy (not in environment variables)\n');
320
+
321
+ console.error('SOLUTIONS TO TRY:');
322
+ console.error('1. Check your internet connection');
323
+ console.error('2. Try: curl https://pypi.org/simple/');
324
+ console.error('3. Check firewall/antivirus settings');
325
+ console.error('4. Check system proxy settings (not environment variables)\n');
326
+ }
327
+
328
+ console.error('='.repeat(70) + '\n');
329
+ }
330
+
331
+ /**
332
+ * Install Python dependencies with smart proxy detection
161
333
  * @param {string} venvPath - Path to virtual environment
162
334
  */
163
335
  function installDependencies(venvPath) {
@@ -171,11 +343,10 @@ function installDependencies(venvPath) {
171
343
  if (fs.existsSync(wheelsPath)) {
172
344
  console.error('Using pre-packaged wheels (no internet required)...');
173
345
 
174
- // Install from local wheels (fast, no network needed)
175
346
  const installReqs = spawnSync(pip, [
176
347
  'install',
177
- '--no-index', // Don't use PyPI
178
- '--find-links', wheelsPath, // Use local wheels
348
+ '--no-index',
349
+ '--find-links', wheelsPath,
179
350
  '-r', requirementsPath
180
351
  ], {
181
352
  cwd: projectRoot,
@@ -186,35 +357,96 @@ function installDependencies(venvPath) {
186
357
  error('Failed to install from wheels');
187
358
  process.exit(1);
188
359
  }
360
+
361
+ log('✓ Requirements installed', 'green');
189
362
  } else {
190
- // Fallback to normal install with proxy support
363
+ // Need network - detect proxy configuration intelligently
191
364
  console.error('Downloading from PyPI...');
365
+
366
+ const activeProxies = detectProxyConfig();
367
+ const hasProxyVars = Object.keys(activeProxies).length > 0;
368
+
369
+ let proxyToUse = null;
370
+ let useNoProxy = false;
371
+
372
+ if (hasProxyVars) {
373
+ const proxyUrl = process.env.HTTP_PROXY || process.env.http_proxy ||
374
+ process.env.HTTPS_PROXY || process.env.https_proxy;
375
+
376
+ info('Proxy environment variables detected. Testing connectivity...');
377
+
378
+ // Test proxy connectivity
379
+ const proxyWorks = proxyUrl && proxyUrl.startsWith('http') && testProxyConnectivity(proxyUrl);
380
+ const directWorks = testDirectPyPIAccess();
381
+
382
+ if (proxyWorks && !directWorks) {
383
+ // Corporate network - use proxy
384
+ info('Corporate network detected. Using proxy.');
385
+ proxyToUse = proxyUrl;
386
+ } else if (!proxyWorks && directWorks) {
387
+ // Public network with stale proxy vars - ignore proxy
388
+ warning('Proxy unreachable but direct access available. Ignoring proxy settings.');
389
+ useNoProxy = true;
390
+ } else if (proxyWorks && directWorks) {
391
+ // Both work - prefer direct
392
+ info('Both proxy and direct access available. Using direct connection.');
393
+ useNoProxy = true;
394
+ } else {
395
+ // Neither works - will fail but try direct
396
+ warning('Neither proxy nor direct access working. Attempting direct connection...');
397
+ useNoProxy = true;
398
+ }
399
+ }
400
+
401
+ // Build pip arguments
192
402
  const pipArgs = ['install', '-r', requirementsPath];
193
403
 
194
- const proxyFriendlyArgs = [
404
+ // Trusted hosts for SSL-friendly installation
405
+ const trustedHostArgs = [
195
406
  '--trusted-host', 'pypi.org',
196
407
  '--trusted-host', 'pypi.python.org',
197
408
  '--trusted-host', 'files.pythonhosted.org'
198
409
  ];
410
+ pipArgs.push(...trustedHostArgs);
411
+
412
+ // Add proxy if needed
413
+ if (proxyToUse && !useNoProxy) {
414
+ info(`Using proxy: ${proxyToUse}`);
415
+ pipArgs.push('--proxy', proxyToUse);
416
+ }
199
417
 
200
- const proxy = process.env.HTTP_PROXY || process.env.http_proxy;
201
- if (proxy) {
202
- pipArgs.push('--proxy', proxy);
418
+ // Set up environment (potentially removing proxy vars)
419
+ const pipEnv = { ...process.env };
420
+ if (useNoProxy) {
421
+ // Remove proxy environment variables for this pip call
422
+ delete pipEnv.HTTP_PROXY;
423
+ delete pipEnv.HTTPS_PROXY;
424
+ delete pipEnv.http_proxy;
425
+ delete pipEnv.https_proxy;
426
+ delete pipEnv.ALL_PROXY;
427
+ delete pipEnv.all_proxy;
203
428
  }
204
- pipArgs.push(...proxyFriendlyArgs);
205
429
 
206
430
  const installReqs = spawnSync(pip, pipArgs, {
207
431
  cwd: projectRoot,
208
- stdio: 'inherit'
432
+ stdio: 'inherit',
433
+ env: pipEnv
209
434
  });
210
435
 
211
436
  if (installReqs.status !== 0) {
212
- error('Failed to install dependencies');
437
+ error('Failed to install dependencies from PyPI');
438
+
439
+ // Show intelligent troubleshooting
440
+ const proxyUrl = process.env.HTTP_PROXY || process.env.http_proxy;
441
+ const proxyWorks = proxyUrl ? testProxyConnectivity(proxyUrl) : false;
442
+ const directWorks = testDirectPyPIAccess();
443
+
444
+ showProxyTroubleshooting(activeProxies, directWorks, proxyWorks);
213
445
  process.exit(1);
214
446
  }
215
- }
216
447
 
217
- console.error('✓ Requirements installed');
448
+ log('✓ Requirements installed', 'green');
449
+ }
218
450
 
219
451
  // Install package itself
220
452
  console.error('Installing jenkins-mcp-server package...');
@@ -230,7 +462,7 @@ function installDependencies(venvPath) {
230
462
  process.exit(1);
231
463
  }
232
464
 
233
- console.error('✓ Package installed');
465
+ log('✓ Package installed successfully', 'green');
234
466
  }
235
467
 
236
468
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rishibhushan/jenkins-mcp-server",
3
- "version": "1.0.7",
3
+ "version": "1.1.1",
4
4
  "description": "AI-enabled Jenkins automation via Model Context Protocol (MCP)",
5
5
  "main": "bin/jenkins-mcp.js",
6
6
  "bin": {
package/requirements.txt CHANGED
@@ -2,6 +2,7 @@
2
2
  mcp>=1.0.0
3
3
  python-jenkins>=1.8.0
4
4
  requests>=2.28.0
5
+ structlog>=23.1.0
5
6
 
6
7
  # Settings management
7
8
  pydantic>=2.0.0
@@ -14,19 +14,27 @@ from . import server
14
14
 
15
15
 
16
16
  def setup_logging(verbose: bool = False) -> None:
17
- """Configure logging for the application"""
18
- level = logging.DEBUG if verbose else logging.INFO
19
-
20
- logging.basicConfig(
21
- level=level,
22
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
23
- stream=sys.stderr
17
+ """Configure structured logging"""
18
+ import structlog
19
+
20
+ # Configure structlog
21
+ structlog.configure(
22
+ processors=[
23
+ structlog.stdlib.filter_by_level,
24
+ structlog.stdlib.add_logger_name,
25
+ structlog.stdlib.add_log_level,
26
+ structlog.stdlib.PositionalArgumentsFormatter(),
27
+ structlog.processors.TimeStamper(fmt="iso"),
28
+ structlog.processors.StackInfoRenderer(),
29
+ structlog.processors.format_exc_info,
30
+ structlog.processors.UnicodeDecoder(),
31
+ structlog.processors.JSONRenderer() if not verbose else structlog.dev.ConsoleRenderer()
32
+ ],
33
+ context_class=dict,
34
+ logger_factory=structlog.stdlib.LoggerFactory(),
35
+ cache_logger_on_first_use=True,
24
36
  )
25
37
 
26
- # Reduce noise from libraries
27
- logging.getLogger('urllib3').setLevel(logging.WARNING)
28
- logging.getLogger('requests').setLevel(logging.WARNING)
29
-
30
38
 
31
39
  def main():
32
40
  """