sunholo 0.143.11__py3-none-any.whl → 0.143.14__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.
- sunholo/agents/flask/vac_routes.py +24 -1
- sunholo/mcp/cli.py +28 -0
- sunholo/mcp/stdio_http_bridge.py +93 -0
- {sunholo-0.143.11.dist-info → sunholo-0.143.14.dist-info}/METADATA +4 -3
- {sunholo-0.143.11.dist-info → sunholo-0.143.14.dist-info}/RECORD +9 -8
- {sunholo-0.143.11.dist-info → sunholo-0.143.14.dist-info}/WHEEL +0 -0
- {sunholo-0.143.11.dist-info → sunholo-0.143.14.dist-info}/entry_points.txt +0 -0
- {sunholo-0.143.11.dist-info → sunholo-0.143.14.dist-info}/licenses/LICENSE.txt +0 -0
- {sunholo-0.143.11.dist-info → sunholo-0.143.14.dist-info}/top_level.txt +0 -0
@@ -1036,7 +1036,30 @@ if __name__ == "__main__":
|
|
1036
1036
|
|
1037
1037
|
try:
|
1038
1038
|
# Handle different MCP methods
|
1039
|
-
if method == "
|
1039
|
+
if method == "initialize":
|
1040
|
+
# Handle MCP protocol initialization
|
1041
|
+
protocol_version = params.get("protocolVersion", "2025-06-18")
|
1042
|
+
capabilities = params.get("capabilities", {})
|
1043
|
+
client_info = params.get("clientInfo", {})
|
1044
|
+
|
1045
|
+
log.info(f"MCP client initializing: {client_info} with protocol version: {protocol_version}")
|
1046
|
+
|
1047
|
+
return {
|
1048
|
+
"jsonrpc": "2.0",
|
1049
|
+
"result": {
|
1050
|
+
"protocolVersion": "2025-06-18",
|
1051
|
+
"capabilities": {
|
1052
|
+
"tools": {}
|
1053
|
+
},
|
1054
|
+
"serverInfo": {
|
1055
|
+
"name": "sunholo-vac-server",
|
1056
|
+
"version": sunholo_version()
|
1057
|
+
}
|
1058
|
+
},
|
1059
|
+
"id": request_id
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
elif method == "tools/list":
|
1040
1063
|
# Create mock tools list based on VACMCPServer capabilities
|
1041
1064
|
tools = [
|
1042
1065
|
{
|
sunholo/mcp/cli.py
CHANGED
@@ -281,6 +281,25 @@ def cli_mcp(args):
|
|
281
281
|
logger.error(f"Error running MCP server: {str(e)}")
|
282
282
|
raise
|
283
283
|
|
284
|
+
def cli_mcp_bridge(args):
|
285
|
+
"""CLI handler for the MCP bridge command"""
|
286
|
+
try:
|
287
|
+
from .stdio_http_bridge import run_bridge
|
288
|
+
|
289
|
+
http_url = args.url
|
290
|
+
logger.info(f"Starting MCP stdio-to-HTTP bridge for {http_url}")
|
291
|
+
|
292
|
+
if console:
|
293
|
+
console.print(f"Starting MCP bridge to {http_url}...")
|
294
|
+
|
295
|
+
asyncio.run(run_bridge(http_url))
|
296
|
+
|
297
|
+
except KeyboardInterrupt:
|
298
|
+
logger.info("Bridge stopped by user")
|
299
|
+
except Exception as e:
|
300
|
+
logger.error(f"Error running MCP bridge: {str(e)}")
|
301
|
+
raise
|
302
|
+
|
284
303
|
def setup_mcp_subparser(subparsers):
|
285
304
|
"""
|
286
305
|
Sets up an argparse subparser for the 'mcp' command 3.
|
@@ -296,3 +315,12 @@ def setup_mcp_subparser(subparsers):
|
|
296
315
|
help='Start an Anthropic MCP server that wraps `sunholo` functionality')
|
297
316
|
|
298
317
|
mcp_parser.set_defaults(func=cli_mcp)
|
318
|
+
|
319
|
+
# Add mcp-bridge subcommand
|
320
|
+
mcp_bridge_parser = subparsers.add_parser('mcp-bridge',
|
321
|
+
help='Start a stdio-to-HTTP bridge for MCP servers')
|
322
|
+
mcp_bridge_parser.add_argument('url',
|
323
|
+
nargs='?',
|
324
|
+
default='http://127.0.0.1:1956/mcp',
|
325
|
+
help='HTTP URL of the MCP server (default: http://127.0.0.1:1956/mcp)')
|
326
|
+
mcp_bridge_parser.set_defaults(func=cli_mcp_bridge)
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
MCP stdio-to-HTTP bridge for Sunholo VAC server.
|
4
|
+
This script translates between stdio (used by Claude Desktop) and HTTP (used by Sunholo).
|
5
|
+
"""
|
6
|
+
|
7
|
+
import sys
|
8
|
+
import json
|
9
|
+
import asyncio
|
10
|
+
import aiohttp
|
11
|
+
from typing import Optional
|
12
|
+
|
13
|
+
from ..custom_logging import setup_logging
|
14
|
+
logger = setup_logging("mcp-bridge")
|
15
|
+
|
16
|
+
class MCPStdioHttpBridge:
|
17
|
+
def __init__(self, http_url: str):
|
18
|
+
self.http_url = http_url
|
19
|
+
self.session: Optional[aiohttp.ClientSession] = None
|
20
|
+
|
21
|
+
async def start(self):
|
22
|
+
"""Start the bridge."""
|
23
|
+
self.session = aiohttp.ClientSession()
|
24
|
+
|
25
|
+
# Send initialization success to stderr for debugging
|
26
|
+
logger.info(f"MCP stdio-to-HTTP bridge started, forwarding to: {self.http_url}")
|
27
|
+
|
28
|
+
try:
|
29
|
+
await self.process_messages()
|
30
|
+
finally:
|
31
|
+
await self.session.close()
|
32
|
+
|
33
|
+
async def process_messages(self):
|
34
|
+
"""Process messages from stdin and forward to HTTP server."""
|
35
|
+
loop = asyncio.get_event_loop()
|
36
|
+
reader = asyncio.StreamReader()
|
37
|
+
protocol = asyncio.StreamReaderProtocol(reader)
|
38
|
+
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
|
39
|
+
|
40
|
+
while True:
|
41
|
+
try:
|
42
|
+
# Read line from stdin
|
43
|
+
line = await reader.readline()
|
44
|
+
if not line:
|
45
|
+
break
|
46
|
+
|
47
|
+
line = line.decode().strip()
|
48
|
+
if not line:
|
49
|
+
continue
|
50
|
+
|
51
|
+
# Parse JSON-RPC message
|
52
|
+
try:
|
53
|
+
message = json.loads(line)
|
54
|
+
logger.debug(f"Received from stdin: {message}")
|
55
|
+
except json.JSONDecodeError as e:
|
56
|
+
logger.error(f"Invalid JSON: {e}")
|
57
|
+
continue
|
58
|
+
|
59
|
+
# Forward to HTTP server
|
60
|
+
try:
|
61
|
+
async with self.session.post(
|
62
|
+
self.http_url,
|
63
|
+
json=message,
|
64
|
+
headers={"Content-Type": "application/json"}
|
65
|
+
) as response:
|
66
|
+
result = await response.json()
|
67
|
+
logger.debug(f"Received from HTTP: {result}")
|
68
|
+
|
69
|
+
# Send response back to stdout
|
70
|
+
print(json.dumps(result))
|
71
|
+
sys.stdout.flush()
|
72
|
+
|
73
|
+
except aiohttp.ClientError as e:
|
74
|
+
logger.error(f"HTTP error: {e}")
|
75
|
+
error_response = {
|
76
|
+
"jsonrpc": "2.0",
|
77
|
+
"error": {
|
78
|
+
"code": -32603,
|
79
|
+
"message": f"HTTP error: {str(e)}"
|
80
|
+
},
|
81
|
+
"id": message.get("id")
|
82
|
+
}
|
83
|
+
print(json.dumps(error_response))
|
84
|
+
sys.stdout.flush()
|
85
|
+
|
86
|
+
except Exception as e:
|
87
|
+
logger.error(f"Bridge error: {e}")
|
88
|
+
continue
|
89
|
+
|
90
|
+
async def run_bridge(http_url: str):
|
91
|
+
"""Run the stdio-to-HTTP bridge."""
|
92
|
+
bridge = MCPStdioHttpBridge(http_url)
|
93
|
+
await bridge.start()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: sunholo
|
3
|
-
Version: 0.143.
|
3
|
+
Version: 0.143.14
|
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
|
@@ -70,7 +70,7 @@ Requires-Dist: langchain_google_alloydb_pg; extra == "all"
|
|
70
70
|
Requires-Dist: langchain-anthropic>=0.1.23; extra == "all"
|
71
71
|
Requires-Dist: langchain-google-vertexai; extra == "all"
|
72
72
|
Requires-Dist: langchain-unstructured; extra == "all"
|
73
|
-
Requires-Dist: langfuse; extra == "all"
|
73
|
+
Requires-Dist: langfuse==2.60.9; extra == "all"
|
74
74
|
Requires-Dist: mcp>=1.1.1; extra == "all"
|
75
75
|
Requires-Dist: numpy; extra == "all"
|
76
76
|
Requires-Dist: opencv-python; extra == "all"
|
@@ -169,7 +169,7 @@ Requires-Dist: gunicorn; extra == "http"
|
|
169
169
|
Requires-Dist: httpcore; extra == "http"
|
170
170
|
Requires-Dist: httpx; extra == "http"
|
171
171
|
Requires-Dist: langchain; extra == "http"
|
172
|
-
Requires-Dist: langfuse; extra == "http"
|
172
|
+
Requires-Dist: langfuse==2.60.9; extra == "http"
|
173
173
|
Requires-Dist: python-socketio; extra == "http"
|
174
174
|
Requires-Dist: requests; extra == "http"
|
175
175
|
Requires-Dist: tenacity; extra == "http"
|
@@ -288,6 +288,7 @@ sunholo deploy my-agent
|
|
288
288
|
|
289
289
|
- **Web Frameworks**: Flask and FastAPI templates
|
290
290
|
- **AI Frameworks**: LangChain and LlamaIndex integration
|
291
|
+
- **MCP Integration**: Model Context Protocol server and client support
|
291
292
|
- **Observability**: Langfuse for tracing and monitoring
|
292
293
|
- **API Standards**: OpenAI-compatible endpoints
|
293
294
|
|
@@ -18,7 +18,7 @@ sunholo/agents/fastapi/base.py,sha256=W-cyF8ZDUH40rc-c-Apw3-_8IIi2e4Y9qRtnoVnsc1
|
|
18
18
|
sunholo/agents/fastapi/qna_routes.py,sha256=lKHkXPmwltu9EH3RMwmD153-J6pE7kWQ4BhBlV3to-s,3864
|
19
19
|
sunholo/agents/flask/__init__.py,sha256=dEoByI3gDNUOjpX1uVKP7uPjhfFHJubbiaAv3xLopnk,63
|
20
20
|
sunholo/agents/flask/base.py,sha256=vnpxFEOnCmt9humqj-jYPLfJcdwzsop9NorgkJ-tSaU,1756
|
21
|
-
sunholo/agents/flask/vac_routes.py,sha256=
|
21
|
+
sunholo/agents/flask/vac_routes.py,sha256=kaPUDyIH5KhCgeCEtag97qErGVZfqpY1ZEiX3y1_r-s,57505
|
22
22
|
sunholo/archive/__init__.py,sha256=qNHWm5rGPVOlxZBZCpA1wTYPbalizRT7f8X4rs2t290,31
|
23
23
|
sunholo/archive/archive.py,sha256=PxVfDtO2_2ZEEbnhXSCbXLdeoHoQVImo4y3Jr2XkCFY,1204
|
24
24
|
sunholo/auth/__init__.py,sha256=TeP-OY0XGxYV_8AQcVGoh35bvyWhNUcMRfhuD5l44Sk,91
|
@@ -115,8 +115,9 @@ sunholo/llamaindex/user_history.py,sha256=ZtkecWuF9ORduyGB8kF8gP66bm9DdvCI-ZiK6K
|
|
115
115
|
sunholo/lookup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
116
116
|
sunholo/lookup/model_lookup.yaml,sha256=O7o-jP53MLA06C8pI-ILwERShO-xf6z_258wtpZBv6A,739
|
117
117
|
sunholo/mcp/__init__.py,sha256=Bi0ZYMvWuf1AL_QSrMAREVVdTZFiIokGwrytBXKBJyc,1028
|
118
|
-
sunholo/mcp/cli.py,sha256=
|
118
|
+
sunholo/mcp/cli.py,sha256=qD38Kia5j9vIBh3X0L8cIQbCRlqzZpXUo-C_vuMZJbQ,11663
|
119
119
|
sunholo/mcp/mcp_manager.py,sha256=g75vv6XvM24U7uz366slE-p76Qs4AvVcsarHSF9qIvE,5061
|
120
|
+
sunholo/mcp/stdio_http_bridge.py,sha256=xi9aaeueKvYT5gdBo-jmltqUNe7X9a7dCZeTz3o-CtY,3258
|
120
121
|
sunholo/mcp/vac_mcp_server.py,sha256=WcFOgN2_lyp1vfn-KcW4GewrBidkRYDx9gzEORV6rV8,10611
|
121
122
|
sunholo/ollama/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
122
123
|
sunholo/ollama/ollama_images.py,sha256=H2cpcNu88R4TwyfL_nnqkQhdvBQ2FPCAy4Ok__0yQmo,2351
|
@@ -175,9 +176,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
|
|
175
176
|
sunholo/vertex/memory_tools.py,sha256=tBZxqVZ4InTmdBvLlOYwoSEWu4-kGquc-gxDwZCC4FA,7667
|
176
177
|
sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
|
177
178
|
sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
|
178
|
-
sunholo-0.143.
|
179
|
-
sunholo-0.143.
|
180
|
-
sunholo-0.143.
|
181
|
-
sunholo-0.143.
|
182
|
-
sunholo-0.143.
|
183
|
-
sunholo-0.143.
|
179
|
+
sunholo-0.143.14.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
180
|
+
sunholo-0.143.14.dist-info/METADATA,sha256=qUcap4poGN94xjE0VYCg5CdUM3TaUNJ5ZmFo1jzzZFQ,18502
|
181
|
+
sunholo-0.143.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
182
|
+
sunholo-0.143.14.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
183
|
+
sunholo-0.143.14.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
184
|
+
sunholo-0.143.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|