blaxel 0.2.0rc1__py3-none-any.whl → 0.2.0rc3__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.
- blaxel/core/mcp/client.py +13 -8
- blaxel/core/mcp/server.py +9 -93
- {blaxel-0.2.0rc1.dist-info → blaxel-0.2.0rc3.dist-info}/METADATA +4 -4
- {blaxel-0.2.0rc1.dist-info → blaxel-0.2.0rc3.dist-info}/RECORD +6 -6
- {blaxel-0.2.0rc1.dist-info → blaxel-0.2.0rc3.dist-info}/WHEEL +0 -0
- {blaxel-0.2.0rc1.dist-info → blaxel-0.2.0rc3.dist-info}/licenses/LICENSE +0 -0
blaxel/core/mcp/client.py
CHANGED
@@ -7,6 +7,7 @@ import anyio
|
|
7
7
|
import mcp.types as types
|
8
8
|
from anyio.abc import TaskStatus
|
9
9
|
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
|
10
|
+
from mcp.shared.message import SessionMessage
|
10
11
|
from websockets.asyncio.client import ClientConnection
|
11
12
|
from websockets.asyncio.client import connect as ws_connect
|
12
13
|
|
@@ -28,11 +29,11 @@ async def websocket_client(
|
|
28
29
|
|
29
30
|
The `timeout` parameter controls connection timeout.
|
30
31
|
"""
|
31
|
-
read_stream: MemoryObjectReceiveStream[
|
32
|
-
read_stream_writer: MemoryObjectSendStream[
|
32
|
+
read_stream: MemoryObjectReceiveStream[SessionMessage | Exception]
|
33
|
+
read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception]
|
33
34
|
|
34
|
-
write_stream: MemoryObjectSendStream[
|
35
|
-
write_stream_reader: MemoryObjectReceiveStream[
|
35
|
+
write_stream: MemoryObjectSendStream[SessionMessage]
|
36
|
+
write_stream_reader: MemoryObjectReceiveStream[SessionMessage]
|
36
37
|
|
37
38
|
read_stream_writer, read_stream = anyio.create_memory_object_stream(0)
|
38
39
|
write_stream, write_stream_reader = anyio.create_memory_object_stream(0)
|
@@ -64,7 +65,9 @@ async def websocket_client(
|
|
64
65
|
message
|
65
66
|
)
|
66
67
|
logger.debug(f"Received server message: {parsed_message}")
|
67
|
-
await read_stream_writer.send(
|
68
|
+
await read_stream_writer.send(
|
69
|
+
SessionMessage(message=parsed_message)
|
70
|
+
)
|
68
71
|
except Exception as exc:
|
69
72
|
logger.error(f"Error parsing server message: {exc}")
|
70
73
|
await read_stream_writer.send(exc)
|
@@ -77,10 +80,12 @@ async def websocket_client(
|
|
77
80
|
async def ws_writer(websocket: ClientConnection):
|
78
81
|
try:
|
79
82
|
async with write_stream_reader:
|
80
|
-
async for
|
81
|
-
logger.debug(
|
83
|
+
async for session_message in write_stream_reader:
|
84
|
+
logger.debug(
|
85
|
+
f"Sending client message: {session_message.message}"
|
86
|
+
)
|
82
87
|
await websocket.send(
|
83
|
-
message.model_dump_json(
|
88
|
+
session_message.message.model_dump_json(
|
84
89
|
by_alias=True,
|
85
90
|
exclude_none=True,
|
86
91
|
)
|
blaxel/core/mcp/server.py
CHANGED
@@ -2,71 +2,23 @@ import logging
|
|
2
2
|
import traceback
|
3
3
|
import uuid
|
4
4
|
from contextlib import asynccontextmanager
|
5
|
-
from typing import
|
5
|
+
from typing import Literal
|
6
6
|
|
7
7
|
import anyio
|
8
8
|
import mcp.types as types
|
9
9
|
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
|
10
10
|
from mcp.server.fastmcp import FastMCP as FastMCPBase
|
11
|
+
from mcp.shared.message import SessionMessage
|
11
12
|
from websockets.asyncio.server import ServerConnection, serve
|
12
13
|
|
13
|
-
try:
|
14
|
-
from opentelemetry.trace import Span, StatusCode
|
15
|
-
|
16
|
-
HAS_OPENTELEMETRY = True
|
17
|
-
except ImportError:
|
18
|
-
HAS_OPENTELEMETRY = False
|
19
|
-
|
20
|
-
# Create dummy classes for when opentelemetry is not available
|
21
|
-
class Span:
|
22
|
-
def set_attributes(self, *args, **kwargs):
|
23
|
-
pass
|
24
|
-
|
25
|
-
def set_status(self, *args, **kwargs):
|
26
|
-
pass
|
27
|
-
|
28
|
-
def record_exception(self, *args, **kwargs):
|
29
|
-
pass
|
30
|
-
|
31
|
-
def end(self, *args, **kwargs):
|
32
|
-
pass
|
33
|
-
|
34
|
-
def add_event(self, *args, **kwargs):
|
35
|
-
pass
|
36
|
-
|
37
|
-
def get_span_context(self, *args, **kwargs):
|
38
|
-
return None
|
39
|
-
|
40
|
-
def is_recording(self, *args, **kwargs):
|
41
|
-
return False
|
42
|
-
|
43
|
-
def set_attribute(self, *args, **kwargs):
|
44
|
-
pass
|
45
|
-
|
46
|
-
def update_name(self, *args, **kwargs):
|
47
|
-
pass
|
48
|
-
|
49
|
-
class StatusCode:
|
50
|
-
ERROR = "ERROR"
|
51
|
-
|
52
|
-
|
53
14
|
from ..common.env import env
|
54
15
|
|
55
16
|
logger = logging.getLogger(__name__)
|
56
17
|
|
57
18
|
|
58
|
-
class DummySpanManager:
|
59
|
-
"""Dummy span manager for when opentelemetry is not available."""
|
60
|
-
|
61
|
-
def create_span(self, name: str, attributes: dict = None):
|
62
|
-
return Span()
|
63
|
-
|
64
|
-
|
65
19
|
class BlaxelMcpServerTransport:
|
66
20
|
"""WebSocket server transport for MCP."""
|
67
21
|
|
68
|
-
spans: Dict[str, Span] = {}
|
69
|
-
|
70
22
|
def __init__(self, port: int = 8080):
|
71
23
|
"""Initialize the WebSocket server transport.
|
72
24
|
|
@@ -80,21 +32,14 @@ class BlaxelMcpServerTransport:
|
|
80
32
|
self.clients = {}
|
81
33
|
self.server = None
|
82
34
|
|
83
|
-
# Initialize span manager
|
84
|
-
if HAS_OPENTELEMETRY:
|
85
|
-
# TODO: Implement proper OpenTelemetry span manager when telemetry is available
|
86
|
-
self.span_manager = DummySpanManager()
|
87
|
-
else:
|
88
|
-
self.span_manager = DummySpanManager()
|
89
|
-
|
90
35
|
@asynccontextmanager
|
91
36
|
async def websocket_server(self):
|
92
37
|
"""Create and run a WebSocket server for MCP communication."""
|
93
|
-
read_stream: MemoryObjectReceiveStream[
|
94
|
-
read_stream_writer: MemoryObjectSendStream[
|
38
|
+
read_stream: MemoryObjectReceiveStream[SessionMessage | Exception]
|
39
|
+
read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception]
|
95
40
|
|
96
|
-
write_stream: MemoryObjectSendStream[
|
97
|
-
write_stream_reader: MemoryObjectReceiveStream[
|
41
|
+
write_stream: MemoryObjectSendStream[SessionMessage]
|
42
|
+
write_stream_reader: MemoryObjectReceiveStream[SessionMessage]
|
98
43
|
|
99
44
|
read_stream_writer, read_stream = anyio.create_memory_object_stream(0)
|
100
45
|
write_stream, write_stream_reader = anyio.create_memory_object_stream(0)
|
@@ -106,30 +51,14 @@ class BlaxelMcpServerTransport:
|
|
106
51
|
|
107
52
|
try:
|
108
53
|
async for message in websocket:
|
109
|
-
span = self.span_manager.create_span("message", {"mcp.client.id": client_id})
|
110
54
|
try:
|
111
55
|
msg = types.JSONRPCMessage.model_validate_json(message)
|
112
56
|
# Modify message ID to include client ID
|
113
57
|
if hasattr(msg, "id") and msg.id is not None:
|
114
58
|
original_id = msg.id
|
115
59
|
msg.id = f"{client_id}:{original_id}"
|
116
|
-
|
117
|
-
{
|
118
|
-
"mcp.message.parsed": True,
|
119
|
-
"mcp.method": getattr(msg, "method", None),
|
120
|
-
"mcp.messageId": getattr(msg, "id", None),
|
121
|
-
"mcp.toolName": getattr(
|
122
|
-
getattr(msg, "params", None), "name", None
|
123
|
-
),
|
124
|
-
"span.type": "mcp.message",
|
125
|
-
}
|
126
|
-
)
|
127
|
-
self.spans[client_id + ":" + msg.id] = span
|
128
|
-
await read_stream_writer.send(msg)
|
60
|
+
await read_stream_writer.send(SessionMessage(message=msg))
|
129
61
|
except Exception as exc:
|
130
|
-
span.set_status(StatusCode.ERROR)
|
131
|
-
span.record_exception(exc)
|
132
|
-
span.end()
|
133
62
|
logger.error(f"Failed to parse message: {exc}\n{traceback.format_exc()}")
|
134
63
|
await read_stream_writer.send(exc)
|
135
64
|
except Exception as e:
|
@@ -141,11 +70,11 @@ class BlaxelMcpServerTransport:
|
|
141
70
|
|
142
71
|
async def message_sender():
|
143
72
|
async with write_stream_reader:
|
144
|
-
async for
|
73
|
+
async for session_message in write_stream_reader:
|
145
74
|
# Extract client ID from message ID
|
146
75
|
client_id = None
|
147
76
|
msg_id = None
|
148
|
-
|
77
|
+
message = session_message.message
|
149
78
|
if hasattr(message, "id") and message.id is not None:
|
150
79
|
parts = str(message.id).split(":", 1)
|
151
80
|
if len(parts) == 2:
|
@@ -158,25 +87,12 @@ class BlaxelMcpServerTransport:
|
|
158
87
|
if client_id and client_id in self.clients:
|
159
88
|
# Send to specific client
|
160
89
|
websocket = self.clients[client_id]
|
161
|
-
span = self.spans.get(client_id + ":" + msg_id)
|
162
90
|
try:
|
163
91
|
await websocket.send(data)
|
164
|
-
if span:
|
165
|
-
span.set_attributes(
|
166
|
-
{
|
167
|
-
"mcp.message.response_sent": True,
|
168
|
-
}
|
169
|
-
)
|
170
92
|
except Exception as e:
|
171
|
-
if span:
|
172
|
-
span.set_status(StatusCode.ERROR)
|
173
|
-
span.record_exception(e)
|
174
93
|
logger.error(f"Failed to send message to client {client_id}: {e}")
|
175
94
|
if client_id in self.clients:
|
176
95
|
del self.clients[client_id]
|
177
|
-
finally:
|
178
|
-
if span:
|
179
|
-
span.end()
|
180
96
|
else:
|
181
97
|
# Broadcast to all clients
|
182
98
|
dead_clients = []
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: blaxel
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.0rc3
|
4
4
|
Summary: Blaxel - AI development platform SDK
|
5
5
|
Project-URL: Homepage, https://blaxel.ai
|
6
6
|
Project-URL: Documentation, https://docs.blaxel.ai
|
@@ -11,7 +11,7 @@ License-File: LICENSE
|
|
11
11
|
Requires-Python: >=3.10
|
12
12
|
Requires-Dist: attrs>=21.3.0
|
13
13
|
Requires-Dist: httpx>=0.27.0
|
14
|
-
Requires-Dist: mcp
|
14
|
+
Requires-Dist: mcp>=1.9.4
|
15
15
|
Requires-Dist: pydantic>=2.0.0
|
16
16
|
Requires-Dist: pyjwt>=2.0.0
|
17
17
|
Requires-Dist: python-dateutil>=2.8.0
|
@@ -43,7 +43,7 @@ Requires-Dist: llama-index-llms-groq>=0.3.1; extra == 'all'
|
|
43
43
|
Requires-Dist: llama-index-llms-mistralai>=0.4.0; extra == 'all'
|
44
44
|
Requires-Dist: llama-index-llms-openai>=0.3.42; extra == 'all'
|
45
45
|
Requires-Dist: llama-index>=0.12.37; extra == 'all'
|
46
|
-
Requires-Dist: openai-agents>=0.0.
|
46
|
+
Requires-Dist: openai-agents>=0.0.14; extra == 'all'
|
47
47
|
Requires-Dist: opentelemetry-exporter-otlp>=1.28.0; extra == 'all'
|
48
48
|
Requires-Dist: opentelemetry-instrumentation-anthropic==0.40.6; extra == 'all'
|
49
49
|
Requires-Dist: opentelemetry-instrumentation-cohere==0.40.6; extra == 'all'
|
@@ -95,7 +95,7 @@ Requires-Dist: llama-index-llms-openai>=0.3.42; extra == 'llamaindex'
|
|
95
95
|
Requires-Dist: llama-index>=0.12.37; extra == 'llamaindex'
|
96
96
|
Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.40.7; extra == 'llamaindex'
|
97
97
|
Provides-Extra: openai
|
98
|
-
Requires-Dist: openai-agents>=0.0.
|
98
|
+
Requires-Dist: openai-agents>=0.0.14; extra == 'openai'
|
99
99
|
Provides-Extra: pydantic
|
100
100
|
Requires-Dist: pydantic-ai>=0.0.48; extra == 'pydantic'
|
101
101
|
Provides-Extra: telemetry
|
@@ -301,8 +301,8 @@ blaxel/core/common/logger.py,sha256=Jt0MCJgYDPq36rl7UyKRDJH76a-AwYdfggNeNYJt6N0,
|
|
301
301
|
blaxel/core/common/settings.py,sha256=7KTryuBdud0IfHqykX7xEEtpgq5M5h1Z8YEzYKsHB-Q,2327
|
302
302
|
blaxel/core/jobs/__init__.py,sha256=tApZ6t6Savd5c9yH1RhuiPDGq19B464Fakd-YqCOEtI,5441
|
303
303
|
blaxel/core/mcp/__init__.py,sha256=5VjkiQFb1QWW5QKRgwPHARlxZJ9Xqaz0diJTpM8LLF0,142
|
304
|
-
blaxel/core/mcp/client.py,sha256=
|
305
|
-
blaxel/core/mcp/server.py,sha256=
|
304
|
+
blaxel/core/mcp/client.py,sha256=aK3wSnsO8DmT1BZqw4eiCMF71Jwvni6Qga0DhPP806Y,5437
|
305
|
+
blaxel/core/mcp/server.py,sha256=tXySGZKgK3IllYOzYOecp58BixKBkmAIvQp_4nSM_Ww,5919
|
306
306
|
blaxel/core/models/__init__.py,sha256=HbRDsMnUFHkPC-MMkzPXh4mUqkVjqO6p3j7m00N_XSo,1722
|
307
307
|
blaxel/core/sandbox/__init__.py,sha256=eWTH7PWNQZe9efqParwgXzltc7L4OyPtT_REqCdQybU,551
|
308
308
|
blaxel/core/sandbox/action.py,sha256=9Zjkco7YkLzBThD3N2Hr5SpeEiqU_-Ktk8HlKpkpiAg,2802
|
@@ -402,7 +402,7 @@ blaxel/telemetry/instrumentation/map.py,sha256=EVCw6ug1hemE-9kh77Vxs9cqr_p9TPzFw
|
|
402
402
|
blaxel/telemetry/instrumentation/utils.py,sha256=KInMYZH-mu9_wvetmf0EmgrfN3Sw8IWk2Y95v2u90_U,1901
|
403
403
|
blaxel/telemetry/log/log.py,sha256=RvQByRjZMoP_dRaAZu8oK6DTegsHs-xV4W-UIqis6CA,2461
|
404
404
|
blaxel/telemetry/log/logger.py,sha256=NPAS3g82ryROjvc_DEZaTIfrcehoLEZoP-JkLxADxc0,4113
|
405
|
-
blaxel-0.2.
|
406
|
-
blaxel-0.2.
|
407
|
-
blaxel-0.2.
|
408
|
-
blaxel-0.2.
|
405
|
+
blaxel-0.2.0rc3.dist-info/METADATA,sha256=6uAwLfyFgd98jymj7QVZMz6et4U1oAr3JgqyL0ZcMkQ,9878
|
406
|
+
blaxel-0.2.0rc3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
407
|
+
blaxel-0.2.0rc3.dist-info/licenses/LICENSE,sha256=p5PNQvpvyDT_0aYBDgmV1fFI_vAD2aSV0wWG7VTgRis,1069
|
408
|
+
blaxel-0.2.0rc3.dist-info/RECORD,,
|
File without changes
|
File without changes
|