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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fast-agent-mcp
3
- Version: 0.2.20
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==1.6.0
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=RMYNltc2pDIzxwEJSS5589RbvPO0KWV4Y3jSyAmhKf0,4181
87
- mcp_agent/mcp/mcp_aggregator.py,sha256=c3UDWsTgHMcpHPx1p-vVru4y3eVO1jBQyLzwEMH2RHU,40237
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=SiUR2xYfd3vEpghnYRdzz2rFEMtAbCKx2xzUXgvz1g8,18501
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.20.dist-info/METADATA,sha256=RlU6MHHAJoP4xuuA8QsIspMEZfGdSKDo76so374wzA4,30142
147
- fast_agent_mcp-0.2.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
148
- fast_agent_mcp-0.2.20.dist-info/entry_points.txt,sha256=bRniFM5zk3Kix5z7scX0gf9VnmGQ2Cz_Q1Gh7Ir4W00,186
149
- fast_agent_mcp-0.2.20.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
150
- fast_agent_mcp-0.2.20.dist-info/RECORD,,
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(request, result_type)
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:
@@ -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={"name": local_tool_name, "arguments": arguments},
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
- # TODO update to 2025-03-26 specification and test config.
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