fast-agent-mcp 0.2.48__py3-none-any.whl → 0.2.49__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.

Potentially problematic release.


This version of fast-agent-mcp might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fast-agent-mcp
3
- Version: 0.2.48
3
+ Version: 0.2.49
4
4
  Summary: Define, Prompt and Test MCP enabled Agents and Workflows
5
5
  Author-email: Shaun Smith <fastagent@llmindset.co.uk>
6
6
  License: Apache License
@@ -1,6 +1,6 @@
1
1
  mcp_agent/__init__.py,sha256=HWWxZeB-VxrUNNXZnu4duzKGwdfCdD2M_O6drN4kfs8,2389
2
2
  mcp_agent/app.py,sha256=3mtHP1nRQcRaKhhxgTmCOv00alh70nT7UxNA8bN47QE,5560
3
- mcp_agent/config.py,sha256=GBmdsNlW8YqL8Dp-6Ke4ufQkFuLiaUSq_b8mciQ6sOQ,19382
3
+ mcp_agent/config.py,sha256=uwfZIdnO4NpYF90uQjOvwhgh4GqYnVfkqCahhN5jZHc,19248
4
4
  mcp_agent/console.py,sha256=Gjf2QLFumwG1Lav__c07X_kZxxEUSkzV-1_-YbAwcwo,813
5
5
  mcp_agent/context.py,sha256=lzz_Fyf9lz9BBAUt1bRVBlyyHjLkyeuyIziAi4qXYUk,7639
6
6
  mcp_agent/context_dependent.py,sha256=QXfhw3RaQCKfscEEBRGuZ3sdMWqkgShz2jJ1ivGGX1I,1455
@@ -68,7 +68,7 @@ mcp_agent/llm/augmented_llm_silent.py,sha256=IUnK_1Byy4D9TG0Pj46LFeNezgSTQ8d6MQI
68
68
  mcp_agent/llm/augmented_llm_slow.py,sha256=DDSD8bL2flmQrVHZm-UDs7sR8aHRWkDOcOW-mX_GPok,2067
69
69
  mcp_agent/llm/memory.py,sha256=pTOaTDV3EA3X68yKwEtUAu7s0xGIQQ_cKBhfYUnfR0w,8614
70
70
  mcp_agent/llm/model_database.py,sha256=7puiFtc1tH25M5JEnKdAxsEk9OeAMJHamXA1c37tdjw,9490
71
- mcp_agent/llm/model_factory.py,sha256=2Ii81GrFJ9FvyjVb4OUyb0FRT59iAi9Vido5v0kZa7w,11732
71
+ mcp_agent/llm/model_factory.py,sha256=WyuQm0hETOxECA9pjCm-Oo5Oh28186nsSWmjSntw2SE,11784
72
72
  mcp_agent/llm/prompt_utils.py,sha256=yWQHykoK13QRF7evHUKxVF0SpVLN-Bsft0Yixzvn0g0,4825
73
73
  mcp_agent/llm/provider_key_manager.py,sha256=LSWIgcXlrUS4sfBvQBCya82qC6NcXQPYLtDHwHNOXR4,3394
74
74
  mcp_agent/llm/provider_types.py,sha256=LfuVuFjcM_lMED0lkrNfKK8s8Fs1vbxugQsrcBE2CIY,1119
@@ -79,20 +79,20 @@ mcp_agent/llm/providers/__init__.py,sha256=heVxtmuqFJOnjjxHz4bWSqTAxXoN1E8twC_gQ
79
79
  mcp_agent/llm/providers/anthropic_utils.py,sha256=vYDN5G5jKMhD2CQg8veJYab7tvvzYkDMq8M1g_hUAQg,3275
80
80
  mcp_agent/llm/providers/augmented_llm_aliyun.py,sha256=TwqSQmRwnce_a904CSqsKWTzYRb-od8FFYlie2zwXcE,1101
81
81
  mcp_agent/llm/providers/augmented_llm_anthropic.py,sha256=U8znA9HSCOx4FlhIjl-J29nbYc8Y-T6BXevtXuDafio,30352
