fast-agent-mcp 0.2.9__py3-none-any.whl → 0.2.11__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.
Files changed (26) hide show
  1. {fast_agent_mcp-0.2.9.dist-info → fast_agent_mcp-0.2.11.dist-info}/METADATA +7 -6
  2. {fast_agent_mcp-0.2.9.dist-info → fast_agent_mcp-0.2.11.dist-info}/RECORD +26 -17
  3. {fast_agent_mcp-0.2.9.dist-info → fast_agent_mcp-0.2.11.dist-info}/entry_points.txt +0 -1
  4. mcp_agent/cli/commands/{bootstrap.py → quickstart.py} +88 -21
  5. mcp_agent/cli/commands/setup.py +10 -4
  6. mcp_agent/cli/main.py +8 -6
  7. mcp_agent/config.py +3 -0
  8. mcp_agent/llm/providers/augmented_llm_generic.py +2 -2
  9. mcp_agent/llm/providers/augmented_llm_openrouter.py +2 -2
  10. mcp_agent/mcp/mcp_connection_manager.py +5 -1
  11. mcp_agent/mcp/prompt_serialization.py +62 -37
  12. mcp_agent/mcp/prompts/prompt_load.py +27 -27
  13. mcp_agent/mcp/prompts/prompt_server.py +50 -1
  14. mcp_agent/mcp_server/agent_server.py +6 -20
  15. mcp_agent/mcp_server_registry.py +5 -1
  16. mcp_agent/resources/examples/in_dev/css-LICENSE.txt +21 -0
  17. mcp_agent/resources/examples/internal/simple.txt +2 -0
  18. mcp_agent/resources/examples/mcp/state-transfer/agent_one.py +18 -0
  19. mcp_agent/resources/examples/mcp/state-transfer/agent_two.py +18 -0
  20. mcp_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +27 -0
  21. mcp_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +14 -0
  22. mcp_agent/resources/examples/prompting/delimited_prompt.txt +14 -0
  23. mcp_agent/resources/examples/prompting/prompt1.txt +6 -0
  24. mcp_agent/resources/examples/workflows/short_story.txt +19 -0
  25. {fast_agent_mcp-0.2.9.dist-info → fast_agent_mcp-0.2.11.dist-info}/WHEEL +0 -0
  26. {fast_agent_mcp-0.2.9.dist-info → fast_agent_mcp-0.2.11.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.9
3
+ Version: 0.2.11
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
@@ -209,6 +209,7 @@ Classifier: License :: OSI Approved :: Apache Software License
209
209
  Classifier: Operating System :: OS Independent
210
210
  Classifier: Programming Language :: Python :: 3
211
211
  Requires-Python: >=3.10
212
+ Requires-Dist: a2a-types>=0.1.0
212
213
  Requires-Dist: aiohttp>=3.11.13
213
214
  Requires-Dist: anthropic>=0.49.0
214
215
  Requires-Dist: fastapi>=0.115.6
@@ -252,7 +253,7 @@ Description-Content-Type: text/markdown
252
253
  ## Overview
253
254
 
254
255
  > [!TIP]
255
- > Documentation site is in production here : https://fast-agent.ai. Feel free to feed back what's helpful and what's not.
256
+ > Documentation site is in production here : https://fast-agent.ai. Feel free to feed back what's helpful and what's not. llms.txt link is here: https://fast-agent.ai/llms.txt
256
257
 
257
258
  **`fast-agent`** enables you to create and interact with sophisticated Agents and Workflows in minutes. It is the first framework with complete, end-to-end tested MCP Feature support including Sampling. Both Anthropic (Haiku, Sonnet, Opus) and OpenAI models (gpt-4o family, o1/o3 family) are supported.
258
259
 
@@ -282,10 +283,10 @@ uv pip install fast-agent-mcp # install fast-agent!
282
283
  fast-agent setup # create an example agent and config files
283
284
  uv run agent.py # run your first agent
284
285
  uv run agent.py --model=o3-mini.low # specify a model
285
- fast-agent bootstrap workflow # create "building effective agents" examples
286
+ fast-agent quickstart workflow # create "building effective agents" examples
286
287
  ```
287
288
 
288
- Other bootstrap examples include a Researcher Agent (with Evaluator-Optimizer workflow) and Data Analysis Agent (similar to the ChatGPT experience), demonstrating MCP Roots support.
289
+ Other quickstart examples include a Researcher Agent (with Evaluator-Optimizer workflow) and Data Analysis Agent (similar to the ChatGPT experience), demonstrating MCP Roots support.
289
290
 
290
291
  > [!TIP]
291
292
  > Windows Users - there are a couple of configuration changes needed for the Filesystem and Docker MCP Servers - necessary changes are detailed within the configuration files.
@@ -341,7 +342,7 @@ Specify a model with the `--model` switch - for example `uv run sizer.py --model
341
342
 
342
343
  ### Combining Agents and using MCP Servers
343
344
 
344
- _To generate examples use `fast-agent bootstrap workflow`. This example can be run with `uv run workflow/chaining.py`. fast-agent looks for configuration files in the current directory before checking parent directories recursively._
345
+ _To generate examples use `fast-agent quickstart workflow`. This example can be run with `uv run workflow/chaining.py`. fast-agent looks for configuration files in the current directory before checking parent directories recursively._
345
346
 
346
347
  Agents can be chained to build a workflow, using MCP Servers defined in the `fastagent.config.yaml` file:
347
348
 
@@ -463,7 +464,7 @@ async with fast.run() as agent:
463
464
 
464
465
  When used in a workflow, it returns the last `generator` message as the result.
465
466
 
466
- See the `evaluator.py` workflow example, or `fast-agent bootstrap researcher` for a more complete example.
467
+ See the `evaluator.py` workflow example, or `fast-agent quickstart researcher` for a more complete example.
467
468
 
468
469
  ### Router
469
470
 
@@ -1,11 +1,11 @@
1
1
  mcp_agent/__init__.py,sha256=-AIoeL4c9UAp_P4U0z-uIWTTmQWdihOis5nbQ5L_eao,1664
2
2
  mcp_agent/app.py,sha256=jBmzYM_o50g8vhlTgkkf5TGiBWNbXWViYnd0WANbpzo,10276
3
- mcp_agent/config.py,sha256=0GVtAMSiK1oPklHlH-3rbhjPfBx18JfEAn-W-HG5x6k,12167
3
+ mcp_agent/config.py,sha256=z3EtltnwdEM03WevxSHusymMvHB02BN4brDsLYQ-M68,12268
4
4
  mcp_agent/console.py,sha256=Gjf2QLFumwG1Lav__c07X_kZxxEUSkzV-1_-YbAwcwo,813
5
5
  mcp_agent/context.py,sha256=pp_F1Q1jgAxGrRccSZJutn1JUxYfVue-St3S8tUyptM,7903
6
6
  mcp_agent/context_dependent.py,sha256=QXfhw3RaQCKfscEEBRGuZ3sdMWqkgShz2jJ1ivGGX1I,1455
7
7
  mcp_agent/event_progress.py,sha256=25iz0yyg-O4glMmtijcYpDdUmtUIKsCmR_8A52GgeC4,2716
8
- mcp_agent/mcp_server_registry.py,sha256=w0sq-5o_AVVGfwUBo0c_Ekbyjd3Tjg9bzi2r8UZry7o,9945
8
+ mcp_agent/mcp_server_registry.py,sha256=pSD3euU-Oc2LAVenqkLU7UmutAzk6A9liYVLjCj4J70,10068
9
9
  mcp_agent/progress_display.py,sha256=GeJU9VUt6qKsFVymG688hCMVCsAygG9ifiiEb5IcbN4,361
10
10
  mcp_agent/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  mcp_agent/agents/agent.py,sha256=Tn2YKw_ytx9b8jC-65WYQmrnD43kYiZsLa4sVHxn9d4,3854
@@ -20,11 +20,11 @@ mcp_agent/agents/workflow/parallel_agent.py,sha256=SgIXJx2X_MSlLOv6WXYRezwjDYjU9
20
20
  mcp_agent/agents/workflow/router_agent.py,sha256=c4MU55U6q1DRayP0sDoyxdlnKX-N0LPbRv-MFlwbwrY,11165
21
21
  mcp_agent/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  mcp_agent/cli/__main__.py,sha256=AVZ7tQFhU_sDOGuUGJq8ujgKtcxsYJBJwHbVaaiRDlI,166
23
- mcp_agent/cli/main.py,sha256=PZdPJfsAJOm80vTu7j_XpMPhaDZOpqSe-ciU3YQsmA4,3149
23
+ mcp_agent/cli/main.py,sha256=_yMv39nP5faJ8rsp-4xKofX1Mnj7rTKnhBJnC2taNJU,3241
24
24
  mcp_agent/cli/terminal.py,sha256=GRwD-RGW7saIz2IOWZn5vD6JjiArscELBThm1GTFkuI,1065
25
- mcp_agent/cli/commands/bootstrap.py,sha256=UiTt0fO_IpaHqFCKAW5tg7BIH04vPXf8xH0hJjPM52M,11602
26
25
  mcp_agent/cli/commands/config.py,sha256=jU2gl4d5YESrdUboh3u6mxf7CxVT-_DT_sK8Vuh3ajw,231
27
- mcp_agent/cli/commands/setup.py,sha256=CsmfIvKFfOhU1bOkm1cTqNseQdn3qdlfXN4BALwQ3Ik,6345
26
+ mcp_agent/cli/commands/quickstart.py,sha256=SM3CHMzDgvTxIpKjFuX9BrS_N1vRoXNBDaO90aWx1Rk,14586
27
+ mcp_agent/cli/commands/setup.py,sha256=YoZM5DiYj-4CaB5cOPistH8UHCTzZGnOsFhaFcqosB0,6470
28
28
  mcp_agent/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  mcp_agent/core/agent_app.py,sha256=5nQJNo8DocIRWiX4pVKAHUZF8s6HWpc-hJnfzl_1v1c,9697
30
30
  mcp_agent/core/agent_types.py,sha256=LuWslu9YI6JRnAWwh_A1ZejK72-e839wH7tf2MHxSIU,1389
@@ -62,9 +62,9 @@ mcp_agent/llm/providers/__init__.py,sha256=heVxtmuqFJOnjjxHz4bWSqTAxXoN1E8twC_gQ
62
62
  mcp_agent/llm/providers/anthropic_utils.py,sha256=vYDN5G5jKMhD2CQg8veJYab7tvvzYkDMq8M1g_hUAQg,3275
63
63
  mcp_agent/llm/providers/augmented_llm_anthropic.py,sha256=CNKpTEvWqjOteACUx_Vha0uFpPt32C17JrkSXg_allM,14445
64
64
  mcp_agent/llm/providers/augmented_llm_deepseek.py,sha256=SdYDqZZ9hM9sBvW1FSItNn_ENEKQXGNKwVHGnjqjyAA,1927
65
- mcp_agent/llm/providers/augmented_llm_generic.py,sha256=IIgwPYsVGwDdL2mMYsc5seY3pVFblMwmnxoI5dbxras,1524
65
+ mcp_agent/llm/providers/augmented_llm_generic.py,sha256=v6r8mbDO69fpQnvFoy62QyQTnq2qXR2DBbn5o3pyhvg,1533
66
66
  mcp_agent/llm/providers/augmented_llm_openai.py,sha256=Wso9GVgsq8y3sqlOzTk_iQqrkCOL3LyuG07nA1PWDng,17913
67
- mcp_agent/llm/providers/augmented_llm_openrouter.py,sha256=AajWXFIgGEDjeEx8AWCTs3mZGTPaihdsrjEUiNAJkIM,3501
67
+ mcp_agent/llm/providers/augmented_llm_openrouter.py,sha256=jcnbjMO2NHETOOwc3BPZUcfv8gObczpnYDRZeKlV6eY,3552
68
68
  mcp_agent/llm/providers/multipart_converter_anthropic.py,sha256=t5lHYGfFUacJldnrVtMNW-8gEMoto8Y7hJkDrnyZR-Y,16650
69
69
  mcp_agent/llm/providers/multipart_converter_openai.py,sha256=zCj0LBgd9FDG8aL_GeTrPo2ssloYnmC_Uj3ENWVUJAg,16753
70
70
  mcp_agent/llm/providers/openai_multipart.py,sha256=qKBn7d3jSabnJmVgWweVzqh8q9mBqr09fsPmP92niAQ,6899
@@ -85,11 +85,11 @@ mcp_agent/mcp/interfaces.py,sha256=vma7bbWbY3zp1RM6hMYxVO4aV6Vfaygm-nLwzK2jFKI,6
85
85
  mcp_agent/mcp/logger_textio.py,sha256=vljC1BtNTCxBAda9ExqNB-FwVNUZIuJT3h1nWmCjMws,3172
86
86
  mcp_agent/mcp/mcp_agent_client_session.py,sha256=RMYNltc2pDIzxwEJSS5589RbvPO0KWV4Y3jSyAmhKf0,4181
87
87
  mcp_agent/mcp/mcp_aggregator.py,sha256=jaWbOvb3wioECohZ47CubyxfJ5QkfNSshu1hwhZksG4,40486
88
- mcp_agent/mcp/mcp_connection_manager.py,sha256=AMIm2FBbIk7zHInb8X-kFSQFO5TKcoi9w8WU8nx8Ig0,13834
88
+ mcp_agent/mcp/mcp_connection_manager.py,sha256=FGFF3DruVcHD_8J-VadrRyyrOiiq-N9-_ZzIdx4NUOA,13973
89
89
  mcp_agent/mcp/mime_utils.py,sha256=difepNR_gpb4MpMLkBRAoyhDk-AjXUHTiqKvT_VwS1o,1805
90
90
  mcp_agent/mcp/prompt_message_multipart.py,sha256=IpIndd75tAcCbJbfqjpAF0tOUUP1TQceDbWoxO5gvpo,3684
91
91
  mcp_agent/mcp/prompt_render.py,sha256=k3v4BZDThGE2gGiOYVQtA6x8WTEdOuXIEnRafANhN1U,2996
92
- mcp_agent/mcp/prompt_serialization.py,sha256=El12k47c9568sju6fqiaYkYySC9RVhScarHeR_QihNk,17323
92
+ mcp_agent/mcp/prompt_serialization.py,sha256=MQY6QxnhQTiq0oBDsyRzFtX8sBiovUjzUFX78As8q60,17974
93
93
  mcp_agent/mcp/resource_utils.py,sha256=K4XY8bihmBMleRTZ2viMPiD2Y2HWxFnlgIJi6dd_PYE,6588
94
94
  mcp_agent/mcp/sampling.py,sha256=vzWrIdI1CyFSxDWO-O69TpD6RwQcCM694BqMlYPVtaw,4584
95
95
  mcp_agent/mcp/helpers/__init__.py,sha256=sKqwlUR3jSsd9PVJKjXtxHgZA1YOdzPtsSW4xVey77Q,52
@@ -98,16 +98,17 @@ mcp_agent/mcp/prompts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
98
98
  mcp_agent/mcp/prompts/__main__.py,sha256=gr1Tdz9fcK0EXjEuZg_BOnKUmvhYq5AH2lFZicVyNb0,237
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
- mcp_agent/mcp/prompts/prompt_load.py,sha256=VkcY6dD1jRCu-OB5AtSO8YwVATjEoYCkyAIGIujIHmw,5583
102
- mcp_agent/mcp/prompts/prompt_server.py,sha256=tXtQd4EnH86MmdAvHlXm4oOS1dWLSCW5PvoA7uU1TvA,16493
101
+ mcp_agent/mcp/prompts/prompt_load.py,sha256=Zo0FogqWFEG5FtF1d9ZH-RWsCSSMsi5FIEQHpJD8N7M,5404
102
+ mcp_agent/mcp/prompts/prompt_server.py,sha256=SiUR2xYfd3vEpghnYRdzz2rFEMtAbCKx2xzUXgvz1g8,18501
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
- mcp_agent/mcp_server/agent_server.py,sha256=LVZNML2_ysK7nVVLDou8pQuQWiEsMFZLryn_KihmkUQ,6431
105
+ mcp_agent/mcp_server/agent_server.py,sha256=Nzws9h-itEqx9ml87Wx_mKhyoHehAvcAgsve0PZgghI,5905
106
106
  mcp_agent/resources/examples/data-analysis/analysis-campaign.py,sha256=QdNdo0-7LR4Uzw61hEU_jVKmWyk6A9YpGo81kMwVobM,7267
107
107
  mcp_agent/resources/examples/data-analysis/analysis.py,sha256=M9z8Q4YC5OGuqSa5uefYmmfmctqMn-WqCSfg5LI407o,2609
108
108
  mcp_agent/resources/examples/data-analysis/fastagent.config.yaml,sha256=ini94PHyJCfgpjcjHKMMbGuHs6LIj46F1NwY0ll5HVk,1609
109
109
  mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv,sha256=pcMeOL1_r8m8MziE6xgbBrQbjl5Ijo98yycZn7O-dlk,227977
110
110
  mcp_agent/resources/examples/in_dev/agent_build.py,sha256=eetMEdYDbmnRH4CLO7chpQucAar3OE7iVzD_pnMjIGs,2854
111
+ mcp_agent/resources/examples/in_dev/css-LICENSE.txt,sha256=zv0cyruZlRdeDUploPpO54kV1x1fFAc90X7vXVPrUIY,1073
111
112
  mcp_agent/resources/examples/in_dev/slides.py,sha256=-SEFeGIg9SLF253NIxmA0NjlanLe8CR1yjDBBp2LXgs,4904
112
113
  mcp_agent/resources/examples/internal/agent.py,sha256=JDfb-64gKoEG6ihsyyVWkuY9XNOdC1-P3r9qwG_qN28,497
113
114
  mcp_agent/resources/examples/internal/fastagent.config.yaml,sha256=EPJW8vsRfYq57w2U2gPF0rTAxGhkaLgiYXw0mnpXsdM,2060
@@ -115,12 +116,19 @@ mcp_agent/resources/examples/internal/history_transfer.py,sha256=ETyX2wMMvUnMpUh
115
116
  mcp_agent/resources/examples/internal/job.py,sha256=ANF3c01gHJ4O4pIxaAtC3rdgYqVObMySaCUBS4dApW4,4102
116
117
  mcp_agent/resources/examples/internal/prompt_category.py,sha256=kMvqNX_zu0sV-kTaAR3skc_tsq9t8QSEofciK0m4aJc,551
117
118
  mcp_agent/resources/examples/internal/prompt_sizing.py,sha256=bskgxulN57hVkc0V9W0fnjnqSRCK5Tkw9Ggf2MmGIVU,1989
119
+ mcp_agent/resources/examples/internal/simple.txt,sha256=lcWo9h4NJE1OshBhRgg2QBHhHHqcrVj5j1LWdlyYlAk,14
118
120
  mcp_agent/resources/examples/internal/sizer.py,sha256=xP1TBJkp4xIdtJnyk2MP4BufThauzULaMmgnt5Y5Iw4,365
119
121
  mcp_agent/resources/examples/internal/social.py,sha256=pTKcpHAcvA-vQYgjVfDuU1FivCR004Nq4N2GXd5OMs0,1716
122
+ mcp_agent/resources/examples/mcp/state-transfer/agent_one.py,sha256=HR-Igr8k68HU0tqIpaXujtJxnKSUwwtZqTdZk8QHNgo,455
123
+ mcp_agent/resources/examples/mcp/state-transfer/agent_two.py,sha256=TY9SPzJZFv3TL6VEP3IpdJvTjYup5txF_DjpvEzlmbw,476
124
+ mcp_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml,sha256=yxrBBvE3icol3mFrIQ5FLWPWCci4S5LDHQGXy8Mcbnk,796
125
+ mcp_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example,sha256=0n3F2S_Z2CeLHZueZqCGy37mxiMDHLplvxUHYiCpD2A,421
120
126
  mcp_agent/resources/examples/prompting/__init__.py,sha256=2GSrs9MSDIKo-uDrUI0O311F0UH0RW02ZNdvItJzjfI,50
121
127
  mcp_agent/resources/examples/prompting/agent.py,sha256=yuONn6xkQfk6hjanC9j5_zsIK6JtRP7N-tlgVYiKJnE,616
128
+ mcp_agent/resources/examples/prompting/delimited_prompt.txt,sha256=T_RRcJVXbrI6fXUIatQxx-8vALJ64qQqh-2WPeRS1b8,305
122
129
  mcp_agent/resources/examples/prompting/fastagent.config.yaml,sha256=UR6LtCpeSIzkHsCrHJW1z-wE7AgmgKozS_IYcfcSAkc,1270
123
130
  mcp_agent/resources/examples/prompting/image_server.py,sha256=vRDRGi68BqTWcldZ4-sd8j41M3e5TtWIUSzIROK8uFo,1667
131
+ mcp_agent/resources/examples/prompting/prompt1.txt,sha256=H3Is5WvS9xeB7eP2-4bWF5PfZhZ6B0BICKGdGeKL9WE,64
124
132
  mcp_agent/resources/examples/prompting/work_with_image.py,sha256=2MctSPXZsmIyCYvsxsRc1_v_8v0ZKorHH0gWZxLW8Tc,507
125
133
  mcp_agent/resources/examples/researcher/fastagent.config.yaml,sha256=bNOnID9OgdSBTUEhdimKB8LjaZLa1B6igmp-nxx8nr4,2271
126
134
  mcp_agent/resources/examples/researcher/researcher-eval.py,sha256=CR9m4lyoXijS1whvsBDuk6IA-RmNc6iOYbtloETkITY,1833
@@ -133,9 +141,10 @@ mcp_agent/resources/examples/workflows/human_input.py,sha256=_I6nS6xYo8IHAmvzsUY
133
141
  mcp_agent/resources/examples/workflows/orchestrator.py,sha256=rOGilFTliWWnZ3Jx5wZOH6AQMBKwaGqSMI4PR9MKcZw,2507
134
142
  mcp_agent/resources/examples/workflows/parallel.py,sha256=n0dFN26QvYd2wjgohcaUBflac2SzXYx-bCyxMSousJE,1884
135
143
  mcp_agent/resources/examples/workflows/router.py,sha256=E4x_-c3l4YW9w1i4ARcDtkdeqIdbWEGfsMzwLYpdbVc,1677
144
+ mcp_agent/resources/examples/workflows/short_story.txt,sha256=X3y_1AyhLFN2AKzCKvucJtDgAFIJfnlbsbGZO5bBWu0,1187
136
145
  mcp_agent/ui/console_display.py,sha256=TVGDtJ37hc6UG0ei9g7ZPZZfFNeS1MYozt-Mx8HsPCk,9752
137
- fast_agent_mcp-0.2.9.dist-info/METADATA,sha256=Jr7h2V_0O36zTw-_2XfEK2KXbDeoWR61heYQmPQOSWc,29849
138
- fast_agent_mcp-0.2.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
139
- fast_agent_mcp-0.2.9.dist-info/entry_points.txt,sha256=qPM7vwtN1_KmP3dXehxgiCxUBHtqP7yfenZigztvY-w,226
140
- fast_agent_mcp-0.2.9.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
141
- fast_agent_mcp-0.2.9.dist-info/RECORD,,
146
+ fast_agent_mcp-0.2.11.dist-info/METADATA,sha256=1kdkV2W3MbPI2IkokeFwfA-rEdmkTZUR6C8nfFMmVrk,29940
147
+ fast_agent_mcp-0.2.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
148
+ fast_agent_mcp-0.2.11.dist-info/entry_points.txt,sha256=bRniFM5zk3Kix5z7scX0gf9VnmGQ2Cz_Q1Gh7Ir4W00,186
149
+ fast_agent_mcp-0.2.11.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
150
+ fast_agent_mcp-0.2.11.dist-info/RECORD,,
@@ -1,6 +1,5 @@
1
1
  [console_scripts]
2
2
  fast-agent = mcp_agent.cli.__main__:app
3
- fast_agent = mcp_agent.cli.__main__:app
4
3
  fastagent = mcp_agent.cli.__main__:app
5
4
  prompt-server = mcp_agent.mcp.prompts.__main__:main
6
5
  silsila = mcp_agent.cli.__main__:app
@@ -47,6 +47,18 @@ EXAMPLE_TYPES = {
47
47
  "mount_point_files": ["WA_Fn-UseC_-HR-Employee-Attrition.csv"],
48
48
  "create_subdir": True,
49
49
  },
50
+ "state-transfer": {
51
+ "description": "Example demonstrating state transfer between multiple agents.\n"
52
+ "Shows how state can be passed between agent runs to maintain context.\n"
53
+ "Creates examples in a 'state-transfer' subdirectory.",
54
+ "files": [
55
+ "agent_one.py",
56
+ "agent_two.py",
57
+ "fastagent.config.yaml",
58
+ "fastagent.secrets.yaml.example",
59
+ ],
60
+ "create_subdir": True,
61
+ },
50
62
  }
