@rishibhushan/jenkins-mcp-server 1.1.1 → 1.1.3
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/bin/jenkins-mcp.js +108 -0
- package/package.json +6 -4
- package/pyproject.toml +190 -0
- package/src/jenkins_mcp_server/jenkins_client.py +14 -12
- package/src/jenkins_mcp_server/server.py +19 -3
- package/src/jenkins_mcp_server/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/jenkins_mcp_server/__pycache__/__main__.cpython-313.pyc +0 -0
- package/src/jenkins_mcp_server/__pycache__/cache.cpython-313.pyc +0 -0
- package/src/jenkins_mcp_server/__pycache__/config.cpython-313.pyc +0 -0
- package/src/jenkins_mcp_server/__pycache__/jenkins_client.cpython-313.pyc +0 -0
- package/src/jenkins_mcp_server/__pycache__/metrics.cpython-313.pyc +0 -0
- package/src/jenkins_mcp_server/__pycache__/server.cpython-313.pyc +0 -0
- package/src/jenkins_mcp_server.egg-info/PKG-INFO +0 -624
- package/src/jenkins_mcp_server.egg-info/SOURCES.txt +0 -13
- package/src/jenkins_mcp_server.egg-info/dependency_links.txt +0 -1
- package/src/jenkins_mcp_server.egg-info/entry_points.txt +0 -2
- package/src/jenkins_mcp_server.egg-info/requires.txt +0 -20
- package/src/jenkins_mcp_server.egg-info/top_level.txt +0 -1
package/bin/jenkins-mcp.js
CHANGED
|
@@ -73,6 +73,62 @@ function detectProxyConfig() {
|
|
|
73
73
|
return activeProxies;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Check npm config for proxy settings
|
|
78
|
+
* @returns {Object} npm proxy configuration
|
|
79
|
+
*/
|
|
80
|
+
function checkNpmProxy() {
|
|
81
|
+
try {
|
|
82
|
+
const result = spawnSync('npm', ['config', 'list'], {
|
|
83
|
+
stdio: 'pipe',
|
|
84
|
+
encoding: 'utf-8'
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (result.status === 0) {
|
|
88
|
+
const output = result.stdout || '';
|
|
89
|
+
const proxyLines = output.split('\n').filter(line =>
|
|
90
|
+
line.toLowerCase().includes('proxy') && !line.includes('; ///')
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (proxyLines.length > 0) {
|
|
94
|
+
return {
|
|
95
|
+
found: true,
|
|
96
|
+
config: proxyLines.join('\n')
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch (e) {
|
|
101
|
+
// npm not available or error
|
|
102
|
+
}
|
|
103
|
+
return { found: false };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Check pip config for proxy settings
|
|
108
|
+
* @returns {Object} pip proxy configuration
|
|
109
|
+
*/
|
|
110
|
+
function checkPipProxy() {
|
|
111
|
+
try {
|
|
112
|
+
const result = spawnSync('pip3', ['config', 'list'], {
|
|
113
|
+
stdio: 'pipe',
|
|
114
|
+
encoding: 'utf-8'
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (result.status === 0) {
|
|
118
|
+
const output = result.stdout || '';
|
|
119
|
+
if (output.toLowerCase().includes('proxy')) {
|
|
120
|
+
return {
|
|
121
|
+
found: true,
|
|
122
|
+
config: output
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (e) {
|
|
127
|
+
// pip not available or error
|
|
128
|
+
}
|
|
129
|
+
return { found: false };
|
|
130
|
+
}
|
|
131
|
+
|
|
76
132
|
/**
|
|
77
133
|
* Test if proxy is reachable
|
|
78
134
|
* @param {string} proxyUrl - Proxy URL to test
|
|
@@ -254,6 +310,32 @@ function showProxyTroubleshooting(activeProxies, canAccessDirectly, proxyWorks)
|
|
|
254
310
|
console.error(colors.bold + colors.yellow + 'INSTALLATION FAILED - NETWORK CONFIGURATION ISSUE' + colors.reset);
|
|
255
311
|
console.error('='.repeat(70));
|
|
256
312
|
|
|
313
|
+
// Check npm and pip config
|
|
314
|
+
const npmProxy = checkNpmProxy();
|
|
315
|
+
const pipProxy = checkPipProxy();
|
|
316
|
+
|
|
317
|
+
if (npmProxy.found) {
|
|
318
|
+
console.error('\n' + colors.red + '⚠️ FOUND PROXY IN NPM CONFIG!' + colors.reset);
|
|
319
|
+
console.error(colors.cyan + npmProxy.config + colors.reset);
|
|
320
|
+
console.error('\n' + colors.yellow + 'This is likely the cause of your issue!' + colors.reset);
|
|
321
|
+
console.error('\n' + colors.bold + 'FIX (run these commands):' + colors.reset);
|
|
322
|
+
console.error(colors.cyan + ' npm config delete proxy' + colors.reset);
|
|
323
|
+
console.error(colors.cyan + ' npm config delete https-proxy' + colors.reset);
|
|
324
|
+
console.error(colors.cyan + ' npm config delete http-proxy' + colors.reset);
|
|
325
|
+
console.error(colors.cyan + ' npm config --global delete proxy' + colors.reset);
|
|
326
|
+
console.error(colors.cyan + ' npm config --global delete https-proxy' + colors.reset);
|
|
327
|
+
console.error('\nThen run your command again.\n');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (pipProxy.found) {
|
|
331
|
+
console.error('\n' + colors.red + '⚠️ FOUND PROXY IN PIP CONFIG!' + colors.reset);
|
|
332
|
+
console.error(colors.cyan + pipProxy.config + colors.reset);
|
|
333
|
+
console.error('\n' + colors.bold + 'FIX (run these commands):' + colors.reset);
|
|
334
|
+
console.error(colors.cyan + ' pip3 config unset global.proxy' + colors.reset);
|
|
335
|
+
console.error(colors.cyan + ' pip3 config unset user.proxy' + colors.reset);
|
|
336
|
+
console.error('\nOr edit/delete: ~/.config/pip/pip.conf\n');
|
|
337
|
+
}
|
|
338
|
+
|
|
257
339
|
if (Object.keys(activeProxies).length > 0) {
|
|
258
340
|
console.error('\n📡 Active proxy environment variables found:');
|
|
259
341
|
for (const [key, value] of Object.entries(activeProxies)) {
|
|
@@ -450,6 +532,18 @@ function installDependencies(venvPath) {
|
|
|
450
532
|
|
|
451
533
|
// Install package itself
|
|
452
534
|
console.error('Installing jenkins-mcp-server package...');
|
|
535
|
+
|
|
536
|
+
// Verify pyproject.toml exists
|
|
537
|
+
const pyprojectPath = path.join(projectRoot, 'pyproject.toml');
|
|
538
|
+
if (!fs.existsSync(pyprojectPath)) {
|
|
539
|
+
error('pyproject.toml not found in project root');
|
|
540
|
+
console.error('\nProject root:', projectRoot);
|
|
541
|
+
console.error('Expected file:', pyprojectPath);
|
|
542
|
+
console.error('\nThis may be due to npx cache issues with special characters.');
|
|
543
|
+
console.error('Try clearing npx cache: npx clear-npx-cache');
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
546
|
+
|
|
453
547
|
const packageArgs = ['install', '-e', '.'];
|
|
454
548
|
|
|
455
549
|
const installPkg = spawnSync(pip, packageArgs, {
|
|
@@ -459,6 +553,20 @@ function installDependencies(venvPath) {
|
|
|
459
553
|
|
|
460
554
|
if (installPkg.status !== 0) {
|
|
461
555
|
error('Failed to install package');
|
|
556
|
+
console.error('\nProject root:', projectRoot);
|
|
557
|
+
console.error('Files in project root:');
|
|
558
|
+
try {
|
|
559
|
+
const files = fs.readdirSync(projectRoot);
|
|
560
|
+
console.error(files.join(', '));
|
|
561
|
+
} catch (e) {
|
|
562
|
+
console.error('Could not list files');
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
console.error('\n💡 TROUBLESHOOTING:');
|
|
566
|
+
console.error('1. The npx cache may have issues with the @ symbol in package name');
|
|
567
|
+
console.error('2. Try: npx clear-npx-cache && rm -rf ~/.npm/_npx');
|
|
568
|
+
console.error('3. Or install globally: npm install -g @rishibhushan/jenkins-mcp-server');
|
|
569
|
+
console.error(' Then run: jenkins-mcp-server --env-file /path/to/.env');
|
|
462
570
|
process.exit(1);
|
|
463
571
|
}
|
|
464
572
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rishibhushan/jenkins-mcp-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "AI-enabled Jenkins automation via Model Context Protocol (MCP)",
|
|
5
5
|
"main": "bin/jenkins-mcp.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node bin/jenkins-mcp.js",
|
|
11
11
|
"test": "python -m pytest tests/",
|
|
12
|
-
"build": "python -m build"
|
|
12
|
+
"build": "python -m build",
|
|
13
|
+
"prepack": "npm run clean",
|
|
14
|
+
"clean": "find . -type d -name '__pycache__' -exec rm -rf {} + 2>/dev/null || true; find . -type d -name '*.egg-info' -exec rm -rf {} + 2>/dev/null || true"
|
|
13
15
|
},
|
|
14
16
|
"files": [
|
|
15
17
|
"bin/",
|
|
16
|
-
"src
|
|
18
|
+
"src/**/*.py",
|
|
19
|
+
"pyproject.toml",
|
|
17
20
|
"requirements.txt",
|
|
18
|
-
"wheels/",
|
|
19
21
|
"README.md",
|
|
20
22
|
"LICENSE"
|
|
21
23
|
],
|
package/pyproject.toml
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "jenkins-mcp-server"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "AI-enabled Jenkins automation via Model Context Protocol (MCP)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Rishi Bhushan", email = "rishibharat2007@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{name = "Rishi Bhushan", email = "rishibharat2007@example.com"}
|
|
17
|
+
]
|
|
18
|
+
keywords = [
|
|
19
|
+
"mcp",
|
|
20
|
+
"jenkins",
|
|
21
|
+
"ai",
|
|
22
|
+
"automation",
|
|
23
|
+
"ci-cd",
|
|
24
|
+
"devops",
|
|
25
|
+
"model-context-protocol",
|
|
26
|
+
"llm"
|
|
27
|
+
]
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Development Status :: 4 - Beta",
|
|
30
|
+
"Intended Audience :: Developers",
|
|
31
|
+
"Intended Audience :: System Administrators",
|
|
32
|
+
"License :: OSI Approved :: MIT License",
|
|
33
|
+
"Operating System :: OS Independent",
|
|
34
|
+
"Programming Language :: Python :: 3",
|
|
35
|
+
"Programming Language :: Python :: 3.8",
|
|
36
|
+
"Programming Language :: Python :: 3.9",
|
|
37
|
+
"Programming Language :: Python :: 3.10",
|
|
38
|
+
"Programming Language :: Python :: 3.11",
|
|
39
|
+
"Programming Language :: Python :: 3.12",
|
|
40
|
+
"Topic :: Software Development :: Build Tools",
|
|
41
|
+
"Topic :: System :: Systems Administration",
|
|
42
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
dependencies = [
|
|
46
|
+
"mcp>=1.0.0",
|
|
47
|
+
"python-jenkins>=1.8.0",
|
|
48
|
+
"requests>=2.28.0",
|
|
49
|
+
"pydantic>=2.0.0",
|
|
50
|
+
"pydantic-settings>=2.0.0",
|
|
51
|
+
"python-dotenv>=1.0.0",
|
|
52
|
+
"urllib3>=2.0.0"
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[project.optional-dependencies]
|
|
56
|
+
dev = [
|
|
57
|
+
"pytest>=7.0.0",
|
|
58
|
+
"pytest-asyncio>=0.21.0",
|
|
59
|
+
"pytest-cov>=4.0.0",
|
|
60
|
+
"black>=23.0.0",
|
|
61
|
+
"ruff>=0.1.0",
|
|
62
|
+
"mypy>=1.0.0"
|
|
63
|
+
]
|
|
64
|
+
test = [
|
|
65
|
+
"pytest>=7.0.0",
|
|
66
|
+
"pytest-asyncio>=0.21.0",
|
|
67
|
+
"pytest-cov>=4.0.0"
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[project.urls]
|
|
71
|
+
Homepage = "https://github.com/rishibhushan/jenkins_mcp_server"
|
|
72
|
+
Documentation = "https://github.com/rishibhushan/jenkins_mcp_server#readme"
|
|
73
|
+
Repository = "https://github.com/rishibhushan/jenkins_mcp_server.git"
|
|
74
|
+
"Bug Tracker" = "https://github.com/rishibhushan/jenkins_mcp_server/issues"
|
|
75
|
+
Changelog = "https://github.com/rishibhushan/jenkins_mcp_server/releases"
|
|
76
|
+
|
|
77
|
+
[project.scripts]
|
|
78
|
+
jenkins-mcp-server = "jenkins_mcp_server:main"
|
|
79
|
+
|
|
80
|
+
[tool.setuptools]
|
|
81
|
+
package-dir = {"" = "src"}
|
|
82
|
+
|
|
83
|
+
[tool.setuptools.packages.find]
|
|
84
|
+
where = ["src"]
|
|
85
|
+
include = ["jenkins_mcp_server*"]
|
|
86
|
+
exclude = ["tests*"]
|
|
87
|
+
|
|
88
|
+
[tool.setuptools.package-data]
|
|
89
|
+
jenkins_mcp_server = ["py.typed"]
|
|
90
|
+
|
|
91
|
+
# Black configuration
|
|
92
|
+
[tool.black]
|
|
93
|
+
line-length = 100
|
|
94
|
+
target-version = ['py38', 'py39', 'py310', 'py311']
|
|
95
|
+
include = '\.pyi?$'
|
|
96
|
+
extend-exclude = '''
|
|
97
|
+
/(
|
|
98
|
+
# directories
|
|
99
|
+
\.eggs
|
|
100
|
+
| \.git
|
|
101
|
+
| \.hg
|
|
102
|
+
| \.mypy_cache
|
|
103
|
+
| \.tox
|
|
104
|
+
| \.venv
|
|
105
|
+
| build
|
|
106
|
+
| dist
|
|
107
|
+
)/
|
|
108
|
+
'''
|
|
109
|
+
|
|
110
|
+
# Ruff configuration (fast linter)
|
|
111
|
+
[tool.ruff]
|
|
112
|
+
line-length = 100
|
|
113
|
+
target-version = "py38"
|
|
114
|
+
select = [
|
|
115
|
+
"E", # pycodestyle errors
|
|
116
|
+
"W", # pycodestyle warnings
|
|
117
|
+
"F", # pyflakes
|
|
118
|
+
"I", # isort
|
|
119
|
+
"B", # flake8-bugbear
|
|
120
|
+
"C4", # flake8-comprehensions
|
|
121
|
+
"UP", # pyupgrade
|
|
122
|
+
]
|
|
123
|
+
ignore = [
|
|
124
|
+
"E501", # line too long (handled by black)
|
|
125
|
+
"B008", # do not perform function calls in argument defaults
|
|
126
|
+
"C901", # too complex
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
[tool.ruff.per-file-ignores]
|
|
130
|
+
"__init__.py" = ["F401"] # unused imports in __init__.py
|
|
131
|
+
|
|
132
|
+
# MyPy configuration
|
|
133
|
+
[tool.mypy]
|
|
134
|
+
python_version = "3.8"
|
|
135
|
+
warn_return_any = true
|
|
136
|
+
warn_unused_configs = true
|
|
137
|
+
disallow_untyped_defs = false
|
|
138
|
+
disallow_incomplete_defs = false
|
|
139
|
+
check_untyped_defs = true
|
|
140
|
+
no_implicit_optional = true
|
|
141
|
+
warn_redundant_casts = true
|
|
142
|
+
warn_unused_ignores = true
|
|
143
|
+
warn_no_return = true
|
|
144
|
+
strict_equality = true
|
|
145
|
+
|
|
146
|
+
[[tool.mypy.overrides]]
|
|
147
|
+
module = [
|
|
148
|
+
"jenkins",
|
|
149
|
+
"mcp.*"
|
|
150
|
+
]
|
|
151
|
+
ignore_missing_imports = true
|
|
152
|
+
|
|
153
|
+
# Pytest configuration
|
|
154
|
+
[tool.pytest.ini_options]
|
|
155
|
+
minversion = "7.0"
|
|
156
|
+
addopts = [
|
|
157
|
+
"-ra",
|
|
158
|
+
"--strict-markers",
|
|
159
|
+
"--strict-config",
|
|
160
|
+
"--showlocals",
|
|
161
|
+
"--tb=short"
|
|
162
|
+
]
|
|
163
|
+
testpaths = ["tests"]
|
|
164
|
+
pythonpath = ["src"]
|
|
165
|
+
asyncio_mode = "auto"
|
|
166
|
+
|
|
167
|
+
# Coverage configuration
|
|
168
|
+
[tool.coverage.run]
|
|
169
|
+
source = ["src"]
|
|
170
|
+
branch = true
|
|
171
|
+
omit = [
|
|
172
|
+
"*/tests/*",
|
|
173
|
+
"*/__pycache__/*",
|
|
174
|
+
"*/.venv/*"
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
[tool.coverage.report]
|
|
178
|
+
precision = 2
|
|
179
|
+
show_missing = true
|
|
180
|
+
skip_covered = false
|
|
181
|
+
exclude_lines = [
|
|
182
|
+
"pragma: no cover",
|
|
183
|
+
"def __repr__",
|
|
184
|
+
"raise AssertionError",
|
|
185
|
+
"raise NotImplementedError",
|
|
186
|
+
"if __name__ == .__main__.:",
|
|
187
|
+
"if TYPE_CHECKING:",
|
|
188
|
+
"class .*\\bProtocol\\):",
|
|
189
|
+
"@(abc\\.)?abstractmethod"
|
|
190
|
+
]
|
|
@@ -40,12 +40,14 @@ class JenkinsClient:
|
|
|
40
40
|
timeout support.
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
|
-
def __init__(self, settings: Optional[JenkinsSettings] = None):
|
|
43
|
+
def __init__(self, settings: Optional[JenkinsSettings] = None, test_connection: bool = False):
|
|
44
44
|
"""
|
|
45
45
|
Initialize Jenkins client.
|
|
46
46
|
|
|
47
47
|
Args:
|
|
48
48
|
settings: JenkinsSettings instance. If None, uses default settings.
|
|
49
|
+
test_connection: If True, test connection during initialization.
|
|
50
|
+
Set to False for MCP list_resources to avoid blocking.
|
|
49
51
|
|
|
50
52
|
Raises:
|
|
51
53
|
JenkinsConnectionError: If unable to connect to Jenkins
|
|
@@ -72,8 +74,10 @@ class JenkinsClient:
|
|
|
72
74
|
# Cache for python-jenkins server instance
|
|
73
75
|
self._server: Optional[jenkins.Jenkins] = None
|
|
74
76
|
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
+
# Only test connection if explicitly requested
|
|
78
|
+
# This prevents blocking during MCP initialization
|
|
79
|
+
if test_connection:
|
|
80
|
+
self._test_connection()
|
|
77
81
|
|
|
78
82
|
def _test_connection(self) -> None:
|
|
79
83
|
"""Test connection to Jenkins server (with configurable timeout)"""
|
|
@@ -475,12 +479,16 @@ class JenkinsClient:
|
|
|
475
479
|
_default_client: Optional[JenkinsClient] = None
|
|
476
480
|
|
|
477
481
|
|
|
478
|
-
def get_jenkins_client(
|
|
482
|
+
def get_jenkins_client(
|
|
483
|
+
settings: Optional[JenkinsSettings] = None,
|
|
484
|
+
test_connection: bool = False
|
|
485
|
+
) -> JenkinsClient:
|
|
479
486
|
"""
|
|
480
487
|
Get Jenkins client instance.
|
|
481
488
|
|
|
482
489
|
Args:
|
|
483
490
|
settings: Optional JenkinsSettings. If None, uses default settings.
|
|
491
|
+
test_connection: If True, test connection during initialization.
|
|
484
492
|
|
|
485
493
|
Returns:
|
|
486
494
|
JenkinsClient instance
|
|
@@ -492,16 +500,10 @@ def get_jenkins_client(settings: Optional[JenkinsSettings] = None) -> JenkinsCli
|
|
|
492
500
|
|
|
493
501
|
if settings is not None:
|
|
494
502
|
# Always create new client with custom settings
|
|
495
|
-
return JenkinsClient(settings)
|
|
503
|
+
return JenkinsClient(settings, test_connection=test_connection)
|
|
496
504
|
|
|
497
505
|
# Use cached default client
|
|
498
506
|
if _default_client is None:
|
|
499
|
-
_default_client = JenkinsClient()
|
|
507
|
+
_default_client = JenkinsClient(test_connection=test_connection)
|
|
500
508
|
|
|
501
509
|
return _default_client
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
def reset_default_client() -> None:
|
|
505
|
-
"""Reset the default client (useful for testing or reconfiguration)"""
|
|
506
|
-
global _default_client
|
|
507
|
-
_default_client = None
|
|
@@ -120,10 +120,15 @@ async def handle_list_resources() -> list[types.Resource]:
|
|
|
120
120
|
"""
|
|
121
121
|
List available Jenkins resources.
|
|
122
122
|
Each job is exposed as a resource with jenkins:// URI scheme.
|
|
123
|
+
|
|
124
|
+
Enhanced with timeout to prevent MCP initialization delays.
|
|
123
125
|
"""
|
|
124
126
|
try:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
# Wrap in async timeout to prevent blocking MCP initialization
|
|
128
|
+
async with asyncio.timeout(3): # 3 second timeout
|
|
129
|
+
client = get_jenkins_client(get_settings())
|
|
130
|
+
# Run blocking get_jobs() in thread pool
|
|
131
|
+
jobs = await asyncio.to_thread(client.get_jobs)
|
|
127
132
|
|
|
128
133
|
return [
|
|
129
134
|
types.Resource(
|
|
@@ -134,13 +139,24 @@ async def handle_list_resources() -> list[types.Resource]:
|
|
|
134
139
|
)
|
|
135
140
|
for job in jobs
|
|
136
141
|
]
|
|
142
|
+
except asyncio.TimeoutError:
|
|
143
|
+
# Jenkins server not reachable (probably not on VPN/corporate network)
|
|
144
|
+
logger.warning("Jenkins server not reachable within 3 seconds - likely not on corporate network")
|
|
145
|
+
return [
|
|
146
|
+
types.Resource(
|
|
147
|
+
uri=AnyUrl("jenkins://offline"),
|
|
148
|
+
name="Jenkins Server Offline",
|
|
149
|
+
description="Jenkins server not reachable. Connect to VPN/corporate network and restart. Tools will still work when connected.",
|
|
150
|
+
mimeType="text/plain",
|
|
151
|
+
)
|
|
152
|
+
]
|
|
137
153
|
except Exception as e:
|
|
138
154
|
logger.error(f"Failed to list resources: {e}")
|
|
139
155
|
return [
|
|
140
156
|
types.Resource(
|
|
141
157
|
uri=AnyUrl("jenkins://error"),
|
|
142
158
|
name="Error connecting to Jenkins",
|
|
143
|
-
description=f"Error: {str(e)}",
|
|
159
|
+
description=f"Error: {str(e)}. Check your configuration and network connection.",
|
|
144
160
|
mimeType="text/plain",
|
|
145
161
|
)
|
|
146
162
|
]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,624 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: jenkins-mcp-server
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: AI-enabled Jenkins automation via Model Context Protocol (MCP)
|
|
5
|
-
Author-email: Rishi Bhushan <rishibharat2007@gmail.com>
|
|
6
|
-
Maintainer-email: Rishi Bhushan <rishibharat2007@example.com>
|
|
7
|
-
License: MIT
|
|
8
|
-
Project-URL: Homepage, https://github.com/rishibhushan/jenkins_mcp_server
|
|
9
|
-
Project-URL: Documentation, https://github.com/rishibhushan/jenkins_mcp_server#readme
|
|
10
|
-
Project-URL: Repository, https://github.com/rishibhushan/jenkins_mcp_server.git
|
|
11
|
-
Project-URL: Bug Tracker, https://github.com/rishibhushan/jenkins_mcp_server/issues
|
|
12
|
-
Project-URL: Changelog, https://github.com/rishibhushan/jenkins_mcp_server/releases
|
|
13
|
-
Keywords: mcp,jenkins,ai,automation,ci-cd,devops,model-context-protocol,llm
|
|
14
|
-
Classifier: Development Status :: 4 - Beta
|
|
15
|
-
Classifier: Intended Audience :: Developers
|
|
16
|
-
Classifier: Intended Audience :: System Administrators
|
|
17
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
-
Classifier: Operating System :: OS Independent
|
|
19
|
-
Classifier: Programming Language :: Python :: 3
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
-
Classifier: Topic :: Software Development :: Build Tools
|
|
26
|
-
Classifier: Topic :: System :: Systems Administration
|
|
27
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
|
-
Requires-Python: >=3.8
|
|
29
|
-
Description-Content-Type: text/markdown
|
|
30
|
-
Requires-Dist: mcp>=1.0.0
|
|
31
|
-
Requires-Dist: python-jenkins>=1.8.0
|
|
32
|
-
Requires-Dist: requests>=2.28.0
|
|
33
|
-
Requires-Dist: pydantic>=2.0.0
|
|
34
|
-
Requires-Dist: pydantic-settings>=2.0.0
|
|
35
|
-
Requires-Dist: python-dotenv>=1.0.0
|
|
36
|
-
Requires-Dist: urllib3>=2.0.0
|
|
37
|
-
Provides-Extra: dev
|
|
38
|
-
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
39
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
40
|
-
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
41
|
-
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
42
|
-
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
43
|
-
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
44
|
-
Provides-Extra: test
|
|
45
|
-
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
46
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
47
|
-
Requires-Dist: pytest-cov>=4.0.0; extra == "test"
|
|
48
|
-
|
|
49
|
-
# 🧠 Jenkins MCP Server
|
|
50
|
-
|
|
51
|
-
**Jenkins MCP Server** is an AI-enabled Model Context Protocol (MCP) server that exposes Jenkins automation through natural-language commands.
|
|
52
|
-
|
|
53
|
-
Designed to work seamlessly with automation clients such as:
|
|
54
|
-
- 🖥️ **VS Code MCP** - Direct integration with Claude in VS Code
|
|
55
|
-
- 🔌 **Any MCP-compatible client** - Universal compatibility
|
|
56
|
-
|
|
57
|
-
## ✨ About codebase
|
|
58
|
-
|
|
59
|
-
- ✅ **Codebase** - cleaner, more maintainable
|
|
60
|
-
- ✅ **Error messages** - Know exactly what's wrong and how to fix it
|
|
61
|
-
- ✅ **Flexible configuration** - Multiple ways to configure (VS Code, .env, environment)
|
|
62
|
-
- ✅ **Cross-platform** - Seamless support for Windows, macOS, and Linux
|
|
63
|
-
- ✅ **Logging** - Professional logging with `--verbose` flag
|
|
64
|
-
- ✅ **Dependency management** - Automatic detection and installation
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## 📦 Features
|
|
69
|
-
|
|
70
|
-
This project includes:
|
|
71
|
-
- 🐍 Python backend powered by `python-jenkins`
|
|
72
|
-
- 📦 Node.js `npx` wrapper for zero-install execution
|
|
73
|
-
- 🔄 Automatic virtual environment creation + dependency installation
|
|
74
|
-
- 🌐 Corporate proxy/certificate auto-detection support
|
|
75
|
-
- 🪟 Windows, macOS, and Linux support
|
|
76
|
-
- 🛠️ **20 Jenkins management tools**
|
|
77
|
-
|
|
78
|
-
### 🧩 Build Operations
|
|
79
|
-
| Tool Name | Description | Required Fields | Optional Fields |
|
|
80
|
-
|---|---|---|---|
|
|
81
|
-
| `trigger-build` | Trigger a Jenkins job build with optional parameters | `job_name` | `parameters` |
|
|
82
|
-
| `stop-build` | Stop a running Jenkins build | `job_name`, `build_number` | *(none)* |
|
|
83
|
-
|
|
84
|
-
### 📊 Job Information
|
|
85
|
-
| Tool Name | Description | Required Fields | Optional Fields |
|
|
86
|
-
|---|---|---|---|
|
|
87
|
-
| `list-jobs` | List all Jenkins jobs with optional filtering | *(none)* | `filter` |
|
|
88
|
-
| `get-job-details` | Get detailed information about a Jenkins job | `job_name` | *(none)* |
|
|
89
|
-
|
|
90
|
-
### 🛠️ Build Information
|
|
91
|
-
| Tool Name | Description | Required Fields | Optional Fields |
|
|
92
|
-
|---|---|---|---|
|
|
93
|
-
| `get-build-info` | Get information about a specific build | `job_name`, `build_number` | *(none)* |
|
|
94
|
-
| `get-build-console` | Get console output from a build | `job_name`, `build_number` | *(none)* |
|
|
95
|
-
| `get-last-build-number` | Get the last build number for a job | `job_name` | *(none)* |
|
|
96
|
-
| `get-last-build-timestamp` | Get the timestamp of the last build | `job_name` | *(none)* |
|
|
97
|
-
|
|
98
|
-
### 🧩 Job Management
|
|
99
|
-
| Tool Name | Description | Required Fields | Optional Fields |
|
|
100
|
-
|---|---|---|---|
|
|
101
|
-
| `create-job` | Create a new Jenkins job with XML configuration | `job_name`, `config_xml` | *(none)* |
|
|
102
|
-
| `create-job-from-copy` | Create a new job by copying an existing one | `new_job_name`, `source_job_name` | *(none)* |
|
|
103
|
-
| `create-job-from-data` | Create a job from structured data (auto-generated XML) | `job_name`, `config_data` | `root_tag` |
|
|
104
|
-
| `delete-job` | Delete an existing job | `job_name` | *(none)* |
|
|
105
|
-
| `enable-job` | Enable a disabled Jenkins job | `job_name` | *(none)* |
|
|
106
|
-
| `disable-job` | Disable a Jenkins job | `job_name` | *(none)* |
|
|
107
|
-
| `rename-job` | Rename an existing Jenkins job | `job_name`, `new_name` | *(none)* |
|
|
108
|
-
|
|
109
|
-
### ⚙️ Job Configuration
|
|
110
|
-
| Tool Name | Description | Required Fields | Optional Fields |
|
|
111
|
-
|---|---|---|---|
|
|
112
|
-
| `get-job-config` | Fetch job XML configuration | `job_name` | *(none)* |
|
|
113
|
-
| `update-job-config` | Update job XML configuration | `job_name`, `config_xml` | *(none)* |
|
|
114
|
-
|
|
115
|
-
### 🖥️ System Information
|
|
116
|
-
| Tool Name | Description | Required Fields | Optional Fields |
|
|
117
|
-
|---|---|---|---|
|
|
118
|
-
| `get-queue-info` | Get Jenkins build queue info | *(none)* | *(none)* |
|
|
119
|
-
| `list-nodes` | List all Jenkins nodes | *(none)* | *(none)* |
|
|
120
|
-
| `get-node-info` | Get information about a Jenkins node | `node_name` | *(none)* |
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## 🚀 Quick Start
|
|
125
|
-
|
|
126
|
-
### Prerequisites
|
|
127
|
-
|
|
128
|
-
**Node.js** (v14 or higher) is required for the npx wrapper.
|
|
129
|
-
|
|
130
|
-
<details>
|
|
131
|
-
<summary><b>Windows Installation</b></summary>
|
|
132
|
-
|
|
133
|
-
```powershell
|
|
134
|
-
# Using winget (recommended)
|
|
135
|
-
winget install OpenJS.NodeJS.LTS
|
|
136
|
-
|
|
137
|
-
# Verify installation
|
|
138
|
-
node -v
|
|
139
|
-
npm -v
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Or download manually from https://nodejs.org/
|
|
143
|
-
</details>
|
|
144
|
-
|
|
145
|
-
<details>
|
|
146
|
-
<summary><b>macOS Installation</b></summary>
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
# Install nvm (Node Version Manager)
|
|
150
|
-
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
|
151
|
-
|
|
152
|
-
# Reload shell
|
|
153
|
-
source ~/.nvm/nvm.sh
|
|
154
|
-
|
|
155
|
-
# Install Node LTS
|
|
156
|
-
nvm install --lts
|
|
157
|
-
nvm use --lts
|
|
158
|
-
|
|
159
|
-
# Verify installation
|
|
160
|
-
node -v
|
|
161
|
-
npm -v
|
|
162
|
-
```
|
|
163
|
-
</details>
|
|
164
|
-
|
|
165
|
-
<details>
|
|
166
|
-
<summary><b>Linux Installation</b></summary>
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
# Ubuntu/Debian
|
|
170
|
-
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
|
|
171
|
-
sudo apt-get install -y nodejs
|
|
172
|
-
|
|
173
|
-
# Fedora/RHEL
|
|
174
|
-
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
|
|
175
|
-
sudo dnf install -y nodejs
|
|
176
|
-
|
|
177
|
-
# Verify installation
|
|
178
|
-
node -v
|
|
179
|
-
npm -v
|
|
180
|
-
```
|
|
181
|
-
</details>
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## ⚙️ Configuration
|
|
186
|
-
|
|
187
|
-
Jenkins MCP Server supports multiple configuration methods. Choose the one that works best for you:
|
|
188
|
-
|
|
189
|
-
### Option 1: VS Code Settings (Recommended)
|
|
190
|
-
|
|
191
|
-
Add to your VS Code `settings.json`:
|
|
192
|
-
|
|
193
|
-
```json
|
|
194
|
-
{
|
|
195
|
-
"jenkins-mcp-server": {
|
|
196
|
-
"jenkins": {
|
|
197
|
-
"url": "http://jenkins.example.com:8080",
|
|
198
|
-
"username": "your-username",
|
|
199
|
-
"token": "your-api-token"
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
**Where to find settings.json:**
|
|
206
|
-
- **Windows**: `%APPDATA%\Code\User\settings.json`
|
|
207
|
-
- **macOS**: `~/Library/Application Support/Code/User/settings.json`
|
|
208
|
-
- **Linux**: `~/.config/Code/User/settings.json`
|
|
209
|
-
|
|
210
|
-
### Option 2: Environment File (.env)
|
|
211
|
-
|
|
212
|
-
Rename `.env.template` to `.env`
|
|
213
|
-
```bash
|
|
214
|
-
cp .env.template .env
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
In the `.env` file in your project directory:
|
|
218
|
-
|
|
219
|
-
```bash
|
|
220
|
-
JENKINS_URL=http://jenkins.example.com:8080
|
|
221
|
-
JENKINS_USERNAME=your-username
|
|
222
|
-
JENKINS_TOKEN=your-api-token
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
**Note**: Use API token instead of password for better security.
|
|
226
|
-
|
|
227
|
-
### Option 3: Environment Variables
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
# Linux/macOS
|
|
231
|
-
export JENKINS_URL=http://jenkins.example.com:8080
|
|
232
|
-
export JENKINS_USERNAME=your-username
|
|
233
|
-
export JENKINS_TOKEN=your-api-token
|
|
234
|
-
|
|
235
|
-
# Windows (PowerShell)
|
|
236
|
-
$env:JENKINS_URL="http://jenkins.example.com:8080"
|
|
237
|
-
$env:JENKINS_USERNAME="your-username"
|
|
238
|
-
$env:JENKINS_TOKEN="your-api-token"
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### Configuration Priority
|
|
242
|
-
|
|
243
|
-
Settings are loaded in this order (later overrides earlier):
|
|
244
|
-
1. Default `.env` file
|
|
245
|
-
2. Environment variables
|
|
246
|
-
3. Custom `.env` file (via `--env-file`)
|
|
247
|
-
4. VS Code settings
|
|
248
|
-
5. Direct parameters
|
|
249
|
-
|
|
250
|
-
### Getting Your Jenkins API Token
|
|
251
|
-
|
|
252
|
-
1. Log into Jenkins
|
|
253
|
-
2. Click your name (top right) → **Configure**
|
|
254
|
-
3. Scroll to **API Token** section
|
|
255
|
-
4. Click **Add new Token**
|
|
256
|
-
5. Give it a name and click **Generate**
|
|
257
|
-
6. Copy the token (⚠️ it won't be shown again!)
|
|
258
|
-
|
|
259
|
-
---
|
|
260
|
-
|
|
261
|
-
## 🚀 Installation/Running the Server
|
|
262
|
-
|
|
263
|
-
### Option 1: Using npx (No Installation Required)
|
|
264
|
-
```bash
|
|
265
|
-
npx @rishibhushan/jenkins-mcp-server --env-file .env
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Option 2: Global Installation
|
|
269
|
-
```bash
|
|
270
|
-
# Install globally
|
|
271
|
-
npm install -g @rishibhushan/jenkins-mcp-server
|
|
272
|
-
|
|
273
|
-
# Run
|
|
274
|
-
jenkins-mcp-server --env-file .env
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### Option 3: From GitHub
|
|
278
|
-
```bash
|
|
279
|
-
npx github:rishibhushan/jenkins_mcp_server --env-file .env
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
[//]: # ([](https://www.npmjs.com/package/@rishibhushan/jenkins-mcp-server))
|
|
283
|
-
|
|
284
|
-
[//]: # ([](https://www.npmjs.com/package/@rishibhushan/jenkins-mcp-server))
|
|
285
|
-
|
|
286
|
-
---
|
|
287
|
-
|
|
288
|
-
This automatically:
|
|
289
|
-
- ✅ Installs all dependencies
|
|
290
|
-
- ✅ Starts the Jenkins MCP server
|
|
291
|
-
|
|
292
|
-
### Method 2: Direct Python Execution
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
# Create virtual environment
|
|
296
|
-
python3 -m venv .venv
|
|
297
|
-
|
|
298
|
-
# Activate virtual environment
|
|
299
|
-
# Linux/macOS:
|
|
300
|
-
source .venv/bin/activate
|
|
301
|
-
# Windows:
|
|
302
|
-
.venv\Scripts\activate
|
|
303
|
-
|
|
304
|
-
# Install dependencies
|
|
305
|
-
pip install -r requirements.txt
|
|
306
|
-
|
|
307
|
-
# Run the server
|
|
308
|
-
python -m jenkins_mcp_server --env-file /path/to/.env
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
### Command-Line Options
|
|
312
|
-
|
|
313
|
-
```
|
|
314
|
-
jenkins-mcp-server [options]
|
|
315
|
-
|
|
316
|
-
Options:
|
|
317
|
-
--env-file PATH Path to custom .env file
|
|
318
|
-
--verbose, -v Enable verbose/debug logging
|
|
319
|
-
--no-vscode Skip loading VS Code settings
|
|
320
|
-
--version Show version information
|
|
321
|
-
--help, -h Show help message
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
---
|
|
325
|
-
|
|
326
|
-
## 🔌 Integration Examples
|
|
327
|
-
|
|
328
|
-
### VS Code MCP Client
|
|
329
|
-
|
|
330
|
-
Add to your VS Code `mcp.json`:
|
|
331
|
-
|
|
332
|
-
```json
|
|
333
|
-
{
|
|
334
|
-
"servers": {
|
|
335
|
-
"jenkins": {
|
|
336
|
-
"type": "stdio",
|
|
337
|
-
"command": "npx",
|
|
338
|
-
"args": [
|
|
339
|
-
"@rishibhushan/jenkins-mcp-server"
|
|
340
|
-
]
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
Or `setting.json` with `.env` file and proxy settings:
|
|
347
|
-
```json
|
|
348
|
-
{
|
|
349
|
-
"mcp": {
|
|
350
|
-
"servers": {
|
|
351
|
-
"jenkins": {
|
|
352
|
-
"type": "stdio",
|
|
353
|
-
"command": "npx",
|
|
354
|
-
"args": [
|
|
355
|
-
"@rishibhushan/jenkins-mcp-server",
|
|
356
|
-
"--verbose",
|
|
357
|
-
"--env-file",
|
|
358
|
-
"/path/to/.env"
|
|
359
|
-
],
|
|
360
|
-
"env": {
|
|
361
|
-
"HTTP_PROXY": "http://proxy.example.com:8080",
|
|
362
|
-
"HTTPS_PROXY": "http://proxy.example.com:8080",
|
|
363
|
-
"NO_PROXY": "localhost,127.0.0.1,.example.com"
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
### Claude Desktop
|
|
372
|
-
|
|
373
|
-
Add to `claude_desktop_config.json`:
|
|
374
|
-
|
|
375
|
-
```json
|
|
376
|
-
{
|
|
377
|
-
"mcpServers": {
|
|
378
|
-
"jenkins": {
|
|
379
|
-
"command": "npx",
|
|
380
|
-
"args": [
|
|
381
|
-
"@rishibhushan/jenkins-mcp-server",
|
|
382
|
-
"--env-file",
|
|
383
|
-
"/path/to/.env"
|
|
384
|
-
]
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
**Where to find claude_desktop_config.json:**
|
|
391
|
-
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
392
|
-
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
393
|
-
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
|
394
|
-
|
|
395
|
-
---
|
|
396
|
-
|
|
397
|
-
## 💡 Usage Examples
|
|
398
|
-
|
|
399
|
-
### Natural Language Commands
|
|
400
|
-
|
|
401
|
-
Once configured, you can use natural language with your MCP client:
|
|
402
|
-
|
|
403
|
-
```
|
|
404
|
-
"List all Jenkins jobs"
|
|
405
|
-
"List jobs with 'backend' in the name" - # Filter jobs containing "backend"
|
|
406
|
-
"Show me all production jobs" - # Filter jobs containing "prod"
|
|
407
|
-
"Show me the last build of my-project"
|
|
408
|
-
"Trigger a build for deploy-prod with parameter env=production"
|
|
409
|
-
"What's in the build queue?"
|
|
410
|
-
"Show me the console output of build #42 for backend-service"
|
|
411
|
-
"Create a new job called test-job by copying prod-job"
|
|
412
|
-
"Disable the old-job"
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
### Programmatic Usage (Python)
|
|
416
|
-
|
|
417
|
-
```python
|
|
418
|
-
from config import get_settings
|
|
419
|
-
from jenkins_client import get_jenkins_client
|
|
420
|
-
|
|
421
|
-
# Load settings
|
|
422
|
-
settings = get_settings()
|
|
423
|
-
|
|
424
|
-
# Create client
|
|
425
|
-
client = get_jenkins_client(settings)
|
|
426
|
-
|
|
427
|
-
# List jobs
|
|
428
|
-
all_jobs = client.get_jobs()
|
|
429
|
-
for job in all_jobs:
|
|
430
|
-
print(f"Job: {job['name']} - Status: {job['color']}")
|
|
431
|
-
|
|
432
|
-
# Filter in Python
|
|
433
|
-
backend_jobs = [job for job in all_jobs if 'backend' in job['name'].lower()]
|
|
434
|
-
|
|
435
|
-
# Trigger a build
|
|
436
|
-
result = client.build_job(
|
|
437
|
-
"my-job",
|
|
438
|
-
parameters={"BRANCH": "main", "ENV": "staging"}
|
|
439
|
-
)
|
|
440
|
-
print(f"Build queued: {result['queue_id']}")
|
|
441
|
-
print(f"Build number: {result['build_number']}")
|
|
442
|
-
|
|
443
|
-
# Get console output
|
|
444
|
-
if result['build_number']:
|
|
445
|
-
output = client.get_build_console_output(
|
|
446
|
-
"my-job",
|
|
447
|
-
result['build_number']
|
|
448
|
-
)
|
|
449
|
-
print(output)
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
---
|
|
453
|
-
|
|
454
|
-
## 🔧 Troubleshooting
|
|
455
|
-
|
|
456
|
-
### Python Not Found
|
|
457
|
-
```
|
|
458
|
-
Error: Python 3 is required but not found.
|
|
459
|
-
```
|
|
460
|
-
**Solution**: Install Python 3.8+ from https://www.python.org/downloads/
|
|
461
|
-
|
|
462
|
-
### Configuration Issues
|
|
463
|
-
```
|
|
464
|
-
ERROR: Jenkins configuration is incomplete!
|
|
465
|
-
```
|
|
466
|
-
**Solution**: Verify you have set `JENKINS_URL`, `JENKINS_USERNAME`, and `JENKINS_TOKEN`
|
|
467
|
-
|
|
468
|
-
Check your configuration:
|
|
469
|
-
```bash
|
|
470
|
-
# View .env file
|
|
471
|
-
cat .env
|
|
472
|
-
|
|
473
|
-
# Check environment variables
|
|
474
|
-
env | grep JENKINS
|
|
475
|
-
|
|
476
|
-
# Check VS Code settings
|
|
477
|
-
cat ~/.config/Code/User/settings.json | grep jenkins
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
### Connection Failed
|
|
481
|
-
```
|
|
482
|
-
Failed to connect to Jenkins at http://localhost:8080
|
|
483
|
-
```
|
|
484
|
-
**Solution**:
|
|
485
|
-
1. Verify Jenkins is running: `curl http://localhost:8080/api/json`
|
|
486
|
-
2. Check firewall settings
|
|
487
|
-
3. Verify URL is correct (include port if needed)
|
|
488
|
-
4. Test authentication credentials
|
|
489
|
-
|
|
490
|
-
### Dependency Installation Failed
|
|
491
|
-
```
|
|
492
|
-
Failed to install dependencies
|
|
493
|
-
```
|
|
494
|
-
**Solution**:
|
|
495
|
-
1. Check internet connection
|
|
496
|
-
2. If behind a proxy, set `HTTP_PROXY` and `HTTPS_PROXY` environment variables
|
|
497
|
-
3. Try manual installation: `.venv/bin/pip install -r requirements.txt`
|
|
498
|
-
|
|
499
|
-
### Enable Debug Logging
|
|
500
|
-
|
|
501
|
-
Run with verbose flag to see detailed logs:
|
|
502
|
-
```bash
|
|
503
|
-
jenkins-mcp-server --verbose
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
---
|
|
507
|
-
|
|
508
|
-
## 🧪 Development & Testing
|
|
509
|
-
|
|
510
|
-
### Run Tests
|
|
511
|
-
```bash
|
|
512
|
-
# Install test dependencies
|
|
513
|
-
pip install pytest pytest-asyncio
|
|
514
|
-
|
|
515
|
-
# Run tests
|
|
516
|
-
pytest tests/ -v
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
### Build Package
|
|
520
|
-
```bash
|
|
521
|
-
# Install build tools
|
|
522
|
-
pip install build
|
|
523
|
-
|
|
524
|
-
# Build distribution
|
|
525
|
-
python -m build
|
|
526
|
-
|
|
527
|
-
# This creates:
|
|
528
|
-
# - dist/jenkins_mcp_server-1.0.0.tar.gz
|
|
529
|
-
# - dist/jenkins_mcp_server-1.0.0-py3-none-any.whl
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
### Local Development
|
|
533
|
-
```bash
|
|
534
|
-
# Clone repository
|
|
535
|
-
git clone https://github.com/rishibhushan/jenkins_mcp_server.git
|
|
536
|
-
cd jenkins_mcp_server
|
|
537
|
-
|
|
538
|
-
# Install in editable mode
|
|
539
|
-
pip install -e .
|
|
540
|
-
|
|
541
|
-
# Make changes, then test
|
|
542
|
-
jenkins-mcp-server --verbose
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
---
|
|
546
|
-
|
|
547
|
-
## 📚 Project Structure
|
|
548
|
-
|
|
549
|
-
```
|
|
550
|
-
jenkins_mcp_server/
|
|
551
|
-
├── bin/
|
|
552
|
-
│ └── jenkins-mcp.js # Node.js wrapper script
|
|
553
|
-
├── src/
|
|
554
|
-
│ └── jenkins_mcp_server/
|
|
555
|
-
│ ├── __init__.py # Package initialization & main()
|
|
556
|
-
│ ├── __main__.py # Entry point for python -m
|
|
557
|
-
│ ├── config.py # Configuration management
|
|
558
|
-
│ ├── jenkins_client.py # Jenkins API client
|
|
559
|
-
│ └── server.py # MCP server implementation
|
|
560
|
-
├── tests/ # Test suite
|
|
561
|
-
├── requirements.txt # Python dependencies
|
|
562
|
-
├── package.json # Node.js configuration
|
|
563
|
-
└── README.md # This file
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
---
|
|
567
|
-
|
|
568
|
-
## 🔒 Security Best Practices
|
|
569
|
-
|
|
570
|
-
1. **Never commit `.env` files** - Add to `.gitignore`
|
|
571
|
-
2. **Use API tokens**, not passwords - More secure and revocable
|
|
572
|
-
3. **Rotate tokens regularly** - Generate new tokens periodically
|
|
573
|
-
4. **Use environment-specific configs** - Separate dev/staging/prod credentials
|
|
574
|
-
5. **Review permissions** - Only grant necessary Jenkins permissions
|
|
575
|
-
6. **Keep dependencies updated** - Run `pip install --upgrade -r requirements.txt`
|
|
576
|
-
|
|
577
|
-
---
|
|
578
|
-
|
|
579
|
-
## 🤝 Contributing
|
|
580
|
-
|
|
581
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
582
|
-
|
|
583
|
-
1. Fork the repository
|
|
584
|
-
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
585
|
-
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
586
|
-
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
587
|
-
5. Open a Pull Request
|
|
588
|
-
|
|
589
|
-
---
|
|
590
|
-
|
|
591
|
-
## 📝 License
|
|
592
|
-
|
|
593
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
594
|
-
|
|
595
|
-
---
|
|
596
|
-
|
|
597
|
-
## 🙏 Acknowledgments
|
|
598
|
-
|
|
599
|
-
- Built on the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/)
|
|
600
|
-
- Powered by [python-jenkins](https://python-jenkins.readthedocs.io/)
|
|
601
|
-
- Inspired by the need for AI-powered DevOps automation
|
|
602
|
-
|
|
603
|
-
---
|
|
604
|
-
|
|
605
|
-
## 📞 Support
|
|
606
|
-
|
|
607
|
-
- **Issues**: https://github.com/rishibhushan/jenkins_mcp_server/issues
|
|
608
|
-
- **Discussions**: https://github.com/rishibhushan/jenkins_mcp_server/discussions
|
|
609
|
-
|
|
610
|
-
---
|
|
611
|
-
|
|
612
|
-
## 🗺️ Roadmap
|
|
613
|
-
|
|
614
|
-
- [ ] Add pipeline support
|
|
615
|
-
- [ ] Multi-Jenkins instance management
|
|
616
|
-
- [ ] Build artifact management
|
|
617
|
-
- [ ] Advanced filtering and search
|
|
618
|
-
- [ ] Real-time build monitoring
|
|
619
|
-
- [ ] Webhook integration
|
|
620
|
-
- [ ] Docker container support
|
|
621
|
-
|
|
622
|
-
---
|
|
623
|
-
|
|
624
|
-
**Made with ❤️ by [Rishi Bhushan](https://github.com/rishibhushan)**
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
README.md
|
|
2
|
-
pyproject.toml
|
|
3
|
-
src/jenkins_mcp_server/__init__.py
|
|
4
|
-
src/jenkins_mcp_server/__main__.py
|
|
5
|
-
src/jenkins_mcp_server/config.py
|
|
6
|
-
src/jenkins_mcp_server/jenkins_client.py
|
|
7
|
-
src/jenkins_mcp_server/server.py
|
|
8
|
-
src/jenkins_mcp_server.egg-info/PKG-INFO
|
|
9
|
-
src/jenkins_mcp_server.egg-info/SOURCES.txt
|
|
10
|
-
src/jenkins_mcp_server.egg-info/dependency_links.txt
|
|
11
|
-
src/jenkins_mcp_server.egg-info/entry_points.txt
|
|
12
|
-
src/jenkins_mcp_server.egg-info/requires.txt
|
|
13
|
-
src/jenkins_mcp_server.egg-info/top_level.txt
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
mcp>=1.0.0
|
|
2
|
-
python-jenkins>=1.8.0
|
|
3
|
-
requests>=2.28.0
|
|
4
|
-
pydantic>=2.0.0
|
|
5
|
-
pydantic-settings>=2.0.0
|
|
6
|
-
python-dotenv>=1.0.0
|
|
7
|
-
urllib3>=2.0.0
|
|
8
|
-
|
|
9
|
-
[dev]
|
|
10
|
-
pytest>=7.0.0
|
|
11
|
-
pytest-asyncio>=0.21.0
|
|
12
|
-
pytest-cov>=4.0.0
|
|
13
|
-
black>=23.0.0
|
|
14
|
-
ruff>=0.1.0
|
|
15
|
-
mypy>=1.0.0
|
|
16
|
-
|
|
17
|
-
[test]
|
|
18
|
-
pytest>=7.0.0
|
|
19
|
-
pytest-asyncio>=0.21.0
|
|
20
|
-
pytest-cov>=4.0.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
jenkins_mcp_server
|