82
- mcp_agent/llm/providers/augmented_llm_azure.py,sha256=sBVWgY88F4OsdRSHl71BAT2p3XPvuZp844z1ubwcV7U,6098
82
+ mcp_agent/llm/providers/augmented_llm_azure.py,sha256=Xoo6dFst6L9SaGKurqptwwTUzr-sYsolZ-AFb_79puc,6098
83
83
  mcp_agent/llm/providers/augmented_llm_bedrock.py,sha256=nfby1udL07zPTOLlN_tFxd1h0JRioo2oIW7v4iP4Bnk,82267
84
84
  mcp_agent/llm/providers/augmented_llm_deepseek.py,sha256=YokCz22qzbq5DyFCzviB8L7LwO1v3FAEt3UlB2EXWMI,3818
85
85
  mcp_agent/llm/providers/augmented_llm_generic.py,sha256=5Uq8ZBhcFuQTt7koP_5ykolREh2iWu8zKhNbh3pM9lQ,1210
86
86
  mcp_agent/llm/providers/augmented_llm_google_native.py,sha256=c6zczfs-Iw70j3OYELHJ4S7CRwAddkeXinex_yLMhmU,22194
87
87
  mcp_agent/llm/providers/augmented_llm_google_oai.py,sha256=g_g46h-YuxqbRZiO_dVo5zO2OkX1yx7nb6xDaQbOvWs,1137
88
88
  mcp_agent/llm/providers/augmented_llm_groq.py,sha256=MEk_1elggzIGlMIrnRP5bQ7kcBvu5jCwK0AoImkpb7c,1050
89
- mcp_agent/llm/providers/augmented_llm_openai.py,sha256=faleOhWV9ShJ3QW8VhaHOcQsRpYHU1W44eVk6uEcguA,24359
89
+ mcp_agent/llm/providers/augmented_llm_openai.py,sha256=xsJ0IsvXKxDHlsZfku8SYd57AOSUdkdMujvGUyrBcNM,24971
90
90
  mcp_agent/llm/providers/augmented_llm_openrouter.py,sha256=xKhEfjQEOnjMjbHT2Dc0ZD0_Cyx7EfFz1wA3Uh9S6Xk,2341
91
91
  mcp_agent/llm/providers/augmented_llm_tensorzero.py,sha256=wxNffqdM1Psvfyya6Pmo__BZjyrek55_8iTRoH4TboI,20577
92
92
  mcp_agent/llm/providers/augmented_llm_xai.py,sha256=PpztvX26mTl2GPTCzoI24ugxlm5BPpqByHnKO19ej28,1332
93
93
  mcp_agent/llm/providers/google_converter.py,sha256=xCUVw4W7lqBvJMgSKKdzW4Y00zmHBgCR6pOoWLYQQfw,16699
94
94
  mcp_agent/llm/providers/multipart_converter_anthropic.py,sha256=QsgIwWJ14SNZsun3fKDQaUx5AYdk8X6UYeBgYlZgZN0,16607
95
- mcp_agent/llm/providers/multipart_converter_openai.py,sha256=1zHlkMKY-16RL8qnrx7kI53IHmCiqASNvYsAdofSq_I,17000
95
+ mcp_agent/llm/providers/multipart_converter_openai.py,sha256=8vBwX7PB62mV6pe4VvAj9YxzX1Dp1RJMZK1NWOMnioY,17998
96
96
  mcp_agent/llm/providers/multipart_converter_tensorzero.py,sha256=Tr3DgogthxqTw04ajblwE8aB3Ft42X7aSXsMlm5FP4k,8619
97
97
  mcp_agent/llm/providers/openai_multipart.py,sha256=qKBn7d3jSabnJmVgWweVzqh8q9mBqr09fsPmP92niAQ,6899
98
98
  mcp_agent/llm/providers/openai_utils.py,sha256=T4bTCL9f7DsoS_zoKgQKv_FUv_4n98vgbvaUpdWZJr8,1875
