fast-agent-mcp 0.2.54__py3-none-any.whl → 0.2.56__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.
- {fast_agent_mcp-0.2.54.dist-info → fast_agent_mcp-0.2.56.dist-info}/METADATA +4 -18
- {fast_agent_mcp-0.2.54.dist-info → fast_agent_mcp-0.2.56.dist-info}/RECORD +15 -15
- mcp_agent/agents/base_agent.py +63 -6
- mcp_agent/cli/commands/go.py +3 -3
- mcp_agent/core/enhanced_prompt.py +1 -0
- mcp_agent/llm/model_database.py +4 -1
- mcp_agent/llm/providers/augmented_llm_aliyun.py +7 -4
- mcp_agent/llm/providers/augmented_llm_bedrock.py +1 -0
- mcp_agent/llm/providers/augmented_llm_groq.py +59 -30
- mcp_agent/llm/providers/augmented_llm_openai.py +6 -7
- mcp_agent/mcp/interfaces.py +3 -1
- mcp_agent/mcp/mcp_aggregator.py +58 -7
- {fast_agent_mcp-0.2.54.dist-info → fast_agent_mcp-0.2.56.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.2.54.dist-info → fast_agent_mcp-0.2.56.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.2.54.dist-info → fast_agent_mcp-0.2.56.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.56
|
|
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
|
|
@@ -211,15 +211,15 @@ Classifier: Programming Language :: Python :: 3
|
|
|
211
211
|
Requires-Python: >=3.13
|
|
212
212
|
Requires-Dist: a2a-sdk>=0.3.0
|
|
213
213
|
Requires-Dist: aiohttp>=3.11.13
|
|
214
|
-
Requires-Dist: anthropic>=0.
|
|
214
|
+
Requires-Dist: anthropic>=0.63.0
|
|
215
215
|
Requires-Dist: azure-identity>=1.14.0
|
|
216
216
|
Requires-Dist: boto3>=1.35.0
|
|
217
217
|
Requires-Dist: deprecated>=1.2.18
|
|
218
218
|
Requires-Dist: email-validator>=2.2.0
|
|
219
219
|
Requires-Dist: fastapi>=0.115.6
|
|
220
220
|
Requires-Dist: google-genai>=1.27.0
|
|
221
|
-
Requires-Dist: mcp==1.12.
|
|
222
|
-
Requires-Dist: openai>=1.
|
|
221
|
+
Requires-Dist: mcp==1.12.4
|
|
222
|
+
Requires-Dist: openai>=1.99.9
|
|
223
223
|
Requires-Dist: opentelemetry-distro>=0.55b0
|
|
224
224
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.7.0
|
|
225
225
|
Requires-Dist: opentelemetry-instrumentation-anthropic>=0.43.1; python_version >= '3.10' and python_version < '4.0'
|
|
@@ -234,20 +234,6 @@ Requires-Dist: pyyaml>=6.0.2
|
|
|
234
234
|
Requires-Dist: rich>=14.1.0
|
|
235
235
|
Requires-Dist: tensorzero>=2025.7.5
|
|
236
236
|
Requires-Dist: typer>=0.15.1
|
|
237
|
-
Provides-Extra: azure
|
|
238
|
-
Requires-Dist: azure-identity>=1.14.0; extra == 'azure'
|
|
239
|
-
Provides-Extra: dev
|
|
240
|
-
Requires-Dist: anthropic>=0.42.0; extra == 'dev'
|
|
241
|
-
Requires-Dist: pre-commit>=4.0.1; extra == 'dev'
|
|
242
|
-
Requires-Dist: pydantic>=2.10.4; extra == 'dev'
|
|
243
|
-
Requires-Dist: pytest-asyncio>=0.21.1; extra == 'dev'
|
|
244
|
-
Requires-Dist: pytest-cov; extra == 'dev'
|
|
245
|
-
Requires-Dist: pytest>=7.4.0; extra == 'dev'
|
|
246
|
-
Requires-Dist: pyyaml>=6.0.2; extra == 'dev'
|
|
247
|
-
Requires-Dist: ruff>=0.8.4; extra == 'dev'
|
|
248
|
-
Requires-Dist: tomli>=2.2.1; extra == 'dev'
|
|
249
|
-
Provides-Extra: openai
|
|
250
|
-
Requires-Dist: openai>=1.58.1; extra == 'openai'
|
|
251
237
|
Description-Content-Type: text/markdown
|
|
252
238
|
|
|
253
239
|
<p align="center">
|
|
@@ -10,7 +10,7 @@ mcp_agent/progress_display.py,sha256=GeJU9VUt6qKsFVymG688hCMVCsAygG9ifiiEb5IcbN4
|
|
|
10
10
|
mcp_agent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
mcp_agent/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
mcp_agent/agents/agent.py,sha256=EAYlcP1qqI1D0_CS808I806z1048FBjZQxxpcCZPeIU,3154
|
|
13
|
-
mcp_agent/agents/base_agent.py,sha256=
|
|
13
|
+
mcp_agent/agents/base_agent.py,sha256=BXakMe8VtDyWBtgoqcu-BXeMG54MB1o_gjcEAlhhYp8,34727
|
|
14
14
|
mcp_agent/agents/workflow/__init__.py,sha256=HloteEW6kalvgR0XewpiFAqaQlMPlPJYg5p3K33IUzI,25
|
|
15
15
|
mcp_agent/agents/workflow/chain_agent.py,sha256=eIlImirrSXkqBJmPuAJgOKis81Cl6lZEGM0-6IyaUV8,6105
|
|
16
16
|
mcp_agent/agents/workflow/evaluator_optimizer.py,sha256=LT81m2B7fxgBZY0CorXFOZJbVhM5fnjDjfrcywO5UrM,12210
|
|
@@ -26,7 +26,7 @@ mcp_agent/cli/constants.py,sha256=KawdkaN289nVB02DKPB4IVUJ8-fohIUD0gLfOp0P7B8,55
|
|
|
26
26
|
mcp_agent/cli/main.py,sha256=Oo13X7LB0Cf7JrkilQXz8Eqi_48cE0Rr2qqDUOQifEQ,3175
|
|
27
27
|
mcp_agent/cli/terminal.py,sha256=GRwD-RGW7saIz2IOWZn5vD6JjiArscELBThm1GTFkuI,1065
|
|
28
28
|
mcp_agent/cli/commands/check_config.py,sha256=15YK0mtDQbVopnMm3HBjOeY2-00FUHj6tt8RvaemKmI,21081
|
|
29
|
-
mcp_agent/cli/commands/go.py,sha256=
|
|
29
|
+
mcp_agent/cli/commands/go.py,sha256=RfNJQYmuDJicpYM7oT-jfv_9P7kBqCh_5Ezd4RtcYME,14712
|
|
30
30
|
mcp_agent/cli/commands/quickstart.py,sha256=hwIr1F9zGRSQGf7kwvmirMIK7Qke2s6W95inZ-a2SMQ,21171
|
|
31
31
|
mcp_agent/cli/commands/server_helpers.py,sha256=x5tD_qhf1W4D2li09sfOyfRWCOCa6lmpumYAPsEfIQs,3649
|
|
32
32
|
mcp_agent/cli/commands/setup.py,sha256=eOEd4TL-b0DaDeSJMGOfNOsTEItoZ67W88eTP4aP-bo,6482
|
|
@@ -36,7 +36,7 @@ mcp_agent/core/agent_app.py,sha256=SolGwejEmv9XtsTsmiMkNKPia7RN1VcHXm6JoEo4hvQ,1
|
|
|
36
36
|
mcp_agent/core/agent_types.py,sha256=ClFN7ikstZ5suweeLFf5w9jcg3ygxVhMS7GRj9VJ8yQ,1749
|
|
37
37
|
mcp_agent/core/direct_decorators.py,sha256=mOMLHf_qhWFqcOY0QE1UbHtXAarnetIKp7n0U8WvcyM,24061
|
|
38
38
|
mcp_agent/core/direct_factory.py,sha256=0G1HbVECfdFJGn__lBYGha_qt7Xyp18ST18IOzO134E,20867
|
|
39
|
-
mcp_agent/core/enhanced_prompt.py,sha256=
|
|
39
|
+
mcp_agent/core/enhanced_prompt.py,sha256=4uy_HRLL05DFzqYodN6EkzVLfux2iAbNOWib5d2YVaY,36097
|
|
40
40
|
mcp_agent/core/error_handling.py,sha256=xoyS2kLe0eG0bj2eSJCJ2odIhGUve2SbDR7jP-A-uRw,624
|
|
41
41
|
mcp_agent/core/exceptions.py,sha256=ENAD_qGG67foxy6vDkIvc-lgopIUQy6O7zvNPpPXaQg,2289
|
|
42
42
|
mcp_agent/core/fastagent.py,sha256=HiKuxHsj0wq6_RV0wkJih8br39ciHNnnfVEsknhbiQA,25264
|
|
@@ -67,7 +67,7 @@ mcp_agent/llm/augmented_llm_playback.py,sha256=rLzgai496e2RlxqQp_Bp0U-Y1FF1SGsWl
|
|
|
67
67
|
mcp_agent/llm/augmented_llm_silent.py,sha256=IUnK_1Byy4D9TG0Pj46LFeNezgSTQ8d6MQIHWAImBwE,1846
|
|
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
|
-
mcp_agent/llm/model_database.py,sha256=
|
|
70
|
+
mcp_agent/llm/model_database.py,sha256=MXCf1dHwZZq_JeLUcuGshlfNyqTYPfS6MNr9zAM4fWs,11221
|
|
71
71
|
mcp_agent/llm/model_factory.py,sha256=Dd3Drg9OyodkT4G4blFSbNiD8PAcphnZIWEmCjXP-QE,12203
|
|
72
72
|
mcp_agent/llm/prompt_utils.py,sha256=yWQHykoK13QRF7evHUKxVF0SpVLN-Bsft0Yixzvn0g0,4825
|
|
73
73
|
mcp_agent/llm/provider_key_manager.py,sha256=LSWIgcXlrUS4sfBvQBCya82qC6NcXQPYLtDHwHNOXR4,3394
|
|
@@ -77,16 +77,16 @@ mcp_agent/llm/sampling_format_converter.py,sha256=xGz4odHpOcP7--eFaJaFtUR8eR9jxZ
|
|
|
77
77
|
mcp_agent/llm/usage_tracking.py,sha256=rF6v8QQDam8QbvlP4jzHljKqvuNHExeYDLkUMI86czY,16073
|
|
78
78
|
mcp_agent/llm/providers/__init__.py,sha256=heVxtmuqFJOnjjxHz4bWSqTAxXoN1E8twC_gQ_yJpHk,265
|
|
79
79
|
mcp_agent/llm/providers/anthropic_utils.py,sha256=vYDN5G5jKMhD2CQg8veJYab7tvvzYkDMq8M1g_hUAQg,3275
|
|
80
|
-
mcp_agent/llm/providers/augmented_llm_aliyun.py,sha256=
|
|
80
|
+
mcp_agent/llm/providers/augmented_llm_aliyun.py,sha256=Th4qeyihOSfTrojPw8YsgzEyaDwhybk7hkXkFjH-1dY,1277
|
|
81
81
|
mcp_agent/llm/providers/augmented_llm_anthropic.py,sha256=U8znA9HSCOx4FlhIjl-J29nbYc8Y-T6BXevtXuDafio,30352
|
|
82
82
|
mcp_agent/llm/providers/augmented_llm_azure.py,sha256=Xoo6dFst6L9SaGKurqptwwTUzr-sYsolZ-AFb_79puc,6098
|
|
83
|
-
mcp_agent/llm/providers/augmented_llm_bedrock.py,sha256=
|
|
83
|
+
mcp_agent/llm/providers/augmented_llm_bedrock.py,sha256=lL_au5-QdVNFr7lxQQYk0HVQ3LKUieh2HHnBQsOWoro,82312
|
|
84
84
|
mcp_agent/llm/providers/augmented_llm_deepseek.py,sha256=vphkYMFyukaejBw8SkCN-MqcG9qsfXJfWKZYYtspqPY,3877
|
|
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
|
-
mcp_agent/llm/providers/augmented_llm_groq.py,sha256=
|
|
89
|
-
mcp_agent/llm/providers/augmented_llm_openai.py,sha256=
|
|
88
|
+
mcp_agent/llm/providers/augmented_llm_groq.py,sha256=w-R1N2B7790v9tXxRCPt2SKnaB-DRdEtN_51fpdYb_I,5355
|
|
89
|
+
mcp_agent/llm/providers/augmented_llm_openai.py,sha256=v0iInSlPt939Dh2kGpGJ9_7qGpL7MhxQ7UNSc42dT6Q,25318
|
|
90
90
|
mcp_agent/llm/providers/augmented_llm_openrouter.py,sha256=m3wS83fabBOmaZJH9gQ9sFw_2TB4xTb44WCOPB-2NJ4,2001
|
|
91
91
|
mcp_agent/llm/providers/augmented_llm_tensorzero_openai.py,sha256=D53Fry2AfBLOB5z9hM19U6_HMJeVNTpiBCAJb11ulNg,5503
|
|
92
92
|
mcp_agent/llm/providers/augmented_llm_xai.py,sha256=MhlX91IUNynQ_NDknx4EQJLwg-NbR8lcHS1P4JuLOnA,1433
|
|
@@ -110,10 +110,10 @@ mcp_agent/mcp/elicitation_factory.py,sha256=gY0gEsF8Jdg01nSsrVbbl62ZS1A725QgDRB6
|
|
|
110
110
|
mcp_agent/mcp/elicitation_handlers.py,sha256=w2S4kBn05pIKdq2-X13MErinFg5jSElwFsoTuW3zFSs,6618
|
|
111
111
|
mcp_agent/mcp/gen_client.py,sha256=fAVwFVCgSamw4PwoWOV4wrK9TABx1S_zZv8BctRyF2k,3030
|
|
112
112
|
mcp_agent/mcp/hf_auth.py,sha256=7szw4rkwRyK3J-sUTcVZHdwoLIZqlYo8XolJnZdjOww,4571
|
|
113
|
-
mcp_agent/mcp/interfaces.py,sha256=
|
|
113
|
+
mcp_agent/mcp/interfaces.py,sha256=5y7zuXkpGCfsJfZOAEZAZtbFd5rAKjn7oG4JoblPHZ4,8070
|
|
114
114
|
mcp_agent/mcp/logger_textio.py,sha256=vljC1BtNTCxBAda9ExqNB-FwVNUZIuJT3h1nWmCjMws,3172
|
|
115
115
|
mcp_agent/mcp/mcp_agent_client_session.py,sha256=ssRgxMOzyCPyAr25AeRBz3Xr-08OBdmsJf8A-ofc3bY,9115
|
|
116
|
-
mcp_agent/mcp/mcp_aggregator.py,sha256=
|
|
116
|
+
mcp_agent/mcp/mcp_aggregator.py,sha256=KtZEDydOw577Tk-3eNiZkPmuHIT-mDPxpCfT43ZYbx4,53399
|
|
117
117
|
mcp_agent/mcp/mcp_connection_manager.py,sha256=dJxjnv2IRzlFIxrbPFl39-pmGcZHgyeMXVlMfqpREhE,17974
|
|
118
118
|
mcp_agent/mcp/mime_utils.py,sha256=difepNR_gpb4MpMLkBRAoyhDk-AjXUHTiqKvT_VwS1o,1805
|
|
119
119
|
mcp_agent/mcp/prompt_message_multipart.py,sha256=-oSO0mnc5gkSgulE1gAntPEwAKF4asOjEeVyLjhYrEk,4336
|
|
@@ -185,8 +185,8 @@ mcp_agent/resources/examples/workflows/short_story.txt,sha256=X3y_1AyhLFN2AKzCKv
|
|
|
185
185
|
mcp_agent/tools/tool_definition.py,sha256=L3Pxl-uLEXqlVoo-bYuFTFALeI-2pIU44YgFhsTKEtM,398
|
|
186
186
|
mcp_agent/ui/console_display.py,sha256=XXrHr950wSBSedEKUaaGkXjOzuFpQYzUKKiyaZ58Mps,28280
|
|
187
187
|
mcp_agent/ui/console_display_legacy.py,sha256=sm2v61-IPVafbF7uUaOyhO2tW_zgFWOjNS83IEWqGgI,14931
|
|
188
|
-
fast_agent_mcp-0.2.
|
|
189
|
-
fast_agent_mcp-0.2.
|
|
190
|
-
fast_agent_mcp-0.2.
|
|
191
|
-
fast_agent_mcp-0.2.
|
|
192
|
-
fast_agent_mcp-0.2.
|
|
188
|
+
fast_agent_mcp-0.2.56.dist-info/METADATA,sha256=6cyeWzS7xvOKhhLE9rdoRDxp9LOZ4I4yPVq9bHo9yv4,30459
|
|
189
|
+
fast_agent_mcp-0.2.56.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
190
|
+
fast_agent_mcp-0.2.56.dist-info/entry_points.txt,sha256=QaX5kLdI0VdMPRdPUF1nkG_WdLUTNjp_icW6e3EhNYU,232
|
|
191
|
+
fast_agent_mcp-0.2.56.dist-info/licenses/LICENSE,sha256=Gx1L3axA4PnuK4FxsbX87jQ1opoOkSFfHHSytW6wLUU,10935
|
|
192
|
+
fast_agent_mcp-0.2.56.dist-info/RECORD,,
|
mcp_agent/agents/base_agent.py
CHANGED
|
@@ -364,12 +364,15 @@ class BaseAgent(MCPAggregator, AgentProtocol):
|
|
|
364
364
|
if self.config.tools is not None:
|
|
365
365
|
filtered_tools = []
|
|
366
366
|
for tool in result.tools:
|
|
367
|
-
# Extract server name from tool name
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
367
|
+
# Extract server name from tool name, handling server names with hyphens
|
|
368
|
+
server_name = None
|
|
369
|
+
for configured_server in self.config.tools.keys():
|
|
370
|
+
if tool.name.startswith(f"{configured_server}-"):
|
|
371
|
+
server_name = configured_server
|
|
372
|
+
break
|
|
373
|
+
|
|
374
|
+
# Check if this server has tool filters
|
|
375
|
+
if server_name and server_name in self.config.tools:
|
|
373
376
|
# Check if tool matches any pattern for this server
|
|
374
377
|
for pattern in self.config.tools[server_name]:
|
|
375
378
|
if self._matches_pattern(tool.name, pattern, server_name):
|
|
@@ -783,6 +786,60 @@ class BaseAgent(MCPAggregator, AgentProtocol):
|
|
|
783
786
|
|
|
784
787
|
return result
|
|
785
788
|
|
|
789
|
+
async def list_mcp_tools(self, server_name: str | None = None) -> Mapping[str, List[Tool]]:
|
|
790
|
+
"""
|
|
791
|
+
List all tools available to this agent, grouped by server and filtered by configuration.
|
|
792
|
+
|
|
793
|
+
Args:
|
|
794
|
+
server_name: Optional server name to list tools from
|
|
795
|
+
|
|
796
|
+
Returns:
|
|
797
|
+
Dictionary mapping server names to lists of Tool objects (with original names, not namespaced)
|
|
798
|
+
"""
|
|
799
|
+
if not self.initialized:
|
|
800
|
+
await self.initialize()
|
|
801
|
+
|
|
802
|
+
# Get all tools from the parent class
|
|
803
|
+
result = await super().list_mcp_tools(server_name)
|
|
804
|
+
|
|
805
|
+
# Apply filtering if tools are specified in config
|
|
806
|
+
if self.config.tools is not None:
|
|
807
|
+
filtered_result = {}
|
|
808
|
+
for server, tools in result.items():
|
|
809
|
+
# Check if this server has tool filters
|
|
810
|
+
if server in self.config.tools:
|
|
811
|
+
filtered_tools = []
|
|
812
|
+
for tool in tools:
|
|
813
|
+
# Check if tool matches any pattern for this server
|
|
814
|
+
for pattern in self.config.tools[server]:
|
|
815
|
+
if self._matches_pattern(tool.name, pattern, server):
|
|
816
|
+
filtered_tools.append(tool)
|
|
817
|
+
break
|
|
818
|
+
if filtered_tools:
|
|
819
|
+
filtered_result[server] = filtered_tools
|
|
820
|
+
result = filtered_result
|
|
821
|
+
|
|
822
|
+
# Add human input tool to a special server if human input is configured
|
|
823
|
+
if self.human_input_callback:
|
|
824
|
+
from mcp.server.fastmcp.tools import Tool as FastTool
|
|
825
|
+
|
|
826
|
+
human_input_tool: FastTool = FastTool.from_function(self.request_human_input)
|
|
827
|
+
special_server_name = "__human_input__"
|
|
828
|
+
|
|
829
|
+
# If the special server doesn't exist in result, create it
|
|
830
|
+
if special_server_name not in result:
|
|
831
|
+
result[special_server_name] = []
|
|
832
|
+
|
|
833
|
+
result[special_server_name].append(
|
|
834
|
+
Tool(
|
|
835
|
+
name=HUMAN_INPUT_TOOL_NAME,
|
|
836
|
+
description=human_input_tool.description,
|
|
837
|
+
inputSchema=human_input_tool.parameters,
|
|
838
|
+
)
|
|
839
|
+
)
|
|
840
|
+
|
|
841
|
+
return result
|
|
842
|
+
|
|
786
843
|
@property
|
|
787
844
|
def agent_type(self) -> AgentType:
|
|
788
845
|
"""
|
mcp_agent/cli/commands/go.py
CHANGED
|
@@ -121,9 +121,9 @@ async def _run_agent(
|
|
|
121
121
|
print(response)
|
|
122
122
|
elif prompt_file:
|
|
123
123
|
prompt = load_prompt_multipart(Path(prompt_file))
|
|
124
|
-
response = await agent.generate(prompt)
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
response = await agent.agent.generate(prompt)
|
|
125
|
+
print(f"\nLoaded {len(prompt)} messages from prompt file '{prompt_file}'")
|
|
126
|
+
await agent.interactive()
|
|
127
127
|
else:
|
|
128
128
|
await agent.interactive()
|
|
129
129
|
|
mcp_agent/llm/model_database.py
CHANGED
|
@@ -91,7 +91,10 @@ class ModelDatabase:
|
|
|
91
91
|
)
|
|
92
92
|
|
|
93
93
|
QWEN_STANDARD = ModelParameters(
|
|
94
|
-
context_window=32000,
|
|
94
|
+
context_window=32000,
|
|
95
|
+
max_output_tokens=8192,
|
|
96
|
+
tokenizes=QWEN_MULTIMODAL,
|
|
97
|
+
json_mode="object",
|
|
95
98
|
)
|
|
96
99
|
QWEN3_REASONER = ModelParameters(
|
|
97
100
|
context_window=131072,
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
from mcp_agent.core.request_params import RequestParams
|
|
2
2
|
from mcp_agent.llm.provider_types import Provider
|
|
3
|
+
from mcp_agent.llm.providers.augmented_llm_groq import GroqAugmentedLLM
|
|
3
4
|
from mcp_agent.llm.providers.augmented_llm_openai import OpenAIAugmentedLLM
|
|
4
5
|
|
|
5
6
|
ALIYUN_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
6
7
|
DEFAULT_QWEN_MODEL = "qwen-turbo"
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
class AliyunAugmentedLLM(
|
|
10
|
+
class AliyunAugmentedLLM(GroqAugmentedLLM):
|
|
10
11
|
def __init__(self, *args, **kwargs) -> None:
|
|
11
|
-
|
|
12
|
+
OpenAIAugmentedLLM.__init__(self, *args, provider=Provider.ALIYUN, **kwargs)
|
|
12
13
|
|
|
13
14
|
def _initialize_default_params(self, kwargs: dict) -> RequestParams:
|
|
14
15
|
"""Initialize Aliyun-specific default parameters"""
|
|
15
16
|
# Get base defaults from parent (includes ModelDatabase lookup)
|
|
16
17
|
base_params = super()._initialize_default_params(kwargs)
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
# Override with Aliyun-specific settings
|
|
19
20
|
chosen_model = kwargs.get("model", DEFAULT_QWEN_MODEL)
|
|
20
21
|
base_params.model = chosen_model
|
|
21
|
-
|
|
22
|
+
base_params.parallel_tool_calls = True
|
|
23
|
+
|
|
22
24
|
return base_params
|
|
23
25
|
|
|
24
26
|
def _base_url(self) -> str:
|
|
@@ -27,3 +29,4 @@ class AliyunAugmentedLLM(OpenAIAugmentedLLM):
|
|
|
27
29
|
base_url = self.context.config.aliyun.base_url
|
|
28
30
|
|
|
29
31
|
return base_url if base_url else ALIYUN_BASE_URL
|
|
32
|
+
|
|
@@ -46,38 +46,25 @@ class GroqAugmentedLLM(OpenAIAugmentedLLM):
|
|
|
46
46
|
assert self.default_request_params
|
|
47
47
|
llm_model = self.default_request_params.model or DEFAULT_GROQ_MODEL
|
|
48
48
|
json_mode: str | None = ModelDatabase.get_json_mode(llm_model)
|
|
49
|
-
if "
|
|
49
|
+
if "object" == json_mode:
|
|
50
50
|
request_params.response_format = {"type": "json_object"}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
format_description += "}"
|
|
69
|
-
|
|
70
|
-
multipart_messages[-1].add_text(
|
|
71
|
-
f"""YOU MUST RESPOND WITH A JSON OBJECT IN EXACTLY THIS FORMAT:
|
|
72
|
-
{format_description}
|
|
73
|
-
|
|
74
|
-
IMPORTANT RULES:
|
|
75
|
-
- Respond ONLY with the JSON object, no other text
|
|
76
|
-
- Do NOT include "properties" or "schema" wrappers
|
|
77
|
-
- Do NOT use code fences or markdown
|
|
78
|
-
- The response must be valid JSON that matches the format above
|
|
79
|
-
- All required fields must be included"""
|
|
80
|
-
)
|
|
52
|
+
# Create a cleaner format description from full schema
|
|
53
|
+
full_schema = model.model_json_schema()
|
|
54
|
+
format_description = self._schema_to_json_object(
|
|
55
|
+
full_schema, full_schema.get("$defs")
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
multipart_messages[-1].add_text(
|
|
59
|
+
f"""YOU MUST RESPOND WITH A JSON OBJECT IN EXACTLY THIS FORMAT:
|
|
60
|
+
{format_description}
|
|
61
|
+
|
|
62
|
+
IMPORTANT RULES:
|
|
63
|
+
- Respond ONLY with the JSON object, no other text
|
|
64
|
+
- Do NOT include "properties" or "schema" wrappers
|
|
65
|
+
- Do NOT use code fences or markdown
|
|
66
|
+
- The response must be valid JSON that matches the format above
|
|
67
|
+
- All required fields must be included""")
|
|
81
68
|
|
|
82
69
|
result: PromptMessageMultipart = await self._apply_prompt_provider_specific(
|
|
83
70
|
multipart_messages, request_params
|
|
@@ -101,3 +88,45 @@ class GroqAugmentedLLM(OpenAIAugmentedLLM):
|
|
|
101
88
|
base_url = self.context.config.groq.base_url
|
|
102
89
|
|
|
103
90
|
return base_url if base_url else GROQ_BASE_URL
|
|
91
|
+
|
|
92
|
+
def _schema_to_json_object(
|
|
93
|
+
self, schema: dict, defs: dict | None = None, visited: set | None = None
|
|
94
|
+
) -> str:
|
|
95
|
+
visited = visited or set()
|
|
96
|
+
|
|
97
|
+
if id(schema) in visited:
|
|
98
|
+
return '"<recursive>"'
|
|
99
|
+
visited.add(id(schema))
|
|
100
|
+
|
|
101
|
+
if "$ref" in schema:
|
|
102
|
+
ref = schema.get("$ref", "")
|
|
103
|
+
if ref.startswith("#/$defs/"):
|
|
104
|
+
target = ref.split("/")[-1]
|
|
105
|
+
if defs and target in defs:
|
|
106
|
+
return self._schema_to_json_object(defs[target], defs, visited)
|
|
107
|
+
return f'"<ref:{ref}>"'
|
|
108
|
+
|
|
109
|
+
schema_type = schema.get("type")
|
|
110
|
+
description = schema.get("description", "")
|
|
111
|
+
required = schema.get("required", [])
|
|
112
|
+
|
|
113
|
+
if schema_type == "object":
|
|
114
|
+
props = schema.get("properties", {})
|
|
115
|
+
result = "{\n"
|
|
116
|
+
for prop_name, prop_schema in props.items():
|
|
117
|
+
is_required = prop_name in required
|
|
118
|
+
prop_str = self._schema_to_json_object(prop_schema, defs, visited)
|
|
119
|
+
if is_required:
|
|
120
|
+
prop_str += " // REQUIRED"
|
|
121
|
+
result += f' "{prop_name}": {prop_str},\n'
|
|
122
|
+
result += "}"
|
|
123
|
+
return result
|
|
124
|
+
elif schema_type == "array":
|
|
125
|
+
items = schema.get("items", {})
|
|
126
|
+
items_str = self._schema_to_json_object(items, defs, visited)
|
|
127
|
+
return f"[{items_str}]"
|
|
128
|
+
elif schema_type:
|
|
129
|
+
comment = f" // {description}" if description else ""
|
|
130
|
+
return f'"{schema_type}"' + comment
|
|
131
|
+
|
|
132
|
+
return '"<unknown>"'
|
|
@@ -171,7 +171,6 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
|
|
|
171
171
|
async def _process_stream_manual(self, stream, model: str):
|
|
172
172
|
"""Manual stream processing for providers like Ollama that may not work with ChatCompletionStreamState."""
|
|
173
173
|
from openai.types.chat import ChatCompletionMessageToolCall
|
|
174
|
-
from openai.types.chat.chat_completion_message_tool_call import Function
|
|
175
174
|
|
|
176
175
|
# Track estimated output tokens by counting text chunks
|
|
177
176
|
estimated_tokens = 0
|
|
@@ -249,10 +248,10 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
|
|
|
249
248
|
ChatCompletionMessageToolCall(
|
|
250
249
|
id=tool_call_data["id"],
|
|
251
250
|
type=tool_call_data["type"],
|
|
252
|
-
function=
|
|
253
|
-
name
|
|
254
|
-
arguments
|
|
255
|
-
|
|
251
|
+
function={
|
|
252
|
+
"name": tool_call_data["function"]["name"],
|
|
253
|
+
"arguments": tool_call_data["function"]["arguments"],
|
|
254
|
+
},
|
|
256
255
|
)
|
|
257
256
|
)
|
|
258
257
|
|
|
@@ -333,8 +332,8 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
|
|
|
333
332
|
]
|
|
334
333
|
|
|
335
334
|
if not available_tools:
|
|
336
|
-
if self.provider
|
|
337
|
-
available_tools = None # deepseek does not allow empty array
|
|
335
|
+
if self.provider in [Provider.DEEPSEEK, Provider.ALIYUN]:
|
|
336
|
+
available_tools = None # deepseek/aliyun does not allow empty array
|
|
338
337
|
else:
|
|
339
338
|
available_tools = []
|
|
340
339
|
|
mcp_agent/mcp/interfaces.py
CHANGED
|
@@ -25,7 +25,7 @@ from a2a.types import AgentCard
|
|
|
25
25
|
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
|
|
26
26
|
from deprecated import deprecated
|
|
27
27
|
from mcp import ClientSession
|
|
28
|
-
from mcp.types import GetPromptResult, Prompt, PromptMessage, ReadResourceResult
|
|
28
|
+
from mcp.types import GetPromptResult, Prompt, PromptMessage, ReadResourceResult, Tool
|
|
29
29
|
from pydantic import BaseModel
|
|
30
30
|
|
|
31
31
|
from mcp_agent.core.agent_types import AgentType
|
|
@@ -203,6 +203,8 @@ class AgentProtocol(AugmentedLLMProtocol, Protocol):
|
|
|
203
203
|
|
|
204
204
|
async def list_resources(self, server_name: str | None = None) -> Mapping[str, List[str]]: ...
|
|
205
205
|
|
|
206
|
+
async def list_mcp_tools(self, server_name: str | None = None) -> Mapping[str, List[Tool]]: ...
|
|
207
|
+
|
|
206
208
|
async def get_resource(
|
|
207
209
|
self, resource_uri: str, server_name: str | None = None
|
|
208
210
|
) -> ReadResourceResult:
|
mcp_agent/mcp/mcp_aggregator.py
CHANGED
|
@@ -572,14 +572,13 @@ class MCPAggregator(ContextDependent):
|
|
|
572
572
|
|
|
573
573
|
# Next, attempt to interpret as a namespaced name
|
|
574
574
|
if is_namespaced_name(name):
|
|
575
|
-
|
|
576
|
-
server_name
|
|
575
|
+
# Try to match against known server names, handling server names with hyphens
|
|
576
|
+
for server_name in self.server_names:
|
|
577
|
+
if name.startswith(f"{server_name}{SEP}"):
|
|
578
|
+
local_name = name[len(server_name) + len(SEP):]
|
|
579
|
+
return server_name, local_name
|
|
577
580
|
|
|
578
|
-
#
|
|
579
|
-
if server_name in self.server_names:
|
|
580
|
-
return server_name, local_name
|
|
581
|
-
|
|
582
|
-
# If the server name doesn't exist, it might be a tool with a hyphen in its name
|
|
581
|
+
# If no server name matched, it might be a tool with a hyphen in its name
|
|
583
582
|
# Fall through to the next checks
|
|
584
583
|
|
|
585
584
|
# For tools, search all servers for the tool by exact name match
|
|
@@ -1232,3 +1231,55 @@ class MCPAggregator(ContextDependent):
|
|
|
1232
1231
|
logger.error(f"Error fetching resources from {s_name}: {e}")
|
|
1233
1232
|
|
|
1234
1233
|
return results
|
|
1234
|
+
|
|
1235
|
+
async def list_mcp_tools(self, server_name: str | None = None) -> Dict[str, List[Tool]]:
|
|
1236
|
+
"""
|
|
1237
|
+
List available tools from one or all servers, grouped by server name.
|
|
1238
|
+
|
|
1239
|
+
Args:
|
|
1240
|
+
server_name: Optional server name to list tools from. If not provided,
|
|
1241
|
+
lists tools from all servers.
|
|
1242
|
+
|
|
1243
|
+
Returns:
|
|
1244
|
+
Dictionary mapping server names to lists of Tool objects (with original names, not namespaced)
|
|
1245
|
+
"""
|
|
1246
|
+
if not self.initialized:
|
|
1247
|
+
await self.load_servers()
|
|
1248
|
+
|
|
1249
|
+
results: Dict[str, List[Tool]] = {}
|
|
1250
|
+
|
|
1251
|
+
# Get the list of servers to check
|
|
1252
|
+
servers_to_check = [server_name] if server_name else self.server_names
|
|
1253
|
+
|
|
1254
|
+
# For each server, try to list its tools
|
|
1255
|
+
for s_name in servers_to_check:
|
|
1256
|
+
if s_name not in self.server_names:
|
|
1257
|
+
logger.error(f"Server '{s_name}' not found")
|
|
1258
|
+
continue
|
|
1259
|
+
|
|
1260
|
+
# Initialize empty list for this server
|
|
1261
|
+
results[s_name] = []
|
|
1262
|
+
|
|
1263
|
+
# Check if server supports tools capability
|
|
1264
|
+
if not await self.server_supports_feature(s_name, "tools"):
|
|
1265
|
+
logger.debug(f"Server '{s_name}' does not support tools")
|
|
1266
|
+
continue
|
|
1267
|
+
|
|
1268
|
+
try:
|
|
1269
|
+
# Use the _execute_on_server method to call list_tools on the server
|
|
1270
|
+
result = await self._execute_on_server(
|
|
1271
|
+
server_name=s_name,
|
|
1272
|
+
operation_type="tools-list",
|
|
1273
|
+
operation_name="",
|
|
1274
|
+
method_name="list_tools",
|
|
1275
|
+
method_args={},
|
|
1276
|
+
)
|
|
1277
|
+
|
|
1278
|
+
# Get tools from result (these have original names, not namespaced)
|
|
1279
|
+
tools = getattr(result, "tools", [])
|
|
1280
|
+
results[s_name] = tools
|
|
1281
|
+
|
|
1282
|
+
except Exception as e:
|
|
1283
|
+
logger.error(f"Error fetching tools from {s_name}: {e}")
|
|
1284
|
+
|
|
1285
|
+
return results
|
|
File without changes
|
|
File without changes
|
|
File without changes
|