fast-agent-mcp 0.2.20__py3-none-any.whl → 0.2.21__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.
- {fast_agent_mcp-0.2.20.dist-info → fast_agent_mcp-0.2.21.dist-info}/METADATA +2 -2
- {fast_agent_mcp-0.2.20.dist-info → fast_agent_mcp-0.2.21.dist-info}/RECORD +8 -8
- mcp_agent/mcp/mcp_agent_client_session.py +5 -1
- mcp_agent/mcp/mcp_aggregator.py +22 -17
- mcp_agent/mcp/prompts/prompt_server.py +12 -1
- {fast_agent_mcp-0.2.20.dist-info → fast_agent_mcp-0.2.21.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.2.20.dist-info → fast_agent_mcp-0.2.21.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.2.20.dist-info → fast_agent_mcp-0.2.21.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fast-agent-mcp
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.21
|
4
4
|
Summary: Define, Prompt and Test MCP enabled Agents and Workflows
|
5
5
|
Author-email: Shaun Smith <fastagent@llmindset.co.uk>, Sarmad Qadri <sarmad@lastmileai.dev>
|
6
6
|
License: Apache License
|
@@ -213,7 +213,7 @@ Requires-Dist: a2a-types>=0.1.0
|
|
213
213
|
Requires-Dist: aiohttp>=3.11.13
|
214
214
|
Requires-Dist: anthropic>=0.49.0
|
215
215
|
Requires-Dist: fastapi>=0.115.6
|
216
|
-
Requires-Dist: mcp
|
216
|
+
Requires-Dist: mcp~=1.7.0
|
217
217
|
Requires-Dist: openai>=1.63.2
|
218
218
|
Requires-Dist: opentelemetry-distro>=0.50b0
|
219
219
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.29.0
|
@@ -83,8 +83,8 @@ mcp_agent/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
83
|
mcp_agent/mcp/gen_client.py,sha256=fAVwFVCgSamw4PwoWOV4wrK9TABx1S_zZv8BctRyF2k,3030
|
84
84
|
mcp_agent/mcp/interfaces.py,sha256=PAou8znAl2HgtvfCpLQOZFbKra9F72OcVRfBJbboNX8,6965
|
85
85
|
mcp_agent/mcp/logger_textio.py,sha256=vljC1BtNTCxBAda9ExqNB-FwVNUZIuJT3h1nWmCjMws,3172
|
86
|
-
mcp_agent/mcp/mcp_agent_client_session.py,sha256=
|
87
|
-
mcp_agent/mcp/mcp_aggregator.py,sha256=
|
86
|
+
mcp_agent/mcp/mcp_agent_client_session.py,sha256=Ng7epBXq8BEA_3m1GX5LqwafgNUAMSzBugwN6N0VUWQ,4364
|
87
|
+
mcp_agent/mcp/mcp_aggregator.py,sha256=lVSt0yp0CnaYjcHCWmluwBeFgl8JXHYEZk0MzXgrQzA,40110
|
88
88
|
mcp_agent/mcp/mcp_connection_manager.py,sha256=L5Dk4cyarN_v2rfktkrfZJR4xUuD3yN_hUyQnKHBWgM,14044
|
89
89
|
mcp_agent/mcp/mime_utils.py,sha256=difepNR_gpb4MpMLkBRAoyhDk-AjXUHTiqKvT_VwS1o,1805
|
90
90
|
mcp_agent/mcp/prompt_message_multipart.py,sha256=BDwRdNwyWHb2q2bccDb2iR2VlORqVvkvoG3xYzcMpCE,4403
|
@@ -99,7 +99,7 @@ mcp_agent/mcp/prompts/__main__.py,sha256=gr1Tdz9fcK0EXjEuZg_BOnKUmvhYq5AH2lFZicV
|
|
99
99
|
mcp_agent/mcp/prompts/prompt_constants.py,sha256=Q9W0t3rOXl2LHIG9wcghApUV2QZ1iICuo7SwVwHUf3c,566
|
100
100
|
mcp_agent/mcp/prompts/prompt_helpers.py,sha256=Joqo2t09pTKDP-Wge3G-ozPEHikzjaqwV6GVk8hNR50,7534
|
101
101
|
mcp_agent/mcp/prompts/prompt_load.py,sha256=Zo0FogqWFEG5FtF1d9ZH-RWsCSSMsi5FIEQHpJD8N7M,5404
|
102
|
-
mcp_agent/mcp/prompts/prompt_server.py,sha256=
|
102
|
+
mcp_agent/mcp/prompts/prompt_server.py,sha256=DbuDcYCMbsbqwBeebpNGInAQ4-DP1Jjp49y8uZ-0XlY,18872
|
103
103
|
mcp_agent/mcp/prompts/prompt_template.py,sha256=EejiqGkau8OizORNyKTUwUjrPof5V-hH1H_MBQoQfXw,15732
|
104
104
|
mcp_agent/mcp_server/__init__.py,sha256=zBU51ITHIEPScd9nRafnhEddsWqXRPAAvHhkrbRI2_4,155
|
105
105
|
mcp_agent/mcp_server/agent_server.py,sha256=s-nI0uTNWx4nYDDM_5GmuY5x6ZeFkymfNoCSuwuBRd8,19891
|
@@ -143,8 +143,8 @@ mcp_agent/resources/examples/workflows/parallel.py,sha256=DQ5vY5-h8Qa5QHcYjsWXhZ
|
|
143
143
|
mcp_agent/resources/examples/workflows/router.py,sha256=E4x_-c3l4YW9w1i4ARcDtkdeqIdbWEGfsMzwLYpdbVc,1677
|
144
144
|
mcp_agent/resources/examples/workflows/short_story.txt,sha256=X3y_1AyhLFN2AKzCKvucJtDgAFIJfnlbsbGZO5bBWu0,1187
|
145
145
|
mcp_agent/ui/console_display.py,sha256=TVGDtJ37hc6UG0ei9g7ZPZZfFNeS1MYozt-Mx8HsPCk,9752
|
146
|
-
fast_agent_mcp-0.2.
|
147
|
-
fast_agent_mcp-0.2.
|
148
|
-
fast_agent_mcp-0.2.
|
149
|
-
fast_agent_mcp-0.2.
|
150
|
-
fast_agent_mcp-0.2.
|
146
|
+
fast_agent_mcp-0.2.21.dist-info/METADATA,sha256=c-Aq5664t9xi4iW2mcDHUGaDL_jRUznn_nyeMVFJzgY,30142
|
147
|
+
fast_agent_mcp-0.2.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
148
|
+
fast_agent_mcp-0.2.21.dist-info/entry_points.txt,sha256=bRniFM5zk3Kix5z7scX0gf9VnmGQ2Cz_Q1Gh7Ir4W00,186
|
149
|
+
fast_agent_mcp-0.2.21.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
|
150
|
+
fast_agent_mcp-0.2.21.dist-info/RECORD,,
|
@@ -3,6 +3,7 @@ A derived client session for the MCP Agent framework.
|
|
3
3
|
It adds logging and supports sampling requests.
|
4
4
|
"""
|
5
5
|
|
6
|
+
from datetime import timedelta
|
6
7
|
from typing import TYPE_CHECKING, Optional
|
7
8
|
|
8
9
|
from mcp import ClientSession
|
@@ -73,10 +74,13 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
|
|
73
74
|
self,
|
74
75
|
request: SendRequestT,
|
75
76
|
result_type: type[ReceiveResultT],
|
77
|
+
request_read_timeout_seconds: timedelta | None = None,
|
76
78
|
) -> ReceiveResultT:
|
77
79
|
logger.debug("send_request: request=", data=request.model_dump())
|
78
80
|
try:
|
79
|
-
result = await super().send_request(
|
81
|
+
result = await super().send_request(
|
82
|
+
request, result_type, request_read_timeout_seconds=request_read_timeout_seconds
|
83
|
+
)
|
80
84
|
logger.debug("send_request: response=", data=result.model_dump())
|
81
85
|
return result
|
82
86
|
except Exception as e:
|
mcp_agent/mcp/mcp_aggregator.py
CHANGED
@@ -41,10 +41,12 @@ SEP = "-"
|
|
41
41
|
T = TypeVar("T")
|
42
42
|
R = TypeVar("R")
|
43
43
|
|
44
|
+
|
44
45
|
def create_namespaced_name(server_name: str, resource_name: str) -> str:
|
45
46
|
"""Create a namespaced resource name from server and resource names"""
|
46
47
|
return f"{server_name}{SEP}{resource_name}"
|
47
48
|
|
49
|
+
|
48
50
|
def is_namespaced_name(name: str) -> bool:
|
49
51
|
"""Check if a name is already namespaced"""
|
50
52
|
return SEP in name
|
@@ -325,14 +327,14 @@ class MCPAggregator(ContextDependent):
|
|
325
327
|
except Exception as e:
|
326
328
|
logger.debug(f"Error getting capabilities for server '{server_name}': {e}")
|
327
329
|
return None
|
328
|
-
|
330
|
+
|
329
331
|
async def validate_server(self, server_name: str) -> bool:
|
330
332
|
"""
|
331
333
|
Validate that a server exists in our server list.
|
332
|
-
|
334
|
+
|
333
335
|
Args:
|
334
336
|
server_name: Name of the server to validate
|
335
|
-
|
337
|
+
|
336
338
|
Returns:
|
337
339
|
True if the server exists, False otherwise
|
338
340
|
"""
|
@@ -340,25 +342,25 @@ class MCPAggregator(ContextDependent):
|
|
340
342
|
if not valid:
|
341
343
|
logger.debug(f"Server '{server_name}' not found")
|
342
344
|
return valid
|
343
|
-
|
345
|
+
|
344
346
|
async def server_supports_feature(self, server_name: str, feature: str) -> bool:
|
345
347
|
"""
|
346
348
|
Check if a server supports a specific feature.
|
347
|
-
|
349
|
+
|
348
350
|
Args:
|
349
351
|
server_name: Name of the server to check
|
350
352
|
feature: Feature to check for (e.g., "prompts", "resources")
|
351
|
-
|
353
|
+
|
352
354
|
Returns:
|
353
355
|
True if the server supports the feature, False otherwise
|
354
356
|
"""
|
355
357
|
if not await self.validate_server(server_name):
|
356
358
|
return False
|
357
|
-
|
359
|
+
|
358
360
|
capabilities = await self.get_capabilities(server_name)
|
359
361
|
if not capabilities:
|
360
362
|
return False
|
361
|
-
|
363
|
+
|
362
364
|
return getattr(capabilities, feature, False)
|
363
365
|
|
364
366
|
async def list_servers(self) -> List[str]:
|
@@ -465,26 +467,26 @@ class MCPAggregator(ContextDependent):
|
|
465
467
|
if resource_type == "tool" and name in self._namespaced_tool_map:
|
466
468
|
namespaced_tool = self._namespaced_tool_map[name]
|
467
469
|
return namespaced_tool.server_name, namespaced_tool.tool.name
|
468
|
-
|
470
|
+
|
469
471
|
# Next, attempt to interpret as a namespaced name
|
470
472
|
if is_namespaced_name(name):
|
471
473
|
parts = name.split(SEP, 1)
|
472
474
|
server_name, local_name = parts[0], parts[1]
|
473
|
-
|
475
|
+
|
474
476
|
# Validate that the parsed server actually exists
|
475
477
|
if server_name in self.server_names:
|
476
478
|
return server_name, local_name
|
477
|
-
|
479
|
+
|
478
480
|
# If the server name doesn't exist, it might be a tool with a hyphen in its name
|
479
481
|
# Fall through to the next checks
|
480
|
-
|
482
|
+
|
481
483
|
# For tools, search all servers for the tool by exact name match
|
482
484
|
if resource_type == "tool":
|
483
485
|
for server_name, tools in self._server_to_tool_map.items():
|
484
486
|
for namespaced_tool in tools:
|
485
487
|
if namespaced_tool.tool.name == name:
|
486
488
|
return server_name, name
|
487
|
-
|
489
|
+
|
488
490
|
# For all other resource types, use the first server
|
489
491
|
return (self.server_names[0] if self.server_names else None, name)
|
490
492
|
|
@@ -524,7 +526,10 @@ class MCPAggregator(ContextDependent):
|
|
524
526
|
operation_type="tool",
|
525
527
|
operation_name=local_tool_name,
|
526
528
|
method_name="call_tool",
|
527
|
-
method_args={
|
529
|
+
method_args={
|
530
|
+
"name": local_tool_name,
|
531
|
+
"arguments": arguments,
|
532
|
+
},
|
528
533
|
error_factory=lambda msg: CallToolResult(
|
529
534
|
isError=True, content=[TextContent(type="text", text=msg)]
|
530
535
|
),
|
@@ -558,7 +563,7 @@ class MCPAggregator(ContextDependent):
|
|
558
563
|
elif is_namespaced_name(prompt_name):
|
559
564
|
parts = prompt_name.split(SEP, 1)
|
560
565
|
potential_server = parts[0]
|
561
|
-
|
566
|
+
|
562
567
|
# Only treat as namespaced if the server part is valid
|
563
568
|
if potential_server in self.server_names:
|
564
569
|
server_name = potential_server
|
@@ -570,7 +575,7 @@ class MCPAggregator(ContextDependent):
|
|
570
575
|
else:
|
571
576
|
local_prompt_name = prompt_name
|
572
577
|
# We'll search all servers below
|
573
|
-
|
578
|
+
|
574
579
|
# If we have a specific server to check
|
575
580
|
if server_name:
|
576
581
|
if not await self.validate_server(server_name):
|
@@ -579,7 +584,7 @@ class MCPAggregator(ContextDependent):
|
|
579
584
|
description=f"Error: Server '{server_name}' not found",
|
580
585
|
messages=[],
|
581
586
|
)
|
582
|
-
|
587
|
+
|
583
588
|
# Check if server supports prompts
|
584
589
|
if not await self.server_supports_feature(server_name, "prompts"):
|
585
590
|
logger.debug(f"Server '{server_name}' does not support prompts")
|
@@ -82,6 +82,7 @@ class PromptConfig(PromptMetadata):
|
|
82
82
|
http_timeout: float = 10.0
|
83
83
|
transport: str = "stdio"
|
84
84
|
port: int = 8000
|
85
|
+
host: str = "0.0.0.0"
|
85
86
|
|
86
87
|
|
87
88
|
# We'll maintain registries of all exposed resources and prompts
|
@@ -344,6 +345,12 @@ def parse_args():
|
|
344
345
|
default=8000,
|
345
346
|
help="Port to use for SSE transport (default: 8000)",
|
346
347
|
)
|
348
|
+
parser.add_argument(
|
349
|
+
"--host",
|
350
|
+
type=str,
|
351
|
+
default="0.0.0.0",
|
352
|
+
help="Host to bind to for SSE transport (default: 0.0.0.0)",
|
353
|
+
)
|
347
354
|
parser.add_argument(
|
348
355
|
"--test", type=str, help="Test a specific prompt without starting the server"
|
349
356
|
)
|
@@ -380,6 +387,7 @@ def initialize_config(args) -> PromptConfig:
|
|
380
387
|
http_timeout=args.http_timeout,
|
381
388
|
transport=args.transport,
|
382
389
|
port=args.port,
|
390
|
+
host=args.host,
|
383
391
|
)
|
384
392
|
|
385
393
|
|
@@ -497,7 +505,10 @@ async def async_main() -> int:
|
|
497
505
|
if config.transport == "stdio":
|
498
506
|
await mcp.run_stdio_async()
|
499
507
|
else: # sse
|
500
|
-
#
|
508
|
+
# Set the host and port in settings before running the server
|
509
|
+
mcp.settings.host = config.host
|
510
|
+
mcp.settings.port = config.port
|
511
|
+
logger.info(f"Starting SSE server on {config.host}:{config.port}")
|
501
512
|
await mcp.run_sse_async()
|
502
513
|
return 0
|
503
514
|
|
File without changes
|
File without changes
|
File without changes
|