@@ -103,7 +103,7 @@ mcp_agent/logging/events.py,sha256=dSJJfuCd59-ZyYTVcf0M4HQd6iXb5k50PSAeoq1CpH0,4
103
103
  mcp_agent/logging/json_serializer.py,sha256=qkfxnR9ka6OgvwSpM2CggELbEtzzkApm0s_KYz11RDY,5791
104
104
  mcp_agent/logging/listeners.py,sha256=_S4Jp5_KWp0kUfrx4BxDdNCeQK3MNT3Zi9AaolPri7A,6648
105
105
  mcp_agent/logging/logger.py,sha256=v2_D5kWLSS9u4ueSU7q6cWF1oSmTVeAAtgnwR0LrbXI,11056
106
- mcp_agent/logging/rich_progress.py,sha256=uMAKDPO8TlhT7uTeJzOEwQPme8pu8qCADLNbsI1vV8g,5544
106
+ mcp_agent/logging/rich_progress.py,sha256=jZWjtIudHtfJhY6hK_uu4WEdszHq70OAzwSyasKKayA,6250
107
107
  mcp_agent/logging/transport.py,sha256=_RVckOdcs_mXv6Jwz-MPe0vVTQEKsbejHdteyK5hBQA,16960
108
108
  mcp_agent/mcp/__init__.py,sha256=yxtzSmWBNqRf_nJckqgzYoozyGKja05FvSRLLus_7eM,1100
109
109
  mcp_agent/mcp/common.py,sha256=MpSC0fLO21RcDz4VApah4C8_LisVGz7OXkR17Xw-9mY,431
@@ -113,7 +113,7 @@ mcp_agent/mcp/gen_client.py,sha256=fAVwFVCgSamw4PwoWOV4wrK9TABx1S_zZv8BctRyF2k,3
113
113
  mcp_agent/mcp/hf_auth.py,sha256=7szw4rkwRyK3J-sUTcVZHdwoLIZqlYo8XolJnZdjOww,4571
114
114
  mcp_agent/mcp/interfaces.py,sha256=pe8WKvu3dnNnPWmrkDlu15xdkhuRDAjLUMn2vIE0Mj8,7963
115
115
  mcp_agent/mcp/logger_textio.py,sha256=vljC1BtNTCxBAda9ExqNB-FwVNUZIuJT3h1nWmCjMws,3172
116
- mcp_agent/mcp/mcp_agent_client_session.py,sha256=nEHrSalG5z47BKGwE9ooOmlSTc4Gb7qdEut071Dwepo,8987
116
+ mcp_agent/mcp/mcp_agent_client_session.py,sha256=ssRgxMOzyCPyAr25AeRBz3Xr-08OBdmsJf8A-ofc3bY,9115
117
117
  mcp_agent/mcp/mcp_aggregator.py,sha256=D1xFBVVq_4Tn1Ka16SZTVB3qeU-FO5501ITHGXTuXs0,49730
118
118
  mcp_agent/mcp/mcp_connection_manager.py,sha256=dJxjnv2IRzlFIxrbPFl39-pmGcZHgyeMXVlMfqpREhE,17974
119
119
  mcp_agent/mcp/mime_utils.py,sha256=difepNR_gpb4MpMLkBRAoyhDk-AjXUHTiqKvT_VwS1o,1805
@@ -168,8 +168,8 @@ mcp_agent/resources/examples/workflows/short_story.txt,sha256=X3y_1AyhLFN2AKzCKv
168
168
  mcp_agent/tools/tool_definition.py,sha256=L3Pxl-uLEXqlVoo-bYuFTFALeI-2pIU44YgFhsTKEtM,398
169
169
  mcp_agent/ui/console_display.py,sha256=XXrHr950wSBSedEKUaaGkXjOzuFpQYzUKKiyaZ58Mps,28280
170
170
  mcp_agent/ui/console_display_legacy.py,sha256=sm2v61-IPVafbF7uUaOyhO2tW_zgFWOjNS83IEWqGgI,14931