51
63
 
52
64
 
@@ -75,28 +87,54 @@ def copy_example_files(example_type: str, target_dir: Path, force: bool = False)
75
87
 
76
88
  try:
77
89
  # First try to find examples in the package resources
78
- source_dir = (
79
- files("mcp_agent")
80
- .joinpath("resources")
81
- .joinpath("examples")
82
- .joinpath("workflows" if example_type == "workflow" else f"{example_type}")
83
- )
90
+ if example_type == "state-transfer":
91
+ # The state-transfer example is in the mcp subdirectory
92
+ source_dir = (
93
+ files("mcp_agent")
94
+ .joinpath("resources")
95
+ .joinpath("examples")
96
+ .joinpath("mcp")
97
+ .joinpath("state-transfer")
98
+ )
99
+ else:
100
+ # Other examples are at the top level of examples
101
+ source_dir = (
102
+ files("mcp_agent")
103
+ .joinpath("resources")
104
+ .joinpath("examples")
105
+ .joinpath("workflows" if example_type == "workflow" else f"{example_type}")
106
+ )
107
+
108
+ # Check if we found a valid directory
84
109
  if not source_dir.is_dir():
110
+ console.print(
111
+ f"[yellow]Resource directory not found: {source_dir}. Falling back to development mode.[/yellow]"
112
+ )
85
113
  # Fall back to the top-level directory for development mode
