stinger-python-utils 0.1.9__py3-none-any.whl → 0.2.0__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.
- stinger_python_utils/message_creator.py +152 -23
- stinger_python_utils-0.2.0.dist-info/METADATA +84 -0
- stinger_python_utils-0.2.0.dist-info/RECORD +7 -0
- {stinger_python_utils-0.1.9.dist-info → stinger_python_utils-0.2.0.dist-info}/WHEEL +1 -1
- stinger_python_utils/mcp/__init__.py +0 -20
- stinger_python_utils/mcp/__main__.py +0 -58
- stinger_python_utils/mcp/plugin.py +0 -220
- stinger_python_utils/mcp/server.py +0 -633
- stinger_python_utils-0.1.9.dist-info/METADATA +0 -276
- stinger_python_utils-0.1.9.dist-info/RECORD +0 -12
- stinger_python_utils-0.1.9.dist-info/entry_points.txt +0 -2
- {stinger_python_utils-0.1.9.dist-info → stinger_python_utils-0.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -16,27 +16,73 @@ class MessageCreator:
|
|
|
16
16
|
|
|
17
17
|
@classmethod
|
|
18
18
|
def signal_message(cls, topic: str, payload: BaseModel) -> Message:
|
|
19
|
+
return cls.binary_signal_message(
|
|
20
|
+
topic,
|
|
21
|
+
payload.model_dump_json(by_alias=True).encode("utf-8"),
|
|
22
|
+
"application/json",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def binary_signal_message(cls, topic: str, payload: bytes, content_type: str) -> Message:
|
|
19
27
|
cls._validate_topic(topic)
|
|
20
28
|
return Message(
|
|
21
29
|
topic=topic,
|
|
22
|
-
payload=payload
|
|
30
|
+
payload=payload,
|
|
23
31
|
qos=1,
|
|
24
32
|
retain=False,
|
|
25
|
-
content_type=
|
|
33
|
+
content_type=content_type,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def command_message(cls, topic: str, payload: BaseModel, qos: int = 2) -> Message:
|
|
38
|
+
return cls.binary_command_message(
|
|
39
|
+
topic,
|
|
40
|
+
payload.model_dump_json(by_alias=True).encode("utf-8"),
|
|
41
|
+
"application/json",
|
|
42
|
+
qos=qos,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def binary_command_message(
|
|
47
|
+
cls, topic: str, payload: bytes, content_type: str, qos: int = 2
|
|
48
|
+
) -> Message:
|
|
49
|
+
"""
|
|
50
|
+
A command is a signal in reverse: the client publishes it to the server and never
|
|
51
|
+
learns whether it was acted on. There is therefore no response topic and no
|
|
52
|
+
correlation data on the message.
|
|
53
|
+
"""
|
|
54
|
+
cls._validate_topic(topic)
|
|
55
|
+
return Message(
|
|
56
|
+
topic=topic,
|
|
57
|
+
payload=payload,
|
|
58
|
+
qos=qos,
|
|
59
|
+
retain=False,
|
|
60
|
+
content_type=content_type,
|
|
26
61
|
)
|
|
27
62
|
|
|
28
63
|
@classmethod
|
|
29
64
|
def status_message(
|
|
30
|
-
cls, topic, status_message: BaseModel, expiry_seconds: int
|
|
65
|
+
cls, topic: str, status_message: BaseModel, expiry_seconds: int
|
|
66
|
+
) -> Message:
|
|
67
|
+
return cls.binary_status_message(
|
|
68
|
+
topic,
|
|
69
|
+
status_message.model_dump_json(by_alias=True).encode("utf-8"),
|
|
70
|
+
"application/json",
|
|
71
|
+
expiry_seconds=expiry_seconds,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def binary_status_message(
|
|
76
|
+
cls, topic: str, payload: bytes, content_type: str, expiry_seconds: int
|
|
31
77
|
) -> Message:
|
|
32
78
|
cls._validate_topic(topic)
|
|
33
79
|
return Message(
|
|
34
80
|
topic=topic,
|
|
35
|
-
payload=
|
|
81
|
+
payload=payload,
|
|
36
82
|
qos=1,
|
|
37
83
|
retain=True,
|
|
38
84
|
message_expiry_interval=expiry_seconds,
|
|
39
|
-
content_type=
|
|
85
|
+
content_type=content_type,
|
|
40
86
|
)
|
|
41
87
|
|
|
42
88
|
@classmethod
|
|
@@ -46,9 +92,14 @@ class MessageCreator:
|
|
|
46
92
|
return_code: Union[int, MethodReturnCode],
|
|
47
93
|
correlation_id: Union[str, bytes, None] = None,
|
|
48
94
|
debug_info: Optional[str] = None,
|
|
95
|
+
content_type: str = "application/json",
|
|
49
96
|
) -> Message:
|
|
50
97
|
"""
|
|
51
98
|
This could be used for a response to a request, but where there was an error fulfilling the request.
|
|
99
|
+
|
|
100
|
+
An error carries no data -- the return code and any debug info travel in MQTT user
|
|
101
|
+
properties -- so the body is an empty JSON object for a JSON response and empty
|
|
102
|
+
bytes for any other content type, since a protobuf consumer would reject "{}".
|
|
52
103
|
"""
|
|
53
104
|
cls._validate_topic(topic)
|
|
54
105
|
rc = (
|
|
@@ -58,7 +109,7 @@ class MessageCreator:
|
|
|
58
109
|
)
|
|
59
110
|
msg_obj = Message(
|
|
60
111
|
topic=topic,
|
|
61
|
-
payload=b"{}",
|
|
112
|
+
payload=b"{}" if content_type == "application/json" else b"",
|
|
62
113
|
qos=1,
|
|
63
114
|
retain=False,
|
|
64
115
|
correlation_data=(
|
|
@@ -67,7 +118,7 @@ class MessageCreator:
|
|
|
67
118
|
else correlation_id
|
|
68
119
|
),
|
|
69
120
|
user_properties={"ReturnCode": str(rc)},
|
|
70
|
-
content_type=
|
|
121
|
+
content_type=content_type,
|
|
71
122
|
)
|
|
72
123
|
if (
|
|
73
124
|
debug_info is not None and msg_obj.user_properties is not None
|
|
@@ -86,19 +137,32 @@ class MessageCreator:
|
|
|
86
137
|
"""
|
|
87
138
|
This could be used for a successful response to a request.
|
|
88
139
|
"""
|
|
89
|
-
cls._validate_topic(response_topic, "response_topic")
|
|
90
140
|
if isinstance(response_obj, BaseModel):
|
|
91
141
|
payload = response_obj.model_dump_json(by_alias=True).encode("utf-8")
|
|
92
142
|
elif isinstance(response_obj, str):
|
|
93
143
|
payload = response_obj.encode("utf-8")
|
|
94
144
|
else:
|
|
95
145
|
payload = response_obj
|
|
146
|
+
return cls.binary_response_message(
|
|
147
|
+
response_topic, payload, "application/json", return_code, correlation_id
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
@classmethod
|
|
151
|
+
def binary_response_message(
|
|
152
|
+
cls,
|
|
153
|
+
response_topic: str,
|
|
154
|
+
payload: bytes,
|
|
155
|
+
content_type: str,
|
|
156
|
+
return_code: Union[int, MethodReturnCode],
|
|
157
|
+
correlation_id: Union[str, bytes, None] = None,
|
|
158
|
+
) -> Message:
|
|
159
|
+
cls._validate_topic(response_topic, "response_topic")
|
|
96
160
|
rc = (
|
|
97
161
|
return_code.value
|
|
98
162
|
if isinstance(return_code, MethodReturnCode)
|
|
99
163
|
else return_code
|
|
100
164
|
)
|
|
101
|
-
|
|
165
|
+
return Message(
|
|
102
166
|
topic=response_topic,
|
|
103
167
|
payload=payload,
|
|
104
168
|
qos=1,
|
|
@@ -109,9 +173,8 @@ class MessageCreator:
|
|
|
109
173
|
else correlation_id
|
|
110
174
|
),
|
|
111
175
|
user_properties={"ReturnCode": str(rc)},
|
|
112
|
-
content_type=
|
|
176
|
+
content_type=content_type,
|
|
113
177
|
)
|
|
114
|
-
return msg_obj
|
|
115
178
|
|
|
116
179
|
@classmethod
|
|
117
180
|
def property_state_message(
|
|
@@ -120,13 +183,24 @@ class MessageCreator:
|
|
|
120
183
|
"""
|
|
121
184
|
Creates a retained message representing the state/value of a property.
|
|
122
185
|
"""
|
|
186
|
+
return cls.binary_property_state_message(
|
|
187
|
+
topic,
|
|
188
|
+
state_obj.model_dump_json(by_alias=True).encode("utf-8"),
|
|
189
|
+
"application/json",
|
|
190
|
+
state_version,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
@classmethod
|
|
194
|
+
def binary_property_state_message(
|
|
195
|
+
cls, topic: str, payload: bytes, content_type: str, state_version: Optional[int] = None
|
|
196
|
+
) -> Message:
|
|
123
197
|
cls._validate_topic(topic)
|
|
124
198
|
msg_obj = Message(
|
|
125
199
|
topic=topic,
|
|
126
|
-
payload=
|
|
200
|
+
payload=payload,
|
|
127
201
|
qos=1,
|
|
128
202
|
retain=True,
|
|
129
|
-
content_type=
|
|
203
|
+
content_type=content_type,
|
|
130
204
|
)
|
|
131
205
|
if state_version is not None:
|
|
132
206
|
msg_obj.user_properties = {"PropertyVersion": str(state_version)}
|
|
@@ -144,14 +218,33 @@ class MessageCreator:
|
|
|
144
218
|
"""
|
|
145
219
|
Creates a message representing a request to update a property.
|
|
146
220
|
"""
|
|
221
|
+
return cls.binary_property_update_request_message(
|
|
222
|
+
topic,
|
|
223
|
+
property_obj.model_dump_json(by_alias=True).encode("utf-8"),
|
|
224
|
+
"application/json",
|
|
225
|
+
version,
|
|
226
|
+
response_topic,
|
|
227
|
+
correlation_id,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
@classmethod
|
|
231
|
+
def binary_property_update_request_message(
|
|
232
|
+
cls,
|
|
233
|
+
topic: str,
|
|
234
|
+
payload: bytes,
|
|
235
|
+
content_type: str,
|
|
236
|
+
version: str,
|
|
237
|
+
response_topic: str,
|
|
238
|
+
correlation_id: Union[str, bytes, None] = None,
|
|
239
|
+
) -> Message:
|
|
147
240
|
cls._validate_topic(topic)
|
|
148
241
|
cls._validate_topic(response_topic, "response_topic")
|
|
149
|
-
|
|
242
|
+
return Message(
|
|
150
243
|
topic=topic,
|
|
151
|
-
payload=
|
|
244
|
+
payload=payload,
|
|
152
245
|
qos=1,
|
|
153
246
|
retain=False,
|
|
154
|
-
content_type=
|
|
247
|
+
content_type=content_type,
|
|
155
248
|
response_topic=response_topic,
|
|
156
249
|
correlation_data=(
|
|
157
250
|
correlation_id.encode("utf-8")
|
|
@@ -160,7 +253,6 @@ class MessageCreator:
|
|
|
160
253
|
),
|
|
161
254
|
user_properties={"PropertyVersion": str(version)},
|
|
162
255
|
)
|
|
163
|
-
return msg_obj
|
|
164
256
|
|
|
165
257
|
@classmethod
|
|
166
258
|
def property_response_message(
|
|
@@ -175,6 +267,27 @@ class MessageCreator:
|
|
|
175
267
|
"""
|
|
176
268
|
Creates a message representing a response to a property update request.
|
|
177
269
|
"""
|
|
270
|
+
return cls.binary_property_response_message(
|
|
271
|
+
response_topic,
|
|
272
|
+
property_obj.model_dump_json(by_alias=True).encode("utf-8"),
|
|
273
|
+
"application/json",
|
|
274
|
+
version,
|
|
275
|
+
return_code,
|
|
276
|
+
correlation_id,
|
|
277
|
+
debug_info,
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
@classmethod
|
|
281
|
+
def binary_property_response_message(
|
|
282
|
+
cls,
|
|
283
|
+
response_topic: str,
|
|
284
|
+
payload: bytes,
|
|
285
|
+
content_type: str,
|
|
286
|
+
version: str,
|
|
287
|
+
return_code: Union[int, MethodReturnCode],
|
|
288
|
+
correlation_id: Union[str, bytes, None] = None,
|
|
289
|
+
debug_info: Optional[str] = None,
|
|
290
|
+
) -> Message:
|
|
178
291
|
cls._validate_topic(response_topic, "response_topic")
|
|
179
292
|
rc = (
|
|
180
293
|
return_code.value
|
|
@@ -183,10 +296,10 @@ class MessageCreator:
|
|
|
183
296
|
)
|
|
184
297
|
msg_obj = Message(
|
|
185
298
|
topic=response_topic,
|
|
186
|
-
payload=
|
|
299
|
+
payload=payload,
|
|
187
300
|
qos=1,
|
|
188
301
|
retain=False,
|
|
189
|
-
content_type=
|
|
302
|
+
content_type=content_type,
|
|
190
303
|
correlation_data=(
|
|
191
304
|
correlation_id.encode("utf-8")
|
|
192
305
|
if isinstance(correlation_id, str)
|
|
@@ -210,22 +323,38 @@ class MessageCreator:
|
|
|
210
323
|
request_obj: BaseModel,
|
|
211
324
|
response_topic: str,
|
|
212
325
|
correlation_id: Union[str, bytes, None] = None,
|
|
326
|
+
) -> Message:
|
|
327
|
+
return cls.binary_request_message(
|
|
328
|
+
topic,
|
|
329
|
+
request_obj.model_dump_json(by_alias=True).encode("utf-8"),
|
|
330
|
+
"application/json",
|
|
331
|
+
response_topic,
|
|
332
|
+
correlation_id,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
@classmethod
|
|
336
|
+
def binary_request_message(
|
|
337
|
+
cls,
|
|
338
|
+
topic: str,
|
|
339
|
+
payload: bytes,
|
|
340
|
+
content_type: str,
|
|
341
|
+
response_topic: str,
|
|
342
|
+
correlation_id: Union[str, bytes, None] = None,
|
|
213
343
|
) -> Message:
|
|
214
344
|
cls._validate_topic(topic)
|
|
215
345
|
cls._validate_topic(response_topic, "response_topic")
|
|
216
346
|
if correlation_id is None:
|
|
217
347
|
correlation_id = str(uuid.uuid4())
|
|
218
|
-
|
|
348
|
+
return Message(
|
|
219
349
|
topic=topic,
|
|
220
|
-
payload=
|
|
350
|
+
payload=payload,
|
|
221
351
|
qos=1,
|
|
222
352
|
retain=False,
|
|
223
353
|
response_topic=response_topic,
|
|
224
|
-
content_type=
|
|
354
|
+
content_type=content_type,
|
|
225
355
|
correlation_data=(
|
|
226
356
|
correlation_id.encode("utf-8")
|
|
227
357
|
if isinstance(correlation_id, str)
|
|
228
358
|
else correlation_id
|
|
229
359
|
),
|
|
230
360
|
)
|
|
231
|
-
return msg_obj
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: stinger-python-utils
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Common utilities for Stinger Python services.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.7
|
|
8
|
+
Requires-Dist: pydantic>=2.5.3
|
|
9
|
+
Requires-Dist: pyqttier>=0.2.0
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# stinger-python-utils
|
|
13
|
+
|
|
14
|
+
Shared utilities for Stinger Python services, providing convenient message creation for MQTT communication.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uv add stinger-python-utils
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## MessageCreator
|
|
25
|
+
|
|
26
|
+
`MessageCreator` is a utility class for creating MQTT messages with standardized properties and payloads.
|
|
27
|
+
|
|
28
|
+
### Basic Usage
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from pydantic import BaseModel
|
|
32
|
+
from stinger_python_utils.message_creator import MessageCreator
|
|
33
|
+
|
|
34
|
+
class MyPayload(BaseModel):
|
|
35
|
+
name: str
|
|
36
|
+
value: int
|
|
37
|
+
|
|
38
|
+
payload = MyPayload(name="test", value=42)
|
|
39
|
+
message = MessageCreator.signal_message("my/topic", payload)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Methods
|
|
43
|
+
|
|
44
|
+
| Method | Purpose | Return Code |
|
|
45
|
+
|--------|---------|-------------|
|
|
46
|
+
| `signal_message(topic, payload)` | Send a signal with one-time delivery | QoS 1, no retain |
|
|
47
|
+
| `status_message(topic, payload, expiry_seconds)` | Send status that expires | QoS 1, retained, with expiry |
|
|
48
|
+
| `error_response_message(topic, return_code, correlation_id, debug_info)` | Error response to a request | QoS 1, user properties: `ReturnCode` |
|
|
49
|
+
| `response_message(topic, payload, return_code, correlation_id)` | Successful response to a request | QoS 1, user properties: `ReturnCode` |
|
|
50
|
+
| `property_state_message(topic, payload, state_version)` | Publish property state | QoS 1, retained, JSON content type |
|
|
51
|
+
| `property_update_request_message(topic, payload, version, response_topic, correlation_id)` | Request property update | QoS 1, user property: `PropertyVersion` |
|
|
52
|
+
| `property_response_message(topic, payload, version, return_code, correlation_id, debug_info)` | Respond to property update | QoS 1, user properties: `ReturnCode`, `PropertyVersion` |
|
|
53
|
+
| `request_message(topic, payload, response_topic, correlation_id)` | Send a request (auto-generates UUID if no correlation_id) | QoS 1, auto correlation ID |
|
|
54
|
+
|
|
55
|
+
### Example: Request/Response Pattern
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from pydantic import BaseModel
|
|
59
|
+
from stinger_python_utils.message_creator import MessageCreator
|
|
60
|
+
|
|
61
|
+
class Request(BaseModel):
|
|
62
|
+
action: str
|
|
63
|
+
|
|
64
|
+
request = Request(action="start")
|
|
65
|
+
msg = MessageCreator.request_message(
|
|
66
|
+
"devices/cmd",
|
|
67
|
+
request,
|
|
68
|
+
response_topic="devices/response"
|
|
69
|
+
)
|
|
70
|
+
# Returns a Message with auto-generated correlation ID
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Example: Error Response
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
msg = MessageCreator.error_response_message(
|
|
77
|
+
"devices/response",
|
|
78
|
+
return_code=500,
|
|
79
|
+
correlation_id="req-123",
|
|
80
|
+
debug_info="Device not found"
|
|
81
|
+
)
|
|
82
|
+
# User properties include: ReturnCode=500, DebugInfo=Device not found
|
|
83
|
+
```
|
|
84
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
stinger_python_utils/__init__.py,sha256=IjHRV0k2DNwvFrEHebmsXiBvmITE8nQUnsR07h9tVkU,7
|
|
2
|
+
stinger_python_utils/message_creator.py,sha256=SEdtwRJCDSBmVy_1ciJeHwPjK6pav4OIaF0W88RjOMY,11588
|
|
3
|
+
stinger_python_utils/return_codes.py,sha256=AAwshvHu3SBoctwMX35k3j666J4a7DQ3V8AnR7QBjC8,5114
|
|
4
|
+
stinger_python_utils-0.2.0.dist-info/METADATA,sha256=OjtR5mmKovSMZSbeMtaVhRZ-ZJ_GtUe99pKyKC0soUk,2769
|
|
5
|
+
stinger_python_utils-0.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
6
|
+
stinger_python_utils-0.2.0.dist-info/licenses/LICENSE,sha256=_T-8ExmblJbhv-1AxC6XDVEHg1JdJA-126NvRiMqS-I,1070
|
|
7
|
+
stinger_python_utils-0.2.0.dist-info/RECORD,,
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"""Stinger MCP server – plugin-based MCP interface to stinger-ipc services.
|
|
2
|
-
|
|
3
|
-
Public API re-exported here for convenience::
|
|
4
|
-
|
|
5
|
-
from stinger_python_utils.mcp import StingerMCPPlugin, SignalDefinition, ...
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from .plugin import (
|
|
9
|
-
MethodDefinition,
|
|
10
|
-
PropertyDefinition,
|
|
11
|
-
SignalDefinition,
|
|
12
|
-
StingerMCPPlugin,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
__all__ = [
|
|
16
|
-
"MethodDefinition",
|
|
17
|
-
"PropertyDefinition",
|
|
18
|
-
"SignalDefinition",
|
|
19
|
-
"StingerMCPPlugin",
|
|
20
|
-
]
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"""Entry-point for ``python -m stinger_python_utils.mcp``."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import argparse
|
|
6
|
-
import asyncio
|
|
7
|
-
import logging
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def main() -> None:
|
|
11
|
-
parser = argparse.ArgumentParser(
|
|
12
|
-
prog="stinger-mcp-server",
|
|
13
|
-
description="Stinger MCP Server – expose stinger-ipc services over MCP",
|
|
14
|
-
)
|
|
15
|
-
parser.add_argument(
|
|
16
|
-
"--transport",
|
|
17
|
-
choices=["stdio", "sse", "streamable-http"],
|
|
18
|
-
default="stdio",
|
|
19
|
-
help="MCP transport to use (default: stdio)",
|
|
20
|
-
)
|
|
21
|
-
parser.add_argument(
|
|
22
|
-
"--host",
|
|
23
|
-
default="0.0.0.0",
|
|
24
|
-
help="Bind address for SSE/streamable-http transport (default: 0.0.0.0)",
|
|
25
|
-
)
|
|
26
|
-
parser.add_argument(
|
|
27
|
-
"--port",
|
|
28
|
-
type=int,
|
|
29
|
-
default=8000,
|
|
30
|
-
help="Port for SSE/streamable-http transport (default: 8000)",
|
|
31
|
-
)
|
|
32
|
-
parser.add_argument(
|
|
33
|
-
"--log-level",
|
|
34
|
-
default="INFO",
|
|
35
|
-
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
36
|
-
help="Logging level (default: INFO)",
|
|
37
|
-
)
|
|
38
|
-
args = parser.parse_args()
|
|
39
|
-
|
|
40
|
-
logging.basicConfig(
|
|
41
|
-
level=getattr(logging, args.log_level),
|
|
42
|
-
format="%(asctime)s %(levelname)-8s %(name)s %(message)s",
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
from .server import StingerMCPServer
|
|
46
|
-
|
|
47
|
-
server = StingerMCPServer()
|
|
48
|
-
|
|
49
|
-
if args.transport == "stdio":
|
|
50
|
-
asyncio.run(server.run_stdio())
|
|
51
|
-
elif args.transport == "sse":
|
|
52
|
-
asyncio.run(server.run_sse(host=args.host, port=args.port))
|
|
53
|
-
elif args.transport == "streamable-http":
|
|
54
|
-
asyncio.run(server.run_streamable_http(host=args.host, port=args.port))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if __name__ == "__main__":
|
|
58
|
-
main()
|