171
- fast_agent_mcp-0.2.48.dist-info/METADATA,sha256=urEeemSyTBTUjlI5CtGjrqLD8SZWgYx1ph9GeUhp3J8,31048
172
- fast_agent_mcp-0.2.48.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
173
- fast_agent_mcp-0.2.48.dist-info/entry_points.txt,sha256=QaX5kLdI0VdMPRdPUF1nkG_WdLUTNjp_icW6e3EhNYU,232
174
- fast_agent_mcp-0.2.48.dist-info/licenses/LICENSE,sha256=Gx1L3axA4PnuK4FxsbX87jQ1opoOkSFfHHSytW6wLUU,10935
175
- fast_agent_mcp-0.2.48.dist-info/RECORD,,
171
+ fast_agent_mcp-0.2.49.dist-info/METADATA,sha256=9P8RGPNerkSbu1BJl-2GvzR4qQIfqSa97Y4UMZ3tSXg,31048
172
+ fast_agent_mcp-0.2.49.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
173
+ fast_agent_mcp-0.2.49.dist-info/entry_points.txt,sha256=QaX5kLdI0VdMPRdPUF1nkG_WdLUTNjp_icW6e3EhNYU,232
174
+ fast_agent_mcp-0.2.49.dist-info/licenses/LICENSE,sha256=Gx1L3axA4PnuK4FxsbX87jQ1opoOkSFfHHSytW6wLUU,10935
175
+ fast_agent_mcp-0.2.49.dist-info/RECORD,,
mcp_agent/config.py CHANGED
@@ -8,6 +8,7 @@ import re
8
8
  from pathlib import Path
9
9
  from typing import Any, Dict, List, Literal, Optional, Tuple
10
10
 
11
+ from mcp import Implementation
11
12
  from pydantic import BaseModel, ConfigDict, field_validator
12
13
  from pydantic_settings import BaseSettings, SettingsConfigDict
13
14
 
@@ -61,11 +62,9 @@ class MCPServerSettings(BaseModel):
61
62
  Represents the configuration for an individual server.