86
114
  package_dir = Path(__file__).parent.parent.parent.parent.parent
115
+ if example_type == "state-transfer":
116
+ source_dir = package_dir / "examples" / "mcp" / "state-transfer"
117
+ else:
118
+ source_dir = (
119
+ package_dir
120
+ / "examples"
121
+ / ("workflows" if example_type == "workflow" else f"{example_type}")
122
+ )
123
+ console.print(f"[blue]Using development directory: {source_dir}[/blue]")
124
+ except (ImportError, ModuleNotFoundError, ValueError) as e:
125
+ console.print(
126
+ f"[yellow]Error accessing resources: {e}. Falling back to development mode.[/yellow]"
127
+ )
128
+ # Fall back to the top-level directory if the resource finding fails
129
+ package_dir = Path(__file__).parent.parent.parent.parent.parent
130
+ if example_type == "state-transfer":
131
+ source_dir = package_dir / "examples" / "mcp" / "state-transfer"
132
+ else:
87
133
  source_dir = (
88
134
  package_dir
89
135
  / "examples"
90
136
  / ("workflows" if example_type == "workflow" else f"{example_type}")
91
137
  )
92
- except (ImportError, ModuleNotFoundError, ValueError):
93
- # Fall back to the top-level directory if the resource finding fails
94
- package_dir = Path(__file__).parent.parent.parent.parent.parent
95
- source_dir = (
96
- package_dir
97
- / "examples"
98
- / ("workflows" if example_type == "workflow" else f"{example_type}")
99
- )
100
138
 
