sunholo 0.144.7__py3-none-any.whl → 0.144.9__py3-none-any.whl

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.
@@ -353,7 +353,6 @@ class VACRoutesFastAPI:
353
353
  additional_routes: Optional[List[Dict]] = None,
354
354
  mcp_servers: Optional[List[Dict[str, Any]]] = None,
355
355
  add_langfuse_eval: bool = True,
356
- enable_mcp_server: bool = False,
357
356
  enable_a2a_agent: bool = False,
358
357
  a2a_vac_names: Optional[List[str]] = None
359
358
  ):
@@ -371,9 +370,6 @@ class VACRoutesFastAPI:
371
370
  mcp_servers: List of external MCP server configurations to connect to:
372
371
  [{"name": "server-name", "command": "python", "args": ["server.py"]}]
373
372
  add_langfuse_eval: Whether to enable Langfuse evaluation and tracing
374
- enable_mcp_server: Whether to enable the MCP server at /mcp endpoint for
375
- Claude Desktop/Code integration. When True, automatically
376
- includes built-in VAC tools and supports custom tool registration.
377
373
  enable_a2a_agent: Whether to enable A2A (Agent-to-Agent) protocol endpoints
378
374
  a2a_vac_names: List of VAC names available for A2A agent interactions
379
375
 
@@ -398,7 +394,7 @@ class VACRoutesFastAPI:
398
394
 
399
395
  ## MCP Server Integration
400
396
 
401
- When enable_mcp_server=True, the following happens:
397
+ When VACMCPServer is available, the following happens automatically:
402
398
  1. MCP server is mounted at /mcp endpoint
403
399
  2. Built-in VAC tools are automatically registered:
404
400
  - vac_stream, vac_query, list_available_vacs, get_vac_info
@@ -452,13 +448,13 @@ class VACRoutesFastAPI:
452
448
  self.mcp_client_manager = MCPClientManager() if MCPClientManager else None
453
449
  self._mcp_initialized = False
454
450
 
455
- # MCP server initialization
456
- self.enable_mcp_server = enable_mcp_server
451
+ # MCP server initialization - automatically enabled if VACMCPServer is available
457
452
  self.vac_mcp_server = None
458
453
  self._custom_mcp_tools = []
459
454
  self._custom_mcp_resources = []
460
455
 
461
- if self.enable_mcp_server and VACMCPServer:
456
+ # Enable MCP server if VACMCPServer is available
457
+ if VACMCPServer:
462
458
  self.vac_mcp_server = VACMCPServer(
463
459
  server_name="sunholo-vac-fastapi-server",
464
460
  include_vac_tools=True
@@ -497,7 +493,7 @@ class VACRoutesFastAPI:
497
493
  stream_interpreter: Streaming interpreter function
498
494
  vac_interpreter: Non-streaming interpreter function
499
495
  app_lifespan: Optional app lifespan context manager
500
- **kwargs: Additional arguments passed to VACRoutesFastAPI (except enable_mcp_server)
496
+ **kwargs: Additional arguments passed to VACRoutesFastAPI
501
497
 
502
498
  Returns:
503
499
  Tuple of (FastAPI app, VACRoutesFastAPI instance)
@@ -569,7 +565,6 @@ class VACRoutesFastAPI:
569
565
  app,
570
566
  stream_interpreter=stream_interpreter,
571
567
  vac_interpreter=vac_interpreter,
572
- enable_mcp_server=False, # Don't enable again since we manually mounted
573
568
  **kwargs
574
569
  )
575
570
 
@@ -589,7 +584,6 @@ class VACRoutesFastAPI:
589
584
  app,
590
585
  stream_interpreter=stream_interpreter,
591
586
  vac_interpreter=vac_interpreter,
592
- enable_mcp_server=False,
593
587
  **kwargs
594
588
  )
595
589
 
@@ -694,7 +688,7 @@ class VACRoutesFastAPI:
694
688
  self.app.post("/mcp/resources/read")(self.handle_mcp_read_resource)
695
689
 
696
690
  # MCP server endpoint - mount the FastMCP app
697
- if self.enable_mcp_server and self.vac_mcp_server:
691
+ if self.vac_mcp_server:
698
692
  try:
699
693
  mcp_app = self.vac_mcp_server.get_http_app()
700
694
 
@@ -713,8 +707,7 @@ class VACRoutesFastAPI:
713
707
  "The FastAPI app must be created with the MCP lifespan.\n\n"
714
708
  "Quick fix: Use the helper method:\n"
715
709
  " app, vac_routes = VACRoutesFastAPI.create_app_with_mcp(\n"