62
63
  """
63
64
 
64
- # TODO: saqadri - server name should be something a server can provide itself during initialization
65
65
  name: str | None = None
66
66
  """The name of the server."""
67
67
 
68
- # TODO: saqadri - server description should be something a server can provide itself during initialization
69
68
  description: str | None = None
70
69
  """The description of the server."""
71
70
 
@@ -108,6 +107,8 @@ class MCPServerSettings(BaseModel):
108
107
  cwd: str | None = None
109
108
  """Working directory for the executed server command."""
110
109
 
110
+ implementation: Implementation | None = None
111
+
111
112
 
112
113
  class MCPSettings(BaseModel):
113
114
  """Configuration for all MCP servers."""
@@ -143,6 +143,7 @@ class ModelFactory:
143
143
  "gemini2": "gemini-2.0-flash",
144
144
  "gemini25": "gemini-2.5-flash-preview-05-20",
145
145
  "gemini25pro": "gemini-2.5-pro-preview-05-06",
146
+ "kimi": "groq.moonshotai/kimi-k2-instruct",
146
147
  }
147
148
 
148
149
  # Mapping of providers to their LLM classes
@@ -18,7 +18,7 @@ def _extract_resource_name(url: str) -> str | None:
18
18
  return host.replace(suffix, "") if host.endswith(suffix) else None
19
19
 
20
20
 
21
- DEFAULT_AZURE_API_VERSION = "2023-05-15"
21
+ DEFAULT_AZURE_API_VERSION = "2024-10-21"
22
22
 
23
23
 
24
24
  class AzureOpenAIAugmentedLLM(OpenAIAugmentedLLM):
@@ -412,7 +412,9 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
412
412
  )
413
413
 
414
414
  tool_results = []
415
+
415
416
  for tool_call in message.tool_calls:
417
+
416
418
  self.show_tool_call(
417
419
  available_tools,
418
420
  tool_call.function.name,
@@ -428,12 +430,20 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
428
430
  else from_json(tool_call.function.arguments, allow_partial=True),
429
431
  ),
430
432
  )
431
- result = await self.call_tool(tool_call_request, tool_call.id)
432
- self.show_tool_result(result)
433
-
434
- tool_results.append((tool_call.id, result))
435
- responses.extend(result.content)
436
- messages.extend(OpenAIConverter.convert_function_results_to_openai(tool_results))
433
+
434
+ try:
435
+ result = await self.call_tool(tool_call_request, tool_call.id)
436
+ self.show_tool_result(result)
437
+ tool_results.append((tool_call.id, result))
438
+ responses.extend(result.content)
439
+ except Exception as e:
440
+ self.logger.error(f"Tool call {tool_call.id} failed with error: {e}")
441
+ # Still add the tool_call_id with an error result to prevent missing responses
442
+ error_result = CallToolResult(content=[TextContent(type="text", text=f"Tool call failed: {str(e)}")])
443
+ tool_results.append((tool_call.id, error_result))
444
+
445
+ converted_messages = OpenAIConverter.convert_function_results_to_openai(tool_results)
446
+ messages.extend(converted_messages)
437
447
 
438
448
  self.logger.debug(
439
449
  f"Iteration {i}: Tool call results: {str(tool_results) if tool_results else 'None'}"
@@ -441,9 +441,6 @@ class OpenAIConverter:
441
441
  # Convert to OpenAI format
442
442
  user_message = OpenAIConverter.convert_to_openai(non_text_multipart)
443
443
 
444
- # We need to add tool_call_id manually
445
- user_message["tool_call_id"] = tool_call_id
446
-
447
444
  return (tool_message, [user_message])
448
445
 
449
446
  @staticmethod
@@ -461,22 +458,42 @@ class OpenAIConverter:
461
458
  Returns:
462
459
  List of OpenAI API messages for tool responses
463
460
  """
464
- messages = []
461
+ tool_messages = []
462
+ user_messages = []
463
+ has_mixed_content = False
465
464
 
466
465
  for tool_call_id, result in results:
467
- converted = OpenAIConverter.convert_tool_result_to_openai(
468
- tool_result=result,
469
- tool_call_id=tool_call_id,
470
- concatenate_text_blocks=concatenate_text_blocks,
471
- )
472
-
473
- # Handle the case where we have mixed content and get back a tuple
474
- if isinstance(converted, tuple):
475
- tool_message, additional_messages = converted
476
- messages.append(tool_message)
477
- messages.extend(additional_messages)
478
- else:
479
- # Single message case (text-only)
480
- messages.append(converted)
466
+ try:
467
+ converted = OpenAIConverter.convert_tool_result_to_openai(
468
+ tool_result=result,
469
+ tool_call_id=tool_call_id,
470
+ concatenate_text_blocks=concatenate_text_blocks,
471
+ )
481
472
 
473
+ # Handle the case where we have mixed content and get back a tuple
474
+ if isinstance(converted, tuple):
475
+ tool_message, additional_messages = converted
476
+ tool_messages.append(tool_message)
477
+ user_messages.extend(additional_messages)
478
+ has_mixed_content = True
479
+ else:
480
+ # Single message case (text-only)
481
+ tool_messages.append(converted)
482
+ except Exception as e:
483
+ _logger.error(f"Failed to convert tool_call_id={tool_call_id}: {e}")
484
+ # Create a basic tool response to prevent missing tool_call_id error
485
+ fallback_message = {
486
+ "role": "tool",
487
+ "tool_call_id": tool_call_id,
488
+ "content": f"[Conversion error: {str(e)}]",
489
+ }
490
+ tool_messages.append(fallback_message)
491
+
492
+ # CONDITIONAL REORDERING: Only reorder if there are user messages (mixed content)
493
+ if has_mixed_content and user_messages:
494
+ # Reorder: All tool messages first (OpenAI sequence), then user messages (vision context)
495
+ messages = tool_messages + user_messages
496
+ else:
497
+ # Pure tool responses - keep original order to preserve context (snapshots, etc.)
498
+ messages = tool_messages
482
499
  return messages