101
139
  if not source_dir.exists():
102
140
  console.print(f"[red]Error: Source directory not found: {source_dir}[/red]")
@@ -116,7 +154,14 @@ def copy_example_files(example_type: str, target_dir: Path, force: bool = False)
116
154
  continue
117
155
 
118
156
  shutil.copy2(source, target)
119
- created.append(str(target.relative_to(target_dir.parent)))
157
+ try:
158
+ # This can fail in test environments where the target is not relative to target_dir.parent
159
+ rel_path = str(target.relative_to(target_dir.parent))
160
+ except ValueError:
161
+ # Fallback to just the filename
162
+ rel_path = f"{example_type}/{filename}"
163
+
164
+ created.append(rel_path)
120
165
  console.print(f"[green]Created[/green] {created[-1]}")
121
166
 
122
167
  except Exception as e:
@@ -174,15 +219,17 @@ def show_overview() -> None:
174
219
  # Show usage instructions in a panel
175
220
  usage_text = (
176
221
  "[bold]Commands:[/bold]\n"
177
- " fastagent bootstrap workflow DIR Create workflow examples in DIR\n"
178
- " fastagent bootstrap researcher DIR Create researcher example in 'researcher' subdirectory\n"
179
- " fastagent bootstrap data-analysis DIR Create data analysis examples in 'data-analysis' subdirectory\n\n"
222
+ " fastagent quickstart workflow DIR Create workflow examples in DIR\n"
223
+ " fastagent quickstart researcher DIR Create researcher example in 'researcher' subdirectory\n"
224
+ " fastagent quickstart data-analysis DIR Create data analysis examples in 'data-analysis' subdirectory\n"
225
+ " fastagent quickstart state-transfer DIR Create state transfer examples in 'state-transfer' subdirectory\n\n"
180
226
  "[bold]Options:[/bold]\n"
181
227
  " --force Overwrite existing files\n\n"
182
228
  "[bold]Examples:[/bold]\n"
183
- " fastagent bootstrap workflow . Create in current directory\n"
184
- " fastagent bootstrap researcher . Create in researcher subdirectory\n"
185
- " fastagent bootstrap data-analysis . --force Force overwrite files in data-analysis subdirectory"
229
+ " fastagent quickstart workflow . Create in current directory\n"
230
+ " fastagent quickstart researcher . Create in researcher subdirectory\n"
231
+ " fastagent quickstart data-analysis . --force Force overwrite files in data-analysis subdirectory\n"
232
+ " fastagent quickstart state-transfer . Create state transfer examples"
186
233
  )
