@rishibhushan/jenkins-mcp-server 1.1.0 → 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.
@@ -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
- # Test connection
76
- self._test_connection()
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(settings: Optional[JenkinsSettings] = None) -> JenkinsClient:
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
- client = get_jenkins_client(get_settings())
126
- jobs = client.get_jobs()
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
  ]