@@ -21,7 +21,7 @@ class RichProgressDisplay:
21
21
  self._progress = Progress(
22
22
  SpinnerColumn(spinner_name="simpleDotsScrolling"),
23
23
  TextColumn(
24
- "[progress.description]{task.description}|",
24
+ "[progress.description]{task.description}",
25
25
  # table_column=Column(max_width=16),
26
26
  ),
27
27
  TextColumn(text_format="{task.fields[target]:<16}", style="Bold Blue"),
@@ -77,7 +77,7 @@ class RichProgressDisplay:
77
77
  ProgressAction.LOADED: "dim green",
78
78
  ProgressAction.INITIALIZED: "dim green",
79
79
  ProgressAction.CHATTING: "bold blue",
80
- ProgressAction.STREAMING: "bold blue", # Same color as chatting
80
+ ProgressAction.STREAMING: "bold green", # Assistant Colour
81
81
  ProgressAction.ROUTING: "bold blue",
82
82
  ProgressAction.PLANNING: "bold blue",
83
83
  ProgressAction.READY: "dim green",
@@ -107,10 +107,19 @@ class RichProgressDisplay:
107
107
  # Ensure no None values in the update
108
108
  # For streaming, use custom description immediately to avoid flashing
109
109
  if event.action == ProgressAction.STREAMING and event.streaming_tokens:
110
- formatted_tokens = f"↓ {event.streaming_tokens.strip()}".ljust(15)
110
+ # Account for [dim][/dim] tags (11 characters) in padding calculation
111
+ formatted_tokens = f"▎[dim]◀[/dim] {event.streaming_tokens.strip()}".ljust(17 + 11)
111
112
  description = f"[{self._get_action_style(event.action)}]{formatted_tokens}"
113
+ elif event.action == ProgressAction.CHATTING:
114
+ # Add special formatting for chatting with dimmed arrow
115
+ formatted_text = f"▎[dim]▶[/dim] {event.action.value.strip()}".ljust(17 + 11)
116
+ description = f"[{self._get_action_style(event.action)}]{formatted_text}"
117
+ elif event.action == ProgressAction.CALLING_TOOL:
118
+ # Add special formatting for calling tool with dimmed arrow
119
+ formatted_text = f"▎[dim]◀[/dim] {event.action.value}".ljust(17 + 11)
120
+ description = f"[{self._get_action_style(event.action)}]{formatted_text}"
112
121
  else:
113
- description = f"[{self._get_action_style(event.action)}]{event.action.value:<15}"
122
+ description = f"[{self._get_action_style(event.action)}]{event.action.value:<15}"
114
123
 
115
124
  self._progress.update(
116
125
  task_id,
@@ -66,9 +66,6 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
66
66
  # Extract server_name if provided in kwargs
67
67
  from importlib.metadata import version
68
68
 
69
- version = version("fast-agent-mcp") or "dev"
70
- fast_agent: Implementation = Implementation(name="fast-agent-mcp", version=version)
71
-
72
69
  self.session_server_name = kwargs.pop("server_name", None)
73
70
  # Extract the notification callbacks if provided
74
71
  self._tool_list_changed_callback = kwargs.pop("tool_list_changed_callback", None)
@@ -83,6 +80,11 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
83
80
  # Extract custom elicitation handler if provided
84
81
  custom_elicitation_handler = kwargs.pop("elicitation_handler", None)
85
82
 
83
+ version = version("fast-agent-mcp") or "dev"
84
+ fast_agent: Implementation = Implementation(name="fast-agent-mcp", version=version)
85
+ if self.server_config and self.server_config.implementation:
86
+ fast_agent = self.server_config.implementation
87
+
86
88
  # Only register callbacks if the server_config has the relevant settings
87
89
  list_roots_cb = list_roots if (self.server_config and self.server_config.roots) else None
88
90