187
234
  console.print(Panel(usage_text, title="Usage", border_style="blue"))
188
235
 
@@ -241,6 +288,24 @@ def data_analysis(
241
288
  _show_completion_message("data-analysis", created)
242
289
 
243
290
 
291
+ @app.command()
292
+ def state_transfer(
293
+ directory: Path = typer.Argument(
294
+ Path("."),
295
+ help="Directory where state transfer examples will be created (in 'state-transfer' subdirectory)",
296
+ ),
297
+ force: bool = typer.Option(False, "--force", "-f", help="Force overwrite existing files"),
298
+ ) -> None:
299
+ """Create state transfer example showing state passing between agents."""
300
+ target_dir = directory.resolve()
301
+ if not target_dir.exists():
302
+ target_dir.mkdir(parents=True)
303
+ console.print(f"Created directory: {target_dir}")
304
+
305
+ created = copy_example_files("state-transfer", target_dir, force)
306
+ _show_completion_message("state-transfer", created)
307
+
308
+
244
309
  def _show_completion_message(example_type: str, created: list[str]) -> None:
245
310
  """Show completion message and next steps."""
246
311
  if created:
@@ -275,6 +340,8 @@ def _show_completion_message(example_type: str, created: list[str]) -> None:
275
340
  console.print(
276
341
  "On Windows platforms, please edit the fastagent.config.yaml and adjust the volume mount point."
277
342
  )
343
+ elif example_type == "state-transfer":
344
+ console.print("Check https://fast-agent.ai for quick start walkthroughs")
278
345
  else:
279
346
  console.print("\n[yellow]No files were created.[/yellow]")
280
347
 
@@ -55,12 +55,18 @@ FASTAGENT_SECRETS_TEMPLATE = """
55
55
  # FastAgent Secrets Configuration
56
56
  # WARNING: Keep this file secure and never commit to version control
57
57
 
58
- # Alternatively set OPENAI_API_KEY and ANTHROPIC_API_KEY environment variables. Config file takes precedence.
58
+ # Alternatively set OPENAI_API_KEY, ANTHROPIC_API_KEY or other environment variables.
59
+ # Keys in the configuration file override environment variables.
59
60
 
60
61
  openai:
61
62
  api_key: <your-api-key-here>
62
63
  anthropic:
63
64
  api_key: <your-api-key-here>
65
+ deepseek:
66
+ api_key: <your-api-key-here>
67
+ openrouter:
68
+ api_key: <your-api-key-here>
69
+
64
70
 
65
71
  # Example of setting an MCP Server environment variable
66
72
  mcp:
@@ -116,15 +122,15 @@ import asyncio
116
122
  from mcp_agent.core.fastagent import FastAgent
117
123
 
118
124
  # Create the application
119
- fast = FastAgent("FastAgent Example")
125
+ fast = FastAgent("fast-agent example")
120
126
 
121
127
 
122
128
  # Define the agent
123
- @fast.agent(instruction="You are a helpful AI Agent", servers=["fetch"])
129
+ @fast.agent(instruction="You are a helpful AI Agent")
124
130
  async def main():
125
131
  # use the --model command line switch or agent arguments to change model
126
132
  async with fast.run() as agent:
127
- await agent()
133
+ await agent.interactive()
128
134
 
129
135
 
130
136
  if __name__ == "__main__":
mcp_agent/cli/main.py CHANGED
@@ -4,7 +4,7 @@ import typer
4
4
  from rich.console import Console
5
5
  from rich.table import Table
6
6
 
7
- from mcp_agent.cli.commands import bootstrap, setup
7
+ from mcp_agent.cli.commands import quickstart, setup
8
8
  from mcp_agent.cli.terminal import Application
9
9
 
10
10
  app = typer.Typer(
@@ -14,7 +14,8 @@ app = typer.Typer(
14
14
 
15
15
  # Subcommands
16
16
  app.add_typer(setup.app, name="setup", help="Set up a new agent project")
17
- app.add_typer(bootstrap.app, name="bootstrap", help="Create example applications")
17
+ app.add_typer(quickstart.app, name="bootstrap", help="Create example applications")
18
+ app.add_typer(quickstart.app, name="quickstart", help="Create example applications")
18
19
 
19
20
  # Shared application context
20
21
  application = Application()
@@ -39,7 +40,7 @@ def show_welcome() -> None:
39
40
  table.add_column("Description")
40
41
 
41
42
  table.add_row("setup", "Set up a new agent project with configuration files")
42
- table.add_row("bootstrap", "Create example applications (workflow, researcher, etc.)")
43
+ table.add_row("quickstart", "Create example applications (workflow, researcher, etc.)")
43
44
  # table.add_row("config", "Manage agent configuration settings")
44
45
 
45
46
  console.print(table)
@@ -48,12 +49,12 @@ def show_welcome() -> None:
48
49
  console.print("1. Set up a new project:")
49
50
  console.print(" fastagent setup")
50
51
  console.print("\n2. Create Building Effective Agents workflow examples:")
51
- console.print(" fastagent bootstrap workflow")
52
+ console.print(" fastagent quickstart workflow")
52
53
  console.print("\n3. Explore other examples:")
53
- console.print(" fastagent bootstrap")
54
+ console.print(" fastagent quickstart")
54
55
 
55
56
  console.print("\nUse --help with any command for more information")
56
- console.print("Example: fastagent bootstrap --help")
57
+ console.print("Example: fastagent quickstart --help")
57
58
 
58
59
 
59
60
  @app.callback(invoke_without_command=True)
@@ -74,6 +75,7 @@ def main(
74
75
  # Handle version flag
75
76
  if version:
76
77
  from importlib.metadata import version as get_version
78
+
77
79
  try:
78
80
  app_version = get_version("fast-agent-mcp")
79
81
  except: # noqa: E722
mcp_agent/config.py CHANGED
@@ -70,6 +70,9 @@ class MCPServerSettings(BaseModel):
70
70
  """The arguments for the server command."""
71
71
 
72
72
  read_timeout_seconds: int | None = None
73
+ """The timeout in seconds for the session."""
74
+
75
+ read_transport_sse_timeout_seconds: int = 300
73
76
  """The timeout in seconds for the server connection."""
74
77
 
75
78
  url: str | None = None
@@ -40,8 +40,8 @@ class GenericAugmentedLLM(OpenAIAugmentedLLM):
40
40
  return api_key or "ollama"
41
41
 
42
42
  def _base_url(self) -> str:
43
- base_url = None
43
+ base_url = os.getenv("GENERIC_BASE_URL", DEFAULT_OLLAMA_BASE_URL)
44
44
  if self.context.config and self.context.config.generic:
45
45
  base_url = self.context.config.generic.base_url
46
46
 
47
- return base_url if base_url else DEFAULT_OLLAMA_BASE_URL
47
+ return base_url
@@ -4,7 +4,7 @@ from mcp_agent.core.exceptions import ProviderKeyError
4
4
  from mcp_agent.core.request_params import RequestParams
5
5
  from mcp_agent.llm.providers.augmented_llm_openai import OpenAIAugmentedLLM
6
6
 
7
- OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
7
+ DEFAULT_OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
8
8
  # No single default model for OpenRouter, users must specify full path
9
9
  DEFAULT_OPENROUTER_MODEL = None
10
10
 
@@ -63,7 +63,7 @@ class OpenRouterAugmentedLLM(OpenAIAugmentedLLM):
63
63
 
64
64
  def _base_url(self) -> str:
65
65
  """Retrieve the OpenRouter base URL from config or use the default."""
66
- base_url = OPENROUTER_BASE_URL # Default
66
+ base_url = os.getenv("OPENROUTER_BASE_URL", DEFAULT_OPENROUTER_BASE_URL) # Default
67
67
  config = self.context.config
68
68
 
69
69
  # Check config file for override
@@ -271,7 +271,11 @@ class MCPConnectionManager(ContextDependent):
271
271
  logger.debug(f"{server_name}: Creating stdio client with custom error handler")
272
272
  return stdio_client(server_params, errlog=error_handler)
273
273
  elif config.transport == "sse":
274
- return sse_client(config.url, config.headers)
274
+ return sse_client(
275
+ config.url,
276
+ config.headers,
277
+ sse_read_timeout=config.read_transport_sse_timeout_seconds,
278
+ )
275
279
  else:
276
280
  raise ValueError(f"Unsupported transport: {config.transport}")
277
281
 
@@ -5,9 +5,9 @@ This module provides utilities for converting between different serialization fo
5
5
  and PromptMessageMultipart objects. It includes functionality for:
6
6
 
7
7
  1. JSON Serialization:
8
- - Converting PromptMessageMultipart objects to pure JSON format
9
- - Parsing JSON into PromptMessageMultipart objects
10
- - This is ideal for programmatic use and ensures all data fidelity
8
+ - Converting PromptMessageMultipart objects to MCP-compatible GetPromptResult JSON format
9
+ - Parsing GetPromptResult JSON into PromptMessageMultipart objects
10
+ - This is ideal for programmatic use and ensures full MCP compatibility
11
11
 
12
12
  2. Delimited Text Format:
13
13
  - Converting PromptMessageMultipart objects to delimited text (---USER, ---ASSISTANT)
@@ -19,7 +19,13 @@ and PromptMessageMultipart objects. It includes functionality for:
19
19
  import json
20
20
  from typing import List
21
21
 
22
- from mcp.types import EmbeddedResource, ImageContent, TextContent, TextResourceContents
22
+ from mcp.types import (
23
+ EmbeddedResource,
24
+ GetPromptResult,
25
+ ImageContent,
26
+ TextContent,
27
+ TextResourceContents,
28
+ )
23
29
 
24
30
  from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
25
31
  from mcp_agent.mcp.prompts.prompt_constants import (
@@ -33,51 +39,68 @@ from mcp_agent.mcp.prompts.prompt_constants import (
33
39
  # -------------------------------------------------------------------------
34
40
 
35
41
 
42
+ def multipart_messages_to_get_prompt_result(
43
+ messages: List[PromptMessageMultipart],
44
+ ) -> GetPromptResult:
45
+ """
46
+ Convert PromptMessageMultipart objects to a GetPromptResult container.
47
+
48
+ Args:
49
+ messages: List of PromptMessageMultipart objects
50
+
51
+ Returns:
52
+ GetPromptResult object containing flattened messages
53
+ """
54
+ # Convert multipart messages to regular PromptMessage objects
55
+ flat_messages = []
56
+ for message in messages:
57
+ flat_messages.extend(message.from_multipart())
58
+
59
+ # Create a GetPromptResult with the flattened messages
60
+ return GetPromptResult(messages=flat_messages)
61
+
62
+
36
63
  def multipart_messages_to_json(messages: List[PromptMessageMultipart]) -> str:
37
64
  """
38
- Convert PromptMessageMultipart objects to a pure JSON string.
65
+ Convert PromptMessageMultipart objects to a pure JSON string in GetPromptResult format.
39
66
 
40
- This approach preserves all data and structure exactly as is, but is less
41
- human-readable for text content.
67
+ This approach preserves all data and structure exactly as is, compatible with
68
+ the MCP GetPromptResult type.
42
69
 
43
70
  Args:
44
71
  messages: List of PromptMessageMultipart objects
45
72
 
46
73
  Returns:
47
- JSON string representation of the messages
74
+ JSON string representation with GetPromptResult container
48
75
  """
49
- # Convert to dictionaries using model_dump with proper JSON mode
50
- # The mode="json" parameter ensures proper handling of AnyUrl objects
51
- message_dicts = [
52
- message.model_dump(by_alias=True, mode="json", exclude_none=True) for message in messages
53
- ]
76
+ # First convert to GetPromptResult
77
+ result = multipart_messages_to_get_prompt_result(messages)
78
+
79
+ # Convert to dictionary using model_dump with proper JSON mode
80
+ result_dict = result.model_dump(by_alias=True, mode="json", exclude_none=True)
54
81
 
55
82
  # Convert to JSON string
56
- return json.dumps(message_dicts, indent=2)
83
+ return json.dumps(result_dict, indent=2)
57
84
 
58
85
 
59
86
  def json_to_multipart_messages(json_str: str) -> List[PromptMessageMultipart]:
60
87
  """
61
- Parse a JSON string into PromptMessageMultipart objects.
88
+ Parse a JSON string in GetPromptResult format into PromptMessageMultipart objects.
62
89
 
63
90
  Args:
64
- json_str: JSON string representation of messages
91
+ json_str: JSON string representation of GetPromptResult
65
92
 
66
93
  Returns:
67
94
  List of PromptMessageMultipart objects
68
95
  """
69
- # Parse JSON to list of dictionaries
70
- message_dicts = json.loads(json_str)
96
+ # Parse JSON to dictionary
97
+ result_dict = json.loads(json_str)
71
98
 
72
- # Convert dictionaries to PromptMessageMultipart objects
73
- messages = []
74
- for message_dict in message_dicts:
75
- # Parse message using Pydantic's model_validate method (Pydantic v2)
76
- # For Pydantic v1, this would use parse_obj instead
77
- message = PromptMessageMultipart.model_validate(message_dict)
78
- messages.append(message)
99
+ # Parse as GetPromptResult
100
+ result = GetPromptResult.model_validate(result_dict)
79
101
 
80
- return messages
102
+ # Convert to multipart messages
103
+ return PromptMessageMultipart.to_multipart(result.messages)
81
104
 
82
105
 
83
106
  def save_messages_to_json_file(messages: List[PromptMessageMultipart], file_path: str) -> None:
@@ -113,17 +136,18 @@ def load_messages_from_json_file(file_path: str) -> List[PromptMessageMultipart]
113
136
  def save_messages_to_file(messages: List[PromptMessageMultipart], file_path: str) -> None:
114
137
  """
115
138
  Save PromptMessageMultipart objects to a file, with format determined by file extension.
116
-
117
- Uses JSON format for .json files and delimited text format for other extensions.
118
-
139
+
140
+ Uses GetPromptResult JSON format for .json files (fully MCP compatible) and
141
+ delimited text format for other extensions.
142
+
119
143
  Args:
120
144
  messages: List of PromptMessageMultipart objects
121
145
  file_path: Path to save the file
122
146
  """
123
147
  path_str = str(file_path).lower()
124
-
148
+
125
149
  if path_str.endswith(".json"):
126
- # Use JSON format for .json files (MCP SDK compatible format)
150
+ # Use GetPromptResult JSON format for .json files (fully MCP compatible)
127
151
  save_messages_to_json_file(messages, file_path)
128
152
  else:
129
153
  # Use delimited text format for other extensions
@@ -133,19 +157,20 @@ def save_messages_to_file(messages: List[PromptMessageMultipart], file_path: str
133
157
  def load_messages_from_file(file_path: str) -> List[PromptMessageMultipart]:
134
158
  """
135
159
  Load PromptMessageMultipart objects from a file, with format determined by file extension.
136
-
137
- Uses JSON format for .json files and delimited text format for other extensions.
138
-
160
+
161
+ Uses GetPromptResult JSON format for .json files (fully MCP compatible) and
162
+ delimited text format for other extensions.
163
+
139
164
  Args:
140
165
  file_path: Path to the file
141
-
166
+
142
167
  Returns:
143
168
  List of PromptMessageMultipart objects
144
169
  """
145
170
  path_str = str(file_path).lower()
146
-
171
+
147
172
  if path_str.endswith(".json"):
148
- # Use JSON format for .json files (MCP SDK compatible format)
173
+ # Use GetPromptResult JSON format for .json files (fully MCP compatible)
149
174
  return load_messages_from_json_file(file_path)
150
175
  else:
151
176
  # Use delimited text format for other extensions
@@ -103,29 +103,34 @@ def create_resource_message(
103
103
  def load_prompt(file: Path) -> List[PromptMessage]:
104
104
  """
105
105
  Load a prompt from a file and return as PromptMessage objects.
106
-
106
+
107
107
  The loader uses file extension to determine the format:
108
- - .json files are loaded as MCP SDK compatible JSON format
108
+ - .json files are loaded as MCP SDK compatible GetPromptResult JSON format
109
109
  - All other files are loaded using the template-based delimited format
110
-
110
+
111
111
  Args:
112
112
  file: Path to the prompt file
113
-
113
+
114
114
  Returns:
115
115
  List of PromptMessage objects
116
116
  """
117
117
  file_str = str(file).lower()
118
-
118
+
119
119
  if file_str.endswith(".json"):
120
- # JSON format (MCP SDK compatible)
121
- from mcp_agent.mcp.prompt_serialization import load_messages_from_json_file
122
-
123
- # Load multipart messages and convert to flat messages
124
- multipart_messages = load_messages_from_json_file(str(file))
125
- messages = []
126
- for mp in multipart_messages:
127
- messages.extend(mp.from_multipart())
128
- return messages
120
+ # Handle JSON format as GetPromptResult
121
+ import json
122
+
123
+ from mcp.types import GetPromptResult
124
+
125
+ # Load JSON directly into GetPromptResult
126
+ with open(file, "r", encoding="utf-8") as f:
127
+ json_data = json.load(f)
128
+
129
+ # Parse as GetPromptResult object
130
+ result = GetPromptResult.model_validate(json_data)
131
+
132
+ # Return the messages directly
133
+ return result.messages
129
134
  else:
130
135
  # Template-based format (delimited text)
131
136
  template: PromptTemplate = PromptTemplateLoader().load_from_file(file)
@@ -135,23 +140,18 @@ def load_prompt(file: Path) -> List[PromptMessage]:
135
140
  def load_prompt_multipart(file: Path) -> List[PromptMessageMultipart]:
136
141
  """
137
142
  Load a prompt from a file and return as PromptMessageMultipart objects.
138
-
143
+
139
144
  The loader uses file extension to determine the format:
140
- - .json files are loaded as MCP SDK compatible JSON format
145
+ - .json files are loaded as MCP SDK compatible GetPromptResult JSON format
141
146
  - All other files are loaded using the template-based delimited format
142
-
147
+
143
148
  Args:
144
149
  file: Path to the prompt file
145
-
150
+
146
151
  Returns:
147
152
  List of PromptMessageMultipart objects
148
153
  """
149
- file_str = str(file).lower()
150
-
151
- if file_str.endswith(".json"):
152
- # JSON format (MCP SDK compatible)
153
- from mcp_agent.mcp.prompt_serialization import load_messages_from_json_file
154
- return load_messages_from_json_file(str(file))
155
- else:
156
- # Template-based format (delimited text)
157
- return PromptMessageMultipart.to_multipart(load_prompt(file))
154
+ # First load as regular PromptMessage objects
155
+ messages = load_prompt(file)
156
+ # Then convert to multipart messages
157
+ return PromptMessageMultipart.to_multipart(messages)
@@ -140,10 +140,59 @@ def get_delimiter_config(
140
140
  def register_prompt(file_path: Path, config: Optional[PromptConfig] = None) -> None:
141
141
  """Register a prompt file"""
142
142
  try:
143
+ # Check if it's a JSON file for ultra-minimal path
144
+ file_str = str(file_path).lower()
145
+ if file_str.endswith(".json"):
146
+ # Simple JSON handling - just load and register directly
147
+ from mcp.server.fastmcp.prompts.base import Prompt, PromptArgument
148
+
149
+ from mcp_agent.mcp.prompts.prompt_load import load_prompt
150
+
151
+ # Create metadata with minimal information
152
+ metadata = PromptMetadata(
153
+ name=file_path.stem,
154
+ description=f"JSON prompt: {file_path.stem}",
155
+ template_variables=set(),
156
+ resource_paths=[], # Skip resource handling
157
+ file_path=file_path,
158
+ )
159
+
160
+ # Ensure unique name
161
+ prompt_name = metadata.name
162
+ if prompt_name in prompt_registry:
163
+ base_name = prompt_name
164
+ suffix = 1
165
+ while prompt_name in prompt_registry:
166
+ prompt_name = f"{base_name}_{suffix}"
167
+ suffix += 1
168
+ metadata.name = prompt_name
169
+
170
+ prompt_registry[metadata.name] = metadata
171
+
172
+ # Create a simple handler that directly loads the JSON file each time
173
+ async def json_prompt_handler():
174
+ # Load the messages from the JSON file
175
+ messages = load_prompt(file_path)
176
+ # Convert to FastMCP format
177
+ return convert_to_fastmcp_messages(messages)
178
+
179
+ # Register directly with MCP
180
+ prompt = Prompt(
181
+ name=metadata.name,
182
+ description=metadata.description,
183
+ arguments=[], # No arguments for JSON prompts
184
+ fn=json_prompt_handler,
185
+ )
186
+ mcp._prompt_manager.add_prompt(prompt)
187
+
188
+ logger.info(f"Registered JSON prompt: {metadata.name} ({file_path})")
189
+ return # Early return - we're done with JSON files
190
+
191
+ # For non-JSON files, continue with the standard approach
143
192
  # Get delimiter configuration
144
193
  config_values = get_delimiter_config(config, file_path)
145
194
 
146
- # Use our prompt template loader to analyze the file
195
+ # Use standard template loader for text files
147
196
  loader = PromptTemplateLoader(
148
197
  {
149
198
  config_values["user_delimiter"]: "user",
@@ -21,7 +21,7 @@ class AgentMCPServer:
21
21
  server_description: str | None = None,
22
22
  ) -> None:
23
23
  self.agent_app = agent_app
24
- self.mcp_server = FastMCP(
24
+ self.mcp_server: FastMCP = FastMCP(
25
25
  name=server_name,
26
26
  instructions=server_description
27
27
  or f"This server provides access to {len(agent_app._agents)} agents",
@@ -95,16 +95,15 @@ class AgentMCPServer:
95
95
  try:
96
96
  await self.mcp_server.run_sse_async()
97
97
  except (asyncio.CancelledError, KeyboardInterrupt):
98
- # Gracefully handle cancellation during shutdown
99
- await self.shutdown()
100
- pass
98
+ print("Server Stopped (CTRL+C)")
99
+ return
101
100
  else: # stdio
102
101
  try:
103
102
  await self.mcp_server.run_stdio_async()
104
103
  except (asyncio.CancelledError, KeyboardInterrupt):
105
104
  # Gracefully handle cancellation during shutdown
106
- await self.shutdown()
107
- pass
105
+ print("Server Stopped (CTRL+C)")
106
+ return
108
107
 
109
108
  async def with_bridged_context(self, agent_context, mcp_context, func, *args, **kwargs):
110
109
  """
@@ -150,17 +149,4 @@ class AgentMCPServer:
150
149
  async def shutdown(self):
151
150
  """Gracefully shutdown the MCP server and its resources."""
152
151
  # Your MCP server may have additional cleanup code here
153
- try:
154
- # If your MCP server has a shutdown method, call it
155
- if hasattr(self.mcp_server, "shutdown"):
156
- await self.mcp_server.shutdown()
157
-
158
- # Clean up any other resources
159
- import asyncio
160
-
161
- # Allow any pending tasks to clean up
162
- await asyncio.sleep(0.5)
163
- except Exception as e:
164
- # Just log exceptions during shutdown, don't raise
165
- print(f"Error during MCP server shutdown: {e}")
166
- pass
152
+ pass
@@ -152,7 +152,11 @@ class ServerRegistry:
152
152
  raise ValueError(f"URL is required for SSE transport: {server_name}")
153
153
 
154
154
  # Use sse_client to get the read and write streams
155
- async with sse_client(config.url, config.headers) as (read_stream, write_stream):
155
+ async with sse_client(
156
+ config.url,
157
+ config.headers,
158
+ sse_read_timeout=config.read_transport_sse_timeout_seconds,
159
+ ) as (read_stream, write_stream):
156
160
  session = client_session_factory(
157
161
  read_stream,
158
162
  write_stream,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-2024 Paulo Cunha
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ hello, world
2
+
@@ -0,0 +1,18 @@
1
+ import asyncio
2
+
3
+ from mcp_agent.core.fastagent import FastAgent
4
+
5
+ # Create the application
6
+ fast = FastAgent("fast-agent agent_one (mcp server)")
7
+
8
+
9
+ # Define the agent
10
+ @fast.agent(name="agent_one", instruction="You are a helpful AI Agent.")
11
+ async def main():
12
+ # use the --model command line switch or agent arguments to change model
13
+ async with fast.run() as agent:
14
+ await agent.interactive()
15
+
16
+
17
+ if __name__ == "__main__":
18
+ asyncio.run(main())
@@ -0,0 +1,18 @@
1
+ import asyncio
2
+
3
+ from mcp_agent.core.fastagent import FastAgent
4
+
5
+ # Create the application
6
+ fast = FastAgent("fast-agent agent_two (mcp host)")
7
+
8
+
9
+ # Define the agent
10
+ @fast.agent(name="agent_two", instruction="You are a helpful AI Agent.", servers=["agent_one"])
11
+ async def main():
12
+ # use the --model command line switch or agent arguments to change model
13
+ async with fast.run() as agent:
14
+ await agent.interactive()
15
+
16
+
17
+ if __name__ == "__main__":
18
+ asyncio.run(main())
@@ -0,0 +1,27 @@
1
+ # Model string takes format:
2
+ # <provider>.<model_string>.<reasoning_effort?> (e.g. anthropic.claude-3-5-sonnet-20241022 or openai.o3-mini.low)
3
+ #
4
+ # Can be overriden with a command line switch --model=<model>, or within the Agent decorator.
5
+ # Check here for current details: https://fast-agent.ai/models/
6
+
7
+ # set the default model for fast-agent below:
8
+ default_model: gpt-4o
9
+
10
+ # Logging and Console Configuration:
11
+ logger:
12
+ # Switched off to avoid cluttering the console
13
+ progress_display: false
14
+
15
+ # Show chat User/Assistant messages on the console
16
+ show_chat: true
17
+ # Show tool calls on the console
18
+ show_tools: true
19
+ # Truncate long tool responses on the console
20
+ truncate_tools: true
21
+
22
+ # MCP Servers
23
+ mcp:
24
+ servers:
25
+ agent_one:
26
+ transport: sse
27
+ url: http://localhost:8001/sse
@@ -0,0 +1,14 @@
1
+ # FastAgent Secrets Configuration
2
+ # WARNING: Keep this file secure and never commit to version control
3
+
4
+ # Alternatively set OPENAI_API_KEY, ANTHROPIC_API_KEY or other environment variables.
5
+ # Keys in the configuration file override environment variables.
6
+
7
+ openai:
8
+ api_key: <your-api-key-here>
9
+ anthropic:
10
+ api_key: <your-api-key-here>
11
+ deepseek:
12
+ api_key: <your-api-key-here>
13
+ openrouter:
14
+ api_key: <your-api-key-here>
@@ -0,0 +1,14 @@
1
+ ---USER
2
+ I want to learn about {{topic}}.
3
+
4
+ Can you tell me about it in detail?
5
+
6
+ ---ASSISTANT
7
+ I'd be happy to tell you about {{topic}}!
8
+
9
+ Here are some key facts about {{topic}}:
10
+ 1. It's very interesting
11
+ 2. It has a rich history
12
+ 3. Many people study it
13
+
14
+ Would you like me to elaborate on any specific aspect?
@@ -0,0 +1,6 @@
1
+ Hello, World.
2
+
3
+ This is {{blah}} foo
4
+
5
+ This is {{terrible}} etc.
6
+
@@ -0,0 +1,19 @@
1
+ The Battle of Glimmerwood
2
+
3
+ In the heart of Glimmerwood, a mystical forest knowed for its radiant trees, a small village thrived.
4
+ The villagers, who were live peacefully, shared their home with the forest's magical creatures,
5
+ especially the Glimmerfoxes whose fur shimmer like moonlight.
6
+
7
+ One fateful evening, the peace was shaterred when the infamous Dark Marauders attack.
8
+ Lead by the cunning Captain Thorn, the bandits aim to steal the precious Glimmerstones which was believed to grant immortality.
9
+
10
+ Amidst the choas, a young girl named Elara stood her ground, she rallied the villagers and devised a clever plan.
11
+ Using the forests natural defenses they lured the marauders into a trap.
12
+ As the bandits aproached the village square, a herd of Glimmerfoxes emerged, blinding them with their dazzling light,
13
+ the villagers seized the opportunity to captured the invaders.
14
+
15
+ Elara's bravery was celebrated and she was hailed as the "Guardian of Glimmerwood".
16
+ The Glimmerstones were secured in a hidden grove protected by an ancient spell.
17
+
18
+ However, not all was as it seemed. The Glimmerstones true power was never confirm,
19
+ and whispers of a hidden agenda linger among the villagers.