716
- " stream_interpreter=your_interpreter,\n"
717
- " enable_mcp_server=True\n"
710
+ " stream_interpreter=your_interpreter\n"
718
711
  " )\n\n"
719
712
  "Or manually configure the lifespan - see documentation for details."
720
713
  )
@@ -727,6 +720,10 @@ class VACRoutesFastAPI:
727
720
  log.error(f"Failed to mount MCP server: {e}")
728
721
  raise RuntimeError(f"MCP server initialization failed: {e}") from e
729
722
 
723
+ # MCP debug endpoint - add if we have a MCP server instance
724
+ if self.vac_mcp_server:
725
+ self.app.get("/debug/mcp")(self.handle_mcp_debug)
726
+
730
727
  # A2A agent endpoints
731
728
  if self.enable_a2a_agent:
732
729
  self.app.get("/.well-known/agent.json")(self.handle_a2a_agent_card)
@@ -1516,4 +1513,116 @@ class VACRoutesFastAPI:
1516
1513
  """
1517
1514
  if self.vac_mcp_server:
1518
1515
  return self.vac_mcp_server.list_resources()
1519
- return []
1516
+ return []
1517
+
1518
+ async def handle_mcp_debug(self):
1519
+ """
1520
+ Debug endpoint to check MCP server status and list tools.
1521
+
1522
+ Returns:
1523
+ JSON with MCP server status, tools list, and diagnostic information
1524
+ """
1525
+ import json
1526
+
1527
+ has_mcp = self.vac_mcp_server is not None
1528
+ mcp_tools = []
1529
+ mcp_response = None
1530
+
1531
+ # Try to call the MCP endpoint the same way clients do
1532
+ if has_mcp:
1533
+ try:
1534
+ # Make internal request to MCP server to get tools
1535
+ import httpx
1536
+
1537
+ # Get the base URL from the current request
1538
+ from fastapi import Request
1539
+ from starlette.requests import Request as StarletteRequest
1540
+
1541
+ # Try common ports since we don't have request context
1542
+ ports_to_try = [8000, 8001, 8080, 3000, 1956]
1543
+ successful_response = None
1544
+
1545
+ for port in ports_to_try:
1546
+ try:
1547
+ base_url = f"http://localhost:{port}"
1548
+ async with httpx.AsyncClient(timeout=2.0) as client:
1549
+ response = await client.post(
1550
+ f"{base_url}/mcp/mcp",
1551
+ json={
1552
+ "jsonrpc": "2.0",
1553
+ "id": 1,
1554
+ "method": "tools/list"
1555
+ },
1556
+ headers={
1557
+ "Content-Type": "application/json",
1558
+ "Accept": "application/json, text/event-stream"
1559
+ }
1560
+ )
1561
+
1562
+ if response.status_code == 200:
1563
+ successful_response = response
1564
+ break # Found working port
1565
+ except (httpx.ConnectError, httpx.TimeoutException):
1566
+ continue # Try next port
1567
+ except Exception:
1568
+ continue # Try next port
1569
+
1570
+ if successful_response:
1571
+ # Parse SSE (Server-Sent Events) response
1572
+ text = successful_response.text
1573
+ for line in text.split('\n'):
1574
+ if line.startswith('data: '):
1575
+ # Extract JSON from the data line
1576
+ json_str = line[6:] # Remove 'data: ' prefix
1577
+ try:
1578
+ mcp_response = json.loads(json_str)
1579
+ if "result" in mcp_response and "tools" in mcp_response["result"]:
1580
+ for tool in mcp_response["result"]["tools"]:
1581
+ mcp_tools.append({
1582
+ "name": tool.get("name"),
1583
+ "description": tool.get("description", "No description")[:100] + "..." if len(tool.get("description", "")) > 100 else tool.get("description", "No description")
1584
+ })
1585
+ break # We found the data we need
1586
+ except json.JSONDecodeError:
1587
+ continue
1588
+ else:
1589
+ mcp_response = {
1590
+ "error": "Could not connect to MCP server on any common port",
1591
+ "ports_tried": ports_to_try
1592
+ }
1593
+
1594
+ except Exception as e:
1595
+ log.error(f"Error calling MCP endpoint in debug: {e}")
1596
+ mcp_response = {"error": str(e)}
1597
+
1598
+ # Fallback: try to get tools from internal MCP server state
1599
+ try:
1600
+ # Get tools from the FastMCP server directly
1601
+ if hasattr(self.vac_mcp_server, 'server'):
1602
+ mcp_server = self.vac_mcp_server.server
1603
+ if hasattr(mcp_server, '_tools'):
1604
+ for tool_name, tool_func in mcp_server._tools.items():
1605
+ mcp_tools.append({
1606
+ "name": tool_name,
1607
+ "description": getattr(tool_func, '__doc__', 'No description') or 'No description'
1608
+ })
1609
+ except Exception as inner_e:
1610
+ log.error(f"Error getting MCP tools from internal state: {inner_e}")
1611
+
1612
+ # Check for pending tools that haven't been registered yet
1613
+ pending_tools = len(self._custom_mcp_tools) if hasattr(self, '_custom_mcp_tools') else 0
1614
+
1615
+ return {
1616
+ "mcp_enabled": has_mcp,
1617
+ "has_mcp_server": has_mcp,
1618
+ "mcp_tools_count": len(mcp_tools),
1619
+ "mcp_tools": [tool["name"] for tool in mcp_tools] if mcp_tools else [],
1620
+ "tool_details": mcp_tools,
1621
+ "pending_tools": pending_tools,
1622
+ "message": f"MCP server is available at /mcp endpoint with {len(mcp_tools)} tools" if has_mcp and mcp_tools else "MCP server is available at /mcp endpoint" if has_mcp else "MCP server not configured",
1623
+ "debug_info": {
1624
+ "mcp_server_type": type(self.vac_mcp_server).__name__ if self.vac_mcp_server else None,
1625
+ "has_custom_tools": len(self._custom_mcp_tools) > 0 if hasattr(self, '_custom_mcp_tools') else False,
1626
+ "has_custom_resources": len(self._custom_mcp_resources) > 0 if hasattr(self, '_custom_mcp_resources') else False
1627
+ }
1628
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.144.7
3
+ Version: 0.144.9
4
4
  Summary: AI DevOps - a package to help deploy GenAI to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
@@ -16,7 +16,7 @@ sunholo/agents/swagger.py,sha256=2tzGmpveUMmTREykZvVnDj3j295wyOMu7mUFDnXdY3c,106
16
16
  sunholo/agents/fastapi/__init__.py,sha256=f7x7kiEjaNyBiOwJHLJ4vdOiePqkXdI52sIAAHtS-ms,141
17
17
  sunholo/agents/fastapi/base.py,sha256=W-cyF8ZDUH40rc-c-Apw3-_8IIi2e4Y9qRtnoVnsc1Q,2521
18
18
  sunholo/agents/fastapi/qna_routes.py,sha256=lKHkXPmwltu9EH3RMwmD153-J6pE7kWQ4BhBlV3to-s,3864
19
- sunholo/agents/fastapi/vac_routes.py,sha256=FpvKC8zf4lEWr7HEMi-kMafkQYO7liyCcpwKbuRkS9g,60953
19
+ sunholo/agents/fastapi/vac_routes.py,sha256=HrSzIHeNQI6mgNDf3tlSugKyOViXngUG5uTEimPMtLo,66479
20
20
  sunholo/agents/flask/__init__.py,sha256=dEoByI3gDNUOjpX1uVKP7uPjhfFHJubbiaAv3xLopnk,63
21
21
  sunholo/agents/flask/base.py,sha256=vnpxFEOnCmt9humqj-jYPLfJcdwzsop9NorgkJ-tSaU,1756
22
22
  sunholo/agents/flask/vac_routes.py,sha256=kaPUDyIH5KhCgeCEtag97qErGVZfqpY1ZEiX3y1_r-s,57505
@@ -182,9 +182,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
182
182
  sunholo/vertex/memory_tools.py,sha256=tBZxqVZ4InTmdBvLlOYwoSEWu4-kGquc-gxDwZCC4FA,7667
183
183
  sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
184
184
  sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
185
- sunholo-0.144.7.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
186
- sunholo-0.144.7.dist-info/METADATA,sha256=zXKrjWDwtd_bxZ4ff7VYkCy47TN9sLNY4X5DX-usrLc,18700
187
- sunholo-0.144.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
188
- sunholo-0.144.7.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
189
- sunholo-0.144.7.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
190
- sunholo-0.144.7.dist-info/RECORD,,
185
+ sunholo-0.144.9.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
186
+ sunholo-0.144.9.dist-info/METADATA,sha256=8gHM6nGq0fk-W-u2-gmnGLlsNbbLmAiDsGrYpPsYXc0,18700
187
+ sunholo-0.144.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
188
+ sunholo-0.144.9.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
189
+ sunholo-0.144.9.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
190
+ sunholo-0.144.9.dist-info/RECORD,,