mcp-nequeo 2.7.26__tar.gz
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.
- mcp_nequeo-2.7.26/LICENSE +19 -0
- mcp_nequeo-2.7.26/PKG-INFO +23 -0
- mcp_nequeo-2.7.26/README.md +8 -0
- mcp_nequeo-2.7.26/pyproject.toml +19 -0
- mcp_nequeo-2.7.26/setup.cfg +4 -0
- mcp_nequeo-2.7.26/src/mcp-nequeo/McpClient.py +563 -0
- mcp_nequeo-2.7.26/src/mcp-nequeo/McpHost.py +274 -0
- mcp_nequeo-2.7.26/src/mcp-nequeo/McpServerBase.py +503 -0
- mcp_nequeo-2.7.26/src/mcp-nequeo/McpTypes.py +131 -0
- mcp_nequeo-2.7.26/src/mcp_nequeo.egg-info/PKG-INFO +23 -0
- mcp_nequeo-2.7.26/src/mcp_nequeo.egg-info/SOURCES.txt +11 -0
- mcp_nequeo-2.7.26/src/mcp_nequeo.egg-info/dependency_links.txt +1 -0
- mcp_nequeo-2.7.26/src/mcp_nequeo.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) Nequeo 2026 The Python Packaging Authority
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcp-nequeo
|
|
3
|
+
Version: 2.7.26
|
|
4
|
+
Summary: Model Context Protocol (MCP) client and server implementation
|
|
5
|
+
Author-email: Drazen Zadravec <noreply@dznequeo.net>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/drazenzadravec/tools/tree/master/ai/mcp
|
|
8
|
+
Project-URL: Issues, https://github.com/drazenzadravec/tools/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# Model Context Protocol (MCP) Client and Server
|
|
17
|
+
|
|
18
|
+
Client supports Stdio and Streamable HTTP. Server supports Stdio and Streamable HTTP.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
pip install mcp-nequeo
|
|
23
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mcp-nequeo"
|
|
3
|
+
version = "2.7.26"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name="Drazen Zadravec", email="noreply@dznequeo.net" },
|
|
6
|
+
]
|
|
7
|
+
description = "Model Context Protocol (MCP) client and server implementation"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.9"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"Operating System :: OS Independent",
|
|
13
|
+
]
|
|
14
|
+
license = "MIT"
|
|
15
|
+
license-files = ["LICEN[CS]E*"]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Homepage = "https://github.com/drazenzadravec/tools/tree/master/ai/mcp"
|
|
19
|
+
Issues = "https://github.com/drazenzadravec/tools/issues"
|
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
|
|
3
|
+
from mcp import ClientSession, StdioServerParameters
|
|
4
|
+
from mcp.client.stdio import stdio_client
|
|
5
|
+
from mcp.client.streamable_http import streamablehttp_client
|
|
6
|
+
|
|
7
|
+
from datetime import timedelta
|
|
8
|
+
from pydantic import AnyUrl, TypeAdapter
|
|
9
|
+
from typing import Optional, Any, List, Union, Callable, Dict
|
|
10
|
+
from contextlib import AsyncExitStack, _AsyncGeneratorContextManager
|
|
11
|
+
|
|
12
|
+
from .McpTypes import McpTool, McpPrompt, McpResource, McpToolParameters
|
|
13
|
+
|
|
14
|
+
# Model context protocol client.
|
|
15
|
+
class McpClient:
|
|
16
|
+
"""
|
|
17
|
+
Model context protocol client.
|
|
18
|
+
"""
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.open = False
|
|
21
|
+
self.timeout: timedelta = timedelta(seconds=60) # default timeout 60 seconds
|
|
22
|
+
self.logEvent: Callable[[str, str, str, Any], None] | None = None
|
|
23
|
+
|
|
24
|
+
# Initialize session and client objects
|
|
25
|
+
self.session: Optional[ClientSession] = None
|
|
26
|
+
self.exit_stack = AsyncExitStack()
|
|
27
|
+
|
|
28
|
+
# init
|
|
29
|
+
self.tools: List[McpTool] = []
|
|
30
|
+
self.prompts: List[McpPrompt] = []
|
|
31
|
+
self.resources: List[McpResource] = []
|
|
32
|
+
|
|
33
|
+
def onEvent(self, event: Callable[[str, str, str, Any], None]) -> None:
|
|
34
|
+
"""
|
|
35
|
+
subscribe to the on event.
|
|
36
|
+
Args:
|
|
37
|
+
event: the log event handler.
|
|
38
|
+
"""
|
|
39
|
+
self.logEvent = event
|
|
40
|
+
|
|
41
|
+
def setTimeout(self, timeout: timedelta) -> None:
|
|
42
|
+
"""
|
|
43
|
+
set the timeout in seconds (default timeout 60 seconds).
|
|
44
|
+
Args:
|
|
45
|
+
timeout: the timeout in seconds.
|
|
46
|
+
"""
|
|
47
|
+
self.timeout = timeout
|
|
48
|
+
|
|
49
|
+
def isConnected(self) -> bool:
|
|
50
|
+
"""
|
|
51
|
+
is connected to MCP server.
|
|
52
|
+
|
|
53
|
+
Return:
|
|
54
|
+
true if connected to server; else false.
|
|
55
|
+
"""
|
|
56
|
+
return self.open
|
|
57
|
+
|
|
58
|
+
def getTools(self) -> List[McpTool]:
|
|
59
|
+
"""
|
|
60
|
+
get the list of tools
|
|
61
|
+
|
|
62
|
+
Return:
|
|
63
|
+
the list of tools; else empty.
|
|
64
|
+
"""
|
|
65
|
+
return self.tools
|
|
66
|
+
|
|
67
|
+
def getPrompts(self) -> List[McpPrompt]:
|
|
68
|
+
"""
|
|
69
|
+
get the list of prompts
|
|
70
|
+
|
|
71
|
+
Return:
|
|
72
|
+
the list of prompts; else empty.
|
|
73
|
+
"""
|
|
74
|
+
return self.prompts
|
|
75
|
+
|
|
76
|
+
def getResources(self) -> List[McpResource]:
|
|
77
|
+
"""
|
|
78
|
+
get the list of resources
|
|
79
|
+
|
|
80
|
+
Return:
|
|
81
|
+
the list of resources; else empty.
|
|
82
|
+
"""
|
|
83
|
+
return self.resources
|
|
84
|
+
|
|
85
|
+
async def callTool(self, name: str, args: Dict[str, Any] | None = None) -> Any | None:
|
|
86
|
+
"""
|
|
87
|
+
call the tool.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
name: the name of the tool
|
|
91
|
+
args: the arguments
|
|
92
|
+
|
|
93
|
+
Return:
|
|
94
|
+
the result; else none.
|
|
95
|
+
"""
|
|
96
|
+
# if open.
|
|
97
|
+
if self.open:
|
|
98
|
+
return await self.session.call_tool(name, arguments = args, read_timeout_seconds = self.timeout)
|
|
99
|
+
else:
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
async def callPrompt(self, name: str, args: Dict[str, str] | None = None) -> Any | None:
|
|
103
|
+
"""
|
|
104
|
+
read the resource.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
name: the name of the prompt
|
|
108
|
+
args: the arguments
|
|
109
|
+
|
|
110
|
+
Return:
|
|
111
|
+
the result; else none.
|
|
112
|
+
"""
|
|
113
|
+
# if open.
|
|
114
|
+
if self.open:
|
|
115
|
+
return await self.session.get_prompt(name, arguments = args)
|
|
116
|
+
else:
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
async def callResource(self, uri: AnyUrl) -> Any | None:
|
|
120
|
+
"""
|
|
121
|
+
read the resource.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
uri: the resource URI
|
|
125
|
+
|
|
126
|
+
Return:
|
|
127
|
+
the result; else none.
|
|
128
|
+
"""
|
|
129
|
+
# if open.
|
|
130
|
+
if self.open:
|
|
131
|
+
return await self.session.read_resource(uri)
|
|
132
|
+
else:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
async def closeConnection(self):
|
|
136
|
+
"""
|
|
137
|
+
disconnect from the MCP server.
|
|
138
|
+
"""
|
|
139
|
+
self.session = None
|
|
140
|
+
self.tools = []
|
|
141
|
+
self.prompts = []
|
|
142
|
+
self.resources = []
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
# close the stack.
|
|
146
|
+
await self.exit_stack.aclose()
|
|
147
|
+
except Exception as e:
|
|
148
|
+
if (self.logEvent):
|
|
149
|
+
self.logEvent("error", "mcpclient", "client close", e)
|
|
150
|
+
|
|
151
|
+
# closed
|
|
152
|
+
self.logEvent = None
|
|
153
|
+
self.open = False
|
|
154
|
+
|
|
155
|
+
async def openConnectionStdio(self, serverScriptPath: str):
|
|
156
|
+
"""
|
|
157
|
+
connect to the MCP server.
|
|
158
|
+
start receiving messages on stdin and sending messages on stdout.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
serverScriptPath: the server script full path
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
# if not open.
|
|
165
|
+
if not self.open:
|
|
166
|
+
try:
|
|
167
|
+
|
|
168
|
+
# only if JavaScript or Python
|
|
169
|
+
is_python = serverScriptPath.endswith('.py')
|
|
170
|
+
is_js = serverScriptPath.endswith('.js')
|
|
171
|
+
|
|
172
|
+
# if not JavaScript and not Python
|
|
173
|
+
if not (is_python or is_js):
|
|
174
|
+
raise ValueError("Server script must be a .py or .js file")
|
|
175
|
+
|
|
176
|
+
# the command to execute
|
|
177
|
+
command = "python" if is_python else "node"
|
|
178
|
+
server_params = StdioServerParameters(
|
|
179
|
+
command = command,
|
|
180
|
+
args = [serverScriptPath],
|
|
181
|
+
env = None
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# open a connection to the MCP server.
|
|
185
|
+
stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
|
|
186
|
+
self.read, self.write = stdio_transport
|
|
187
|
+
self.session = await self.exit_stack.enter_async_context(ClientSession(self.read, self.write))
|
|
188
|
+
|
|
189
|
+
# start session.
|
|
190
|
+
await self.session.initialize()
|
|
191
|
+
|
|
192
|
+
# client connected.
|
|
193
|
+
self.open = True
|
|
194
|
+
|
|
195
|
+
# request.
|
|
196
|
+
await self.requestTools()
|
|
197
|
+
await self.requestPrompts()
|
|
198
|
+
await self.requestResources()
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
self.open = False
|
|
202
|
+
if (self.logEvent):
|
|
203
|
+
self.logEvent("error", "open", "open connection stdio", e)
|
|
204
|
+
raise # Re-throws the same exception
|
|
205
|
+
|
|
206
|
+
async def openConnectionStdioCustom(self, command: str, argsList: List[str] | None = None, envList: Dict[str, str] | None = None):
|
|
207
|
+
"""
|
|
208
|
+
connect to the MCP server.
|
|
209
|
+
start receiving messages on stdin and sending messages on stdout.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
command: the executable to run to start the server.
|
|
213
|
+
argsList: command line arguments to pass to the executable.
|
|
214
|
+
envList: the environment to use when spawning the process.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
# if not open.
|
|
218
|
+
if not self.open:
|
|
219
|
+
try:
|
|
220
|
+
|
|
221
|
+
# the command to execute
|
|
222
|
+
server_params = StdioServerParameters(
|
|
223
|
+
command = command,
|
|
224
|
+
args = argsList,
|
|
225
|
+
env = envList
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# open a connection to the MCP server.
|
|
229
|
+
stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
|
|
230
|
+
self.read, self.write = stdio_transport
|
|
231
|
+
self.session = await self.exit_stack.enter_async_context(ClientSession(self.read, self.write))
|
|
232
|
+
|
|
233
|
+
# start session.
|
|
234
|
+
await self.session.initialize()
|
|
235
|
+
|
|
236
|
+
# client connected.
|
|
237
|
+
self.open = True
|
|
238
|
+
|
|
239
|
+
# request.
|
|
240
|
+
await self.requestTools()
|
|
241
|
+
await self.requestPrompts()
|
|
242
|
+
await self.requestResources()
|
|
243
|
+
|
|
244
|
+
except Exception as e:
|
|
245
|
+
self.open = False
|
|
246
|
+
if (self.logEvent):
|
|
247
|
+
self.logEvent("error", "open", "open connection stdio custom", e)
|
|
248
|
+
raise # Re-throws the same exception
|
|
249
|
+
|
|
250
|
+
async def openConnectionStdioServerParam(self, server: StdioServerParameters):
|
|
251
|
+
"""
|
|
252
|
+
connect to the MCP server.
|
|
253
|
+
start receiving messages on stdin and sending messages on stdout.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
server: stdio server parameters.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
# if not open.
|
|
260
|
+
if not self.open:
|
|
261
|
+
try:
|
|
262
|
+
|
|
263
|
+
# open a connection to the MCP server.
|
|
264
|
+
stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server))
|
|
265
|
+
self.read, self.write = stdio_transport
|
|
266
|
+
self.session = await self.exit_stack.enter_async_context(ClientSession(self.read, self.write))
|
|
267
|
+
|
|
268
|
+
# start session.
|
|
269
|
+
await self.session.initialize()
|
|
270
|
+
|
|
271
|
+
# client connected.
|
|
272
|
+
self.open = True
|
|
273
|
+
|
|
274
|
+
# request.
|
|
275
|
+
await self.requestTools()
|
|
276
|
+
await self.requestPrompts()
|
|
277
|
+
await self.requestResources()
|
|
278
|
+
|
|
279
|
+
except Exception as e:
|
|
280
|
+
self.open = False
|
|
281
|
+
if (self.logEvent):
|
|
282
|
+
self.logEvent("error", "open", "open connection stdio server param", e)
|
|
283
|
+
raise # Re-throws the same exception
|
|
284
|
+
|
|
285
|
+
async def openConnectionHttp(self, serverUrl: str, requestInit: Dict[str, str] | None = None):
|
|
286
|
+
"""
|
|
287
|
+
connect to the MCP server.
|
|
288
|
+
start receiving messages on streamable HTTP.
|
|
289
|
+
For remote servers, set up a Streamable HTTP transport that handles
|
|
290
|
+
both client requests and server-to-client notifications.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
serverUrl: the server URL path.
|
|
294
|
+
requestInit: ustomizes HTTP requests to the server.
|
|
295
|
+
|
|
296
|
+
Example:
|
|
297
|
+
serverUrl: https://example.com/mcp
|
|
298
|
+
requestInit: {
|
|
299
|
+
'Authorization': 'Bearer <secret>'
|
|
300
|
+
}
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
# if not open.
|
|
304
|
+
if not self.open:
|
|
305
|
+
try:
|
|
306
|
+
http_transport = None
|
|
307
|
+
|
|
308
|
+
# open a connection to the MCP server.
|
|
309
|
+
if(requestInit is None):
|
|
310
|
+
http_transport = await self.exit_stack.enter_async_context(
|
|
311
|
+
streamablehttp_client(serverUrl, timeout=self.timeout))
|
|
312
|
+
else:
|
|
313
|
+
http_transport = await self.exit_stack.enter_async_context(
|
|
314
|
+
streamablehttp_client(url=serverUrl, headers=requestInit, timeout=self.timeout))
|
|
315
|
+
|
|
316
|
+
# get streams
|
|
317
|
+
self.read, self.write, _, = http_transport
|
|
318
|
+
self.session = await self.exit_stack.enter_async_context(ClientSession(self.read, self.write))
|
|
319
|
+
|
|
320
|
+
# Initialize the connection
|
|
321
|
+
await self.session.initialize()
|
|
322
|
+
|
|
323
|
+
# client connected.
|
|
324
|
+
self.open = True
|
|
325
|
+
|
|
326
|
+
# request.
|
|
327
|
+
await self.requestTools()
|
|
328
|
+
await self.requestPrompts()
|
|
329
|
+
await self.requestResources()
|
|
330
|
+
|
|
331
|
+
except Exception as e:
|
|
332
|
+
self.open = False
|
|
333
|
+
if (self.logEvent):
|
|
334
|
+
self.logEvent("error", "open", "open connection http", e)
|
|
335
|
+
raise # Re-throws the same exception
|
|
336
|
+
|
|
337
|
+
async def openConnectionHttpCustom(self, serverUrl: str, headers: Dict[str, str] | None = None, auth: httpx.Auth | None = None):
|
|
338
|
+
"""
|
|
339
|
+
connect to the MCP server.
|
|
340
|
+
start receiving messages on streamable HTTP.
|
|
341
|
+
For remote servers, set up a Streamable HTTP transport that handles
|
|
342
|
+
both client requests and server-to-client notifications.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
serverUrl: the server URL path.
|
|
346
|
+
headers: ustomizes HTTP requests to the server.
|
|
347
|
+
auth: ustomizes HTTP authorization to the server.
|
|
348
|
+
|
|
349
|
+
Example:
|
|
350
|
+
serverUrl: https://example.com/mcp
|
|
351
|
+
headers: {
|
|
352
|
+
'Authorization': 'Bearer <secret>'
|
|
353
|
+
}
|
|
354
|
+
"""
|
|
355
|
+
|
|
356
|
+
# if not open.
|
|
357
|
+
if not self.open:
|
|
358
|
+
try:
|
|
359
|
+
http_transport = None
|
|
360
|
+
|
|
361
|
+
# open a connection to the MCP server.
|
|
362
|
+
http_transport = await self.exit_stack.enter_async_context(
|
|
363
|
+
streamablehttp_client(url=serverUrl, headers=headers, timeout=self.timeout, auth=auth))
|
|
364
|
+
|
|
365
|
+
# get streams
|
|
366
|
+
self.read, self.write, _, = http_transport
|
|
367
|
+
self.session = await self.exit_stack.enter_async_context(ClientSession(self.read, self.write))
|
|
368
|
+
|
|
369
|
+
# Initialize the connection
|
|
370
|
+
await self.session.initialize()
|
|
371
|
+
|
|
372
|
+
# client connected.
|
|
373
|
+
self.open = True
|
|
374
|
+
|
|
375
|
+
# request.
|
|
376
|
+
await self.requestTools()
|
|
377
|
+
await self.requestPrompts()
|
|
378
|
+
await self.requestResources()
|
|
379
|
+
|
|
380
|
+
except Exception as e:
|
|
381
|
+
self.open = False
|
|
382
|
+
if (self.logEvent):
|
|
383
|
+
self.logEvent("error", "open", "open connection http custom", e)
|
|
384
|
+
raise # Re-throws the same exception
|
|
385
|
+
|
|
386
|
+
async def openConnectionHttpTransport(self, transport: _AsyncGeneratorContextManager):
|
|
387
|
+
"""
|
|
388
|
+
connect to the MCP server.
|
|
389
|
+
start receiving messages on streamable HTTP.
|
|
390
|
+
For remote servers, set up a Streamable HTTP transport that handles
|
|
391
|
+
both client requests and server-to-client notifications.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
transport: the transport to use to connect to the server. A streamablehttp_client implementation.
|
|
395
|
+
|
|
396
|
+
Example:
|
|
397
|
+
from botocore.credentials import Credentials
|
|
398
|
+
from mcp_proxy_for_aws.client import aws_iam_streamablehttp_client
|
|
399
|
+
|
|
400
|
+
creds = Credentials(access_key="KEY", secret_key="SECRET")
|
|
401
|
+
|
|
402
|
+
transport = aws_iam_streamablehttp_client(
|
|
403
|
+
endpoint="https://example.com/mcp",
|
|
404
|
+
aws_service="lambda",
|
|
405
|
+
aws_region="ap-southeast-2",
|
|
406
|
+
credentials=creds
|
|
407
|
+
)
|
|
408
|
+
"""
|
|
409
|
+
|
|
410
|
+
# if not open.
|
|
411
|
+
if not self.open:
|
|
412
|
+
try:
|
|
413
|
+
http_transport = None
|
|
414
|
+
|
|
415
|
+
# open a connection to the MCP server.
|
|
416
|
+
http_transport = await self.exit_stack.enter_async_context(transport)
|
|
417
|
+
|
|
418
|
+
# get streams
|
|
419
|
+
self.read, self.write, _, = http_transport
|
|
420
|
+
self.session = await self.exit_stack.enter_async_context(ClientSession(self.read, self.write))
|
|
421
|
+
|
|
422
|
+
# Initialize the connection
|
|
423
|
+
await self.session.initialize()
|
|
424
|
+
|
|
425
|
+
# client connected.
|
|
426
|
+
self.open = True
|
|
427
|
+
|
|
428
|
+
# request.
|
|
429
|
+
await self.requestTools()
|
|
430
|
+
await self.requestPrompts()
|
|
431
|
+
await self.requestResources()
|
|
432
|
+
|
|
433
|
+
except Exception as e:
|
|
434
|
+
self.open = False
|
|
435
|
+
if (self.logEvent):
|
|
436
|
+
self.logEvent("error", "open", "open connection http custom", e)
|
|
437
|
+
raise # Re-throws the same exception
|
|
438
|
+
|
|
439
|
+
async def requestTools(self) -> bool:
|
|
440
|
+
"""
|
|
441
|
+
request the tools list.
|
|
442
|
+
|
|
443
|
+
Return:
|
|
444
|
+
true if list call succeeded: else false.
|
|
445
|
+
"""
|
|
446
|
+
haslist: bool = False
|
|
447
|
+
|
|
448
|
+
# if open.
|
|
449
|
+
if self.open:
|
|
450
|
+
self.tools = []
|
|
451
|
+
|
|
452
|
+
try:
|
|
453
|
+
# load all tools.
|
|
454
|
+
toolsResult = await self.session.list_tools()
|
|
455
|
+
if toolsResult is not None:
|
|
456
|
+
if toolsResult.tools is not None:
|
|
457
|
+
for tool in toolsResult.tools:
|
|
458
|
+
# create the tool model.
|
|
459
|
+
self.tools.append(McpTool(
|
|
460
|
+
tool.name,
|
|
461
|
+
tool.name,
|
|
462
|
+
tool.description,
|
|
463
|
+
tool.inputSchema,
|
|
464
|
+
McpToolParameters(tool.inputSchema)
|
|
465
|
+
))
|
|
466
|
+
|
|
467
|
+
haslist = True
|
|
468
|
+
except Exception as e:
|
|
469
|
+
if (self.logEvent):
|
|
470
|
+
self.logEvent("error", "tools", "request tools", e)
|
|
471
|
+
|
|
472
|
+
return haslist
|
|
473
|
+
|
|
474
|
+
async def requestPrompts(self) -> bool:
|
|
475
|
+
"""
|
|
476
|
+
request the prompts list.
|
|
477
|
+
|
|
478
|
+
Return:
|
|
479
|
+
true if list call succeeded: else false.
|
|
480
|
+
"""
|
|
481
|
+
haslist: bool = False
|
|
482
|
+
|
|
483
|
+
# if open.
|
|
484
|
+
if self.open:
|
|
485
|
+
self.prompts = []
|
|
486
|
+
|
|
487
|
+
try:
|
|
488
|
+
# load all prompts.
|
|
489
|
+
promptsResult = await self.session.list_prompts()
|
|
490
|
+
if promptsResult is not None:
|
|
491
|
+
if promptsResult.prompts is not None:
|
|
492
|
+
for prompt in promptsResult.prompts:
|
|
493
|
+
# create the prompt model.
|
|
494
|
+
self.prompts.append(McpPrompt(
|
|
495
|
+
prompt.name,
|
|
496
|
+
prompt.name,
|
|
497
|
+
prompt.description,
|
|
498
|
+
prompt.arguments
|
|
499
|
+
))
|
|
500
|
+
|
|
501
|
+
haslist = True
|
|
502
|
+
except Exception as e:
|
|
503
|
+
if (self.logEvent):
|
|
504
|
+
self.logEvent("error", "prompts", "request prompts", e)
|
|
505
|
+
|
|
506
|
+
return haslist
|
|
507
|
+
|
|
508
|
+
async def requestResources(self) -> bool:
|
|
509
|
+
"""
|
|
510
|
+
request the resources list.
|
|
511
|
+
|
|
512
|
+
Return:
|
|
513
|
+
true if list call succeeded: else false.
|
|
514
|
+
"""
|
|
515
|
+
haslist: bool = False
|
|
516
|
+
|
|
517
|
+
# if open.
|
|
518
|
+
if self.open:
|
|
519
|
+
self.resources = []
|
|
520
|
+
|
|
521
|
+
try:
|
|
522
|
+
# load all resources.
|
|
523
|
+
resourcesResult = await self.session.list_resources()
|
|
524
|
+
if resourcesResult is not None:
|
|
525
|
+
if resourcesResult.resources is not None:
|
|
526
|
+
for resource in resourcesResult.resources:
|
|
527
|
+
# create the resource model.
|
|
528
|
+
self.resources.append(McpResource(
|
|
529
|
+
resource.name,
|
|
530
|
+
resource.name,
|
|
531
|
+
resource.description,
|
|
532
|
+
resource.uri,
|
|
533
|
+
resource.mimeType
|
|
534
|
+
))
|
|
535
|
+
|
|
536
|
+
haslist = True
|
|
537
|
+
except Exception as e:
|
|
538
|
+
haslist = False
|
|
539
|
+
if (self.logEvent):
|
|
540
|
+
self.logEvent("error", "resources", "request resources", e)
|
|
541
|
+
|
|
542
|
+
try:
|
|
543
|
+
# load all resources.
|
|
544
|
+
resourcesResultTemplates = await self.session.list_resource_templates()
|
|
545
|
+
if resourcesResultTemplates is not None:
|
|
546
|
+
if resourcesResultTemplates.resourceTemplates is not None:
|
|
547
|
+
for resource in resourcesResultTemplates.resourceTemplates:
|
|
548
|
+
# create the resource model.
|
|
549
|
+
self.resources.append(McpResource(
|
|
550
|
+
resource.name,
|
|
551
|
+
resource.name,
|
|
552
|
+
resource.description,
|
|
553
|
+
resource.uriTemplate,
|
|
554
|
+
resource.mimeType
|
|
555
|
+
))
|
|
556
|
+
|
|
557
|
+
haslist = True
|
|
558
|
+
except Exception as e:
|
|
559
|
+
haslist = False
|
|
560
|
+
if (self.logEvent):
|
|
561
|
+
self.logEvent("error", "resources_templates", "request resource templates", e)
|
|
562
|
+
|
|
563
|
+
return haslist
|