fastmcp 2.12.5__py3-none-any.whl → 2.13.0__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.
- fastmcp/cli/cli.py +7 -6
- fastmcp/cli/install/claude_code.py +6 -6
- fastmcp/cli/install/claude_desktop.py +3 -3
- fastmcp/cli/install/cursor.py +7 -7
- fastmcp/cli/install/gemini_cli.py +3 -3
- fastmcp/cli/install/mcp_json.py +3 -3
- fastmcp/cli/run.py +13 -8
- fastmcp/client/auth/oauth.py +100 -208
- fastmcp/client/client.py +11 -11
- fastmcp/client/logging.py +18 -14
- fastmcp/client/oauth_callback.py +85 -171
- fastmcp/client/transports.py +77 -22
- fastmcp/contrib/component_manager/component_service.py +6 -6
- fastmcp/contrib/mcp_mixin/README.md +32 -1
- fastmcp/contrib/mcp_mixin/mcp_mixin.py +14 -2
- fastmcp/experimental/utilities/openapi/json_schema_converter.py +4 -0
- fastmcp/experimental/utilities/openapi/parser.py +23 -3
- fastmcp/prompts/prompt.py +13 -6
- fastmcp/prompts/prompt_manager.py +16 -101
- fastmcp/resources/resource.py +13 -6
- fastmcp/resources/resource_manager.py +5 -164
- fastmcp/resources/template.py +107 -17
- fastmcp/resources/types.py +30 -24
- fastmcp/server/auth/auth.py +40 -32
- fastmcp/server/auth/handlers/authorize.py +324 -0
- fastmcp/server/auth/jwt_issuer.py +236 -0
- fastmcp/server/auth/middleware.py +96 -0
- fastmcp/server/auth/oauth_proxy.py +1256 -242
- fastmcp/server/auth/oidc_proxy.py +23 -6
- fastmcp/server/auth/providers/auth0.py +40 -21
- fastmcp/server/auth/providers/aws.py +29 -3
- fastmcp/server/auth/providers/azure.py +178 -127
- fastmcp/server/auth/providers/descope.py +4 -6
- fastmcp/server/auth/providers/github.py +29 -8
- fastmcp/server/auth/providers/google.py +30 -9
- fastmcp/server/auth/providers/introspection.py +281 -0
- fastmcp/server/auth/providers/jwt.py +8 -2
- fastmcp/server/auth/providers/scalekit.py +179 -0
- fastmcp/server/auth/providers/supabase.py +172 -0
- fastmcp/server/auth/providers/workos.py +32 -14
- fastmcp/server/context.py +122 -36
- fastmcp/server/http.py +58 -18
- fastmcp/server/low_level.py +121 -2
- fastmcp/server/middleware/caching.py +469 -0
- fastmcp/server/middleware/error_handling.py +6 -2
- fastmcp/server/middleware/logging.py +48 -37
- fastmcp/server/middleware/middleware.py +28 -15
- fastmcp/server/middleware/rate_limiting.py +3 -3
- fastmcp/server/middleware/tool_injection.py +116 -0
- fastmcp/server/proxy.py +6 -6
- fastmcp/server/server.py +683 -207
- fastmcp/settings.py +24 -10
- fastmcp/tools/tool.py +7 -3
- fastmcp/tools/tool_manager.py +30 -112
- fastmcp/tools/tool_transform.py +3 -3
- fastmcp/utilities/cli.py +62 -22
- fastmcp/utilities/components.py +5 -0
- fastmcp/utilities/inspect.py +77 -21
- fastmcp/utilities/logging.py +118 -8
- fastmcp/utilities/mcp_server_config/v1/environments/uv.py +6 -6
- fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +3 -3
- fastmcp/utilities/mcp_server_config/v1/schema.json +3 -0
- fastmcp/utilities/tests.py +87 -4
- fastmcp/utilities/types.py +1 -1
- fastmcp/utilities/ui.py +617 -0
- {fastmcp-2.12.5.dist-info → fastmcp-2.13.0.dist-info}/METADATA +10 -6
- {fastmcp-2.12.5.dist-info → fastmcp-2.13.0.dist-info}/RECORD +70 -63
- fastmcp/cli/claude.py +0 -135
- fastmcp/utilities/storage.py +0 -204
- {fastmcp-2.12.5.dist-info → fastmcp-2.13.0.dist-info}/WHEEL +0 -0
- {fastmcp-2.12.5.dist-info → fastmcp-2.13.0.dist-info}/entry_points.txt +0 -0
- {fastmcp-2.12.5.dist-info → fastmcp-2.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,31 +2,30 @@ fastmcp/__init__.py,sha256=KX2d8UjlyJdYwock62tYV7vJSRwyxzrjq-jnU6Gre_c,1544
|
|
|
2
2
|
fastmcp/exceptions.py,sha256=-krEavxwddQau6T7MESCR4VjKNLfP9KHJrU1p3y72FU,744
|
|
3
3
|
fastmcp/mcp_config.py,sha256=zbli5c8hcUfxOlqYFBJXbogpVlXwtnCuJjTg3oTfmtQ,11375
|
|
4
4
|
fastmcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
fastmcp/settings.py,sha256=
|
|
5
|
+
fastmcp/settings.py,sha256=RqtXzbIGFWLFbgK82pGOx-OGWtrVKZe3KcBWinCgACY,13936
|
|
6
6
|
fastmcp/cli/__init__.py,sha256=Ii284TNoG5lxTP40ETMGhHEq3lQZWxu9m9JuU57kUpQ,87
|
|
7
|
-
fastmcp/cli/
|
|
8
|
-
fastmcp/cli/
|
|
9
|
-
fastmcp/cli/run.py,sha256=lN1N3TdAWV2pFEiPe08Pk6ZkePoyAXaJ3MRpApkXcyI,6882
|
|
7
|
+
fastmcp/cli/cli.py,sha256=jRU1bGwdJhccAE8q7I6Z9kX9qbY1gmgBiO6tyzCI5pw,29123
|
|
8
|
+
fastmcp/cli/run.py,sha256=HeaiHYcVY17JpHg4UjnIHkP5ttU0PNd1bZIL3brif8A,7047
|
|
10
9
|
fastmcp/cli/install/__init__.py,sha256=FUrwjMVaxONgz1qO7suzJNz1xosRfR3TOHlr3Z77JXA,797
|
|
11
|
-
fastmcp/cli/install/claude_code.py,sha256=
|
|
12
|
-
fastmcp/cli/install/claude_desktop.py,sha256=
|
|
13
|
-
fastmcp/cli/install/cursor.py,sha256=
|
|
14
|
-
fastmcp/cli/install/gemini_cli.py,sha256=
|
|
15
|
-
fastmcp/cli/install/mcp_json.py,sha256=
|
|
10
|
+
fastmcp/cli/install/claude_code.py,sha256=vGv8hbMUM6p5uQ1scy6E7Qxn0BZ2_INATF0xmSl5QWQ,7617
|
|
11
|
+
fastmcp/cli/install/claude_desktop.py,sha256=aX_BrH5ODEN6UPHdw-Gnh0r5g8TojvTA7trqQRCEdAw,6832
|
|
12
|
+
fastmcp/cli/install/cursor.py,sha256=o84evDEY7ZPVnljXY7KHiRwBrOm-zS39pu01LownSIw,10476
|
|
13
|
+
fastmcp/cli/install/gemini_cli.py,sha256=G7NhKnH21893baQjmVbFpwRyMbYIq7bocPQz1CBUH_8,7630
|
|
14
|
+
fastmcp/cli/install/mcp_json.py,sha256=l7b0sWB10YlbcXtcwJv1X2iHEP9V9EwuuD63PyTMvXI,5832
|
|
16
15
|
fastmcp/cli/install/shared.py,sha256=_1MNGCqf7BsAL6ntwA75wn86-0g-248ppQSAPQ8uTXk,5103
|
|
17
16
|
fastmcp/client/__init__.py,sha256=J-RcLU2WcnYnstXWoW01itGtAg7DEjvCsWyqQKQljoo,663
|
|
18
|
-
fastmcp/client/client.py,sha256=
|
|
17
|
+
fastmcp/client/client.py,sha256=ToiMSICH9wIl1HWvNoHSvb2JqJEBizrhvdh8UQ7rFQI,35851
|
|
19
18
|
fastmcp/client/elicitation.py,sha256=VNWgeBe2KipLp9mCc-6AApmfYAU1OlH9_3JdskfW_Wc,2521
|
|
20
|
-
fastmcp/client/logging.py,sha256=
|
|
19
|
+
fastmcp/client/logging.py,sha256=WBByRoBIB-Bl3ZUJVFvHqRt4teYPAvqC8MnJ358Elg8,1939
|
|
21
20
|
fastmcp/client/messages.py,sha256=NIPjt-5js_DkI5BD4OVdTf6pz-nGjc2dtbgt-vAY234,4329
|
|
22
|
-
fastmcp/client/oauth_callback.py,sha256=
|
|
21
|
+
fastmcp/client/oauth_callback.py,sha256=3xqL5_HD1QS9eGfw31HzoVF94QQelq_0TTqS7qWDlQQ,7709
|
|
23
22
|
fastmcp/client/progress.py,sha256=WjLLDbUKMsx8DK-fqO7AGsXb83ak-6BMrLvzzznGmcI,1043
|
|
24
23
|
fastmcp/client/roots.py,sha256=IxI_bHwHTmg6c2H-s1av1ZgrRnNDieHtYwdGFbzXT5c,2471
|
|
25
24
|
fastmcp/client/sampling.py,sha256=TXRj1Fs9lOk1wukhaHhPS__HGqpTieXSq2Rasj1F-e0,1819
|
|
26
|
-
fastmcp/client/transports.py,sha256=
|
|
25
|
+
fastmcp/client/transports.py,sha256=rVe8zQ5hbD2FQNUsRvtiH61j-C4Oj2F0oPauJN-aQwI,40977
|
|
27
26
|
fastmcp/client/auth/__init__.py,sha256=4DNsfp4iaQeBcpds0JDdMn6Mmfud44stWLsret0sVKY,91
|
|
28
27
|
fastmcp/client/auth/bearer.py,sha256=MFEFqcH6u_V86msYiOsEFKN5ks1V9BnBNiPsPLHUTqo,399
|
|
29
|
-
fastmcp/client/auth/oauth.py,sha256=
|
|
28
|
+
fastmcp/client/auth/oauth.py,sha256=pXgHDseI10AfzH7lsVfptSfflUjamtEU1rYhD9gLeMQ,11788
|
|
30
29
|
fastmcp/contrib/README.md,sha256=rKknYSI1T192UvSszqwwDlQ2eYQpxywrNTLoj177SYU,878
|
|
31
30
|
fastmcp/contrib/bulk_tool_caller/README.md,sha256=5aUUY1TSFKtz1pvTLSDqkUCkGkuqMfMZNsLeaNqEgAc,1960
|
|
32
31
|
fastmcp/contrib/bulk_tool_caller/__init__.py,sha256=xvGSSaUXTQrc31erBoi1Gh7BikgOliETDiYVTP3rLxY,75
|
|
@@ -35,12 +34,12 @@ fastmcp/contrib/bulk_tool_caller/example.py,sha256=6og_8pCJN_CabworC5R82zPAwwwM-
|
|
|
35
34
|
fastmcp/contrib/component_manager/README.md,sha256=sTan1D51jzkPNnCQTxwd5JXGzWVy4DtkUjrUfNH3-F0,4457
|
|
36
35
|
fastmcp/contrib/component_manager/__init__.py,sha256=4bppVrCOSEepKmBRwVWN-ndu5BYAz1Kv2Z8yhjEUmlo,164
|
|
37
36
|
fastmcp/contrib/component_manager/component_manager.py,sha256=4R1FPVYjCr-j7Mn6OcbHH-psl9-JTdd1hgNZHasC52Y,6412
|
|
38
|
-
fastmcp/contrib/component_manager/component_service.py,sha256=
|
|
37
|
+
fastmcp/contrib/component_manager/component_service.py,sha256=WGu3XcZSbHriSjvMfuroNZuT5xWWoYbEiIow8FPQNYg,8712
|
|
39
38
|
fastmcp/contrib/component_manager/example.py,sha256=N16OIHmQuR-LNEv7bkrv2rGdMs862Nc3AKKEPfw-6rU,1587
|
|
40
|
-
fastmcp/contrib/mcp_mixin/README.md,sha256=
|
|
39
|
+
fastmcp/contrib/mcp_mixin/README.md,sha256=f6ine6z9kuEx1qKhY9jzrH6sAwj1oWpXcLXGvK0GMVk,5404
|
|
41
40
|
fastmcp/contrib/mcp_mixin/__init__.py,sha256=aw9IQ1ssNjCgws4ZNt8bkdpossAAGVAwwjBpMp9O5ZQ,153
|
|
42
41
|
fastmcp/contrib/mcp_mixin/example.py,sha256=GnunkXmtG5hLLTUsM8aW5ZURU52Z8vI4tNLl-fK7Dg0,1228
|
|
43
|
-
fastmcp/contrib/mcp_mixin/mcp_mixin.py,sha256=
|
|
42
|
+
fastmcp/contrib/mcp_mixin/mcp_mixin.py,sha256=Ij009tiJBj1Lciz4abTICA1Il-kz_myr4aevQ4yGTNo,10582
|
|
44
43
|
fastmcp/experimental/sampling/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
44
|
fastmcp/experimental/sampling/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
45
|
fastmcp/experimental/sampling/handlers/base.py,sha256=mCPFj9ETc-Ro38R_pzx9rHVM2_EADCecScMkNWd6Tbs,714
|
|
@@ -54,81 +53,89 @@ fastmcp/experimental/utilities/openapi/README.md,sha256=pOXftamuVXxEMlOt-JAfpuvH
|
|
|
54
53
|
fastmcp/experimental/utilities/openapi/__init__.py,sha256=4uba3nOrt8hAv1I91BWkg2hMo3O0VmYlSNG058xwmiA,1677
|
|
55
54
|
fastmcp/experimental/utilities/openapi/director.py,sha256=zoYlIp4KESC8UlfKvooEtyzSO15P8T6YMZp5qCV6PfU,8078
|
|
56
55
|
fastmcp/experimental/utilities/openapi/formatters.py,sha256=1RCd8DwPU8_4uF51pj8Qp3oSZkZmoxL5VUwxBzokAMg,15540
|
|
57
|
-
fastmcp/experimental/utilities/openapi/json_schema_converter.py,sha256=
|
|
56
|
+
fastmcp/experimental/utilities/openapi/json_schema_converter.py,sha256=pHGGK13vU3L9Pg8ZqjYZxv8snVc06b6j1BB7R8pZCnY,13089
|
|
58
57
|
fastmcp/experimental/utilities/openapi/models.py,sha256=tgqrHdTbiDfMjiaNVHW5ndbXJ5lg_sajK0S5u9JQL6A,2805
|
|
59
|
-
fastmcp/experimental/utilities/openapi/parser.py,sha256=
|
|
58
|
+
fastmcp/experimental/utilities/openapi/parser.py,sha256=fAzcwCBvtBpNMN-tpSvoSuqbgojAs_NBZlG--NGpHwQ,34494
|
|
60
59
|
fastmcp/experimental/utilities/openapi/schemas.py,sha256=FE7aSgk3285X1okCh1ILLTxboQ-FCeFLyYZZ_jfejVI,23349
|
|
61
60
|
fastmcp/prompts/__init__.py,sha256=An8uMBUh9Hrb7qqcn_5_Hent7IOeSh7EA2IUVsIrtHc,179
|
|
62
|
-
fastmcp/prompts/prompt.py,sha256=
|
|
63
|
-
fastmcp/prompts/prompt_manager.py,sha256=
|
|
61
|
+
fastmcp/prompts/prompt.py,sha256=oKd-O7ry2114fMnglqgWHFWAqfGtQr4BPpKiHEt4jKY,14472
|
|
62
|
+
fastmcp/prompts/prompt_manager.py,sha256=5ZyT0blp5owuaN5pz_TQsyH6zUGFoUiVTGfiEnqBuj8,4262
|
|
64
63
|
fastmcp/resources/__init__.py,sha256=y1iAuqx-GIrS1NqIYzKezIDiYyjNEzzHD35epHpMnXE,463
|
|
65
|
-
fastmcp/resources/resource.py,sha256=
|
|
66
|
-
fastmcp/resources/resource_manager.py,sha256=
|
|
67
|
-
fastmcp/resources/template.py,sha256=
|
|
68
|
-
fastmcp/resources/types.py,sha256=
|
|
64
|
+
fastmcp/resources/resource.py,sha256=V3j08yft6pDIjpPTiU-DSGqeuHEVitVpfGoLFCmLoC0,7226
|
|
65
|
+
fastmcp/resources/resource_manager.py,sha256=V-oJje9-3fS__OOCihWGzE7-v3OfwyEfv-YGG1xY69E,13275
|
|
66
|
+
fastmcp/resources/template.py,sha256=vu9InVUKc5CvEOUvlTXsZ8-tpet_-kf8yX-rNrxE4Pw,14802
|
|
67
|
+
fastmcp/resources/types.py,sha256=efFLGD1Xc5Xq3sxlPaZ_8gtJ2UOixueTBV4KQTi4cOU,4936
|
|
69
68
|
fastmcp/server/__init__.py,sha256=bMD4aQD4yJqLz7-mudoNsyeV8UgQfRAg3PRwPvwTEds,119
|
|
70
|
-
fastmcp/server/context.py,sha256=
|
|
69
|
+
fastmcp/server/context.py,sha256=Y8uJapGlmPSDXUdO5yCqk-wzwK6P_mDKiJt8QsPndAw,27069
|
|
71
70
|
fastmcp/server/dependencies.py,sha256=so60cBZc4QuiKP2Y4ajR_NPkIF5d_b5wp8U3-ZfZMEQ,3888
|
|
72
71
|
fastmcp/server/elicitation.py,sha256=gmP17CzLQVpGzU00Ks31TWxdS-OLL5wTX_W5xRzs1Cc,8777
|
|
73
|
-
fastmcp/server/http.py,sha256=
|
|
74
|
-
fastmcp/server/low_level.py,sha256=
|
|
72
|
+
fastmcp/server/http.py,sha256=l_rEGP8K4_OJRUmYq_TQsy9441nffHsLvfm4wfFPOZg,12059
|
|
73
|
+
fastmcp/server/low_level.py,sha256=b1Sx0_Py0QxeLXSLdDA5PjR9Dd9ANB7KSNkkGSr1AeE,5490
|
|
75
74
|
fastmcp/server/openapi.py,sha256=vm8A8Qy-jzXuxILJs-nPOJLwU2yB0YHDqVpz2HX-AqM,42198
|
|
76
|
-
fastmcp/server/proxy.py,sha256=
|
|
77
|
-
fastmcp/server/server.py,sha256=
|
|
75
|
+
fastmcp/server/proxy.py,sha256=LoYoBEclvW_UJ6lLuckm2muzW_bOWHCc8oTxyzgTGsA,25769
|
|
76
|
+
fastmcp/server/server.py,sha256=BmC7mk7CJ6HezFBUS1v3QyH19d23DAJNqf5ZpX1VMbI,109443
|
|
78
77
|
fastmcp/server/auth/__init__.py,sha256=GwoyosVxuWCPzFHaCnj6iFp9fulnp124G2gQfsnzcgc,695
|
|
79
|
-
fastmcp/server/auth/auth.py,sha256=
|
|
80
|
-
fastmcp/server/auth/
|
|
81
|
-
fastmcp/server/auth/
|
|
78
|
+
fastmcp/server/auth/auth.py,sha256=b6QM-CEErFoQJgQFzgHDZTOAN33zTLmxEjeE83Crrw8,13628
|
|
79
|
+
fastmcp/server/auth/jwt_issuer.py,sha256=lJYvrpC1ygI4jkoJlL_nTH6m7FKdTw2lbEycKo4eHLY,7197
|
|
80
|
+
fastmcp/server/auth/middleware.py,sha256=xwj3fUCLSlJK6n1Ehp-FN1qnjKqEz8b7LGAGMTqQ8Hk,3284
|
|
81
|
+
fastmcp/server/auth/oauth_proxy.py,sha256=PgA8m5OjOcVHKdSt7U4_iIq1JwxchnoiSkmnKWDkb3Q,84053
|
|
82
|
+
fastmcp/server/auth/oidc_proxy.py,sha256=jqCzDI7w3oP9yENeHcTYtzvk9xkPJYAH3p090MDTDns,14475
|
|
82
83
|
fastmcp/server/auth/redirect_validation.py,sha256=Jlhela9xpTbw4aWnQ04A5Z-TW0HYOC3f9BMsq3NXx1Q,2000
|
|
84
|
+
fastmcp/server/auth/handlers/authorize.py,sha256=szfmMSRPL5D6sfi3awsg04UXBokVk4x_tJhAnYjHRfs,11453
|
|
83
85
|
fastmcp/server/auth/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
84
|
-
fastmcp/server/auth/providers/auth0.py,sha256=
|
|
85
|
-
fastmcp/server/auth/providers/aws.py,sha256=
|
|
86
|
-
fastmcp/server/auth/providers/azure.py,sha256=
|
|
86
|
+
fastmcp/server/auth/providers/auth0.py,sha256=dZkc7hppii20YWota_6_Y3vdNw-DZSq0OyModbly-RA,7814
|
|
87
|
+
fastmcp/server/auth/providers/aws.py,sha256=MXoEEnXmeIlRjaHqTeNCmJ90iTx9jwUdEdpyLUmzfIc,10852
|
|
88
|
+
fastmcp/server/auth/providers/azure.py,sha256=YOS7SuJUUzvpQnIOpAUqZVyHUNYu4ld5upcZHUBO340,14687
|
|
87
89
|
fastmcp/server/auth/providers/bearer.py,sha256=iu4pUj7TF5pT1wPuAGzDuM6lt5WtzenBN3c0otUleQY,923
|
|
88
|
-
fastmcp/server/auth/providers/descope.py,sha256
|
|
89
|
-
fastmcp/server/auth/providers/github.py,sha256=
|
|
90
|
-
fastmcp/server/auth/providers/google.py,sha256=
|
|
90
|
+
fastmcp/server/auth/providers/descope.py,sha256=mbqToTMLVR5-ZTUECv9jhVeT3TNjrXStL-D_zCE2Y1U,6348
|
|
91
|
+
fastmcp/server/auth/providers/github.py,sha256=xsv-Qj1VJRc64YcRuUG4a61xFH1nqqVX_biC7B1su9U,12414
|
|
92
|
+
fastmcp/server/auth/providers/google.py,sha256=5e-XnbAB1xWV0wVPiTg4Lmn_oyniP07wfZ2OKZPDQDM,13629
|
|
91
93
|
fastmcp/server/auth/providers/in_memory.py,sha256=CFCfYWMIPUxHNF5Liqud6ksedbykKV-RILWZqTxh3MY,14245
|
|
92
|
-
fastmcp/server/auth/providers/
|
|
93
|
-
fastmcp/server/auth/providers/
|
|
94
|
+
fastmcp/server/auth/providers/introspection.py,sha256=Izp8vEJG8Kyvu5Z-GWIvpKSeEZ2MYpw635MeqkPfb8w,10733
|
|
95
|
+
fastmcp/server/auth/providers/jwt.py,sha256=KzbvPjOKIE6hDvfQ_BdjYMT2CrNcErNOGHF8DvmfQF4,19666
|
|
96
|
+
fastmcp/server/auth/providers/scalekit.py,sha256=_CEdJ5S9eT24gnNlVYzRMhNAjrkoysVOAPDoyAz8Pxw,6628
|
|
97
|
+
fastmcp/server/auth/providers/supabase.py,sha256=6fPSFGxOUdA4E9zCB9AqyZpZTDNF3yHF5M0lQRipYLc,6478
|
|
98
|
+
fastmcp/server/auth/providers/workos.py,sha256=qCLKLrvbbPqVt7ddUw-NZL-9X171ZUuXVuZcOwBF7yg,17232
|
|
94
99
|
fastmcp/server/middleware/__init__.py,sha256=vh5C9ubN6q-y5QND32P4mQ4zDT89C7XYK39yqhELNAk,155
|
|
95
|
-
fastmcp/server/middleware/
|
|
96
|
-
fastmcp/server/middleware/
|
|
97
|
-
fastmcp/server/middleware/
|
|
98
|
-
fastmcp/server/middleware/
|
|
100
|
+
fastmcp/server/middleware/caching.py,sha256=L5cKT4_BrCvjQXIN4pMnrGNR3QAUXDpmk5h-Gl9qk6U,18279
|
|
101
|
+
fastmcp/server/middleware/error_handling.py,sha256=4PGbF39Cpa-h-WXwxOhPLvEM9_iAJ8IKbMTPnXbEyd8,7736
|
|
102
|
+
fastmcp/server/middleware/logging.py,sha256=oxFeMH5E5xs2i_Dbb9atmwbfG8Sohnlh8qgFB_L92uI,9411
|
|
103
|
+
fastmcp/server/middleware/middleware.py,sha256=USnE3fsQJnDh7HdKAj-QHTOoQ-QuF_zTnbhVQVqu0tU,6611
|
|
104
|
+
fastmcp/server/middleware/rate_limiting.py,sha256=MwhMOhgsIhZjYwEQB8H8961hohV5564JlTwwYy_9ctU,7915
|
|
99
105
|
fastmcp/server/middleware/timing.py,sha256=lL_xc-ErLD5lplfvd5-HIyWEbZhgNBYkcQ74KFXAMkA,5591
|
|
106
|
+
fastmcp/server/middleware/tool_injection.py,sha256=zElqBN-yjZvcTADp57e0dn86kpxT9xsFqvYztiXuA08,3595
|
|
100
107
|
fastmcp/server/sampling/handler.py,sha256=yjLzvxlGllE-EY4bc6djsijEmwMT24PCpV6vJl-sPcI,580
|
|
101
108
|
fastmcp/tools/__init__.py,sha256=vzqb-Y7Kf0d5T0aOsld-O-FA8kD7-4uFExChewFHEzY,201
|
|
102
|
-
fastmcp/tools/tool.py,sha256=
|
|
103
|
-
fastmcp/tools/tool_manager.py,sha256=
|
|
104
|
-
fastmcp/tools/tool_transform.py,sha256=
|
|
109
|
+
fastmcp/tools/tool.py,sha256=9zUikGGuxYON-IcxNmJRerId8Iy_EQf2gXLnmq1f2qc,20099
|
|
110
|
+
fastmcp/tools/tool_manager.py,sha256=pCQGvKimXYEigcUqRHBd6_mbfJwD2KN3i0SmFj9Fj_c,5913
|
|
111
|
+
fastmcp/tools/tool_transform.py,sha256=De_E_adWwBdBcmULpRDroiPrdGEbC4fFwXqcKxRVTpU,38462
|
|
105
112
|
fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31
|
|
106
113
|
fastmcp/utilities/auth.py,sha256=ZVHkNb4YBpLE1EmmFyhvFB2qfWDZdEYNH9TRI9jylOE,1140
|
|
107
|
-
fastmcp/utilities/cli.py,sha256=
|
|
108
|
-
fastmcp/utilities/components.py,sha256=
|
|
114
|
+
fastmcp/utilities/cli.py,sha256=efG2Ek2QcUdWZ62cHIOdfaG1bC9HO7QInSVQcJuEe7w,12198
|
|
115
|
+
fastmcp/utilities/components.py,sha256=lYB58QVm97szKjZ5kBs0aUKTQeIIEREte7WX5IHK5TU,5991
|
|
109
116
|
fastmcp/utilities/exceptions.py,sha256=7Z9j5IzM5rT27BC1Mcn8tkS-bjqCYqMKwb2MMTaxJYU,1350
|
|
110
117
|
fastmcp/utilities/http.py,sha256=1ns1ymBS-WSxbZjGP6JYjSO52Wa_ls4j4WbnXiupoa4,245
|
|
111
|
-
fastmcp/utilities/inspect.py,sha256=
|
|
118
|
+
fastmcp/utilities/inspect.py,sha256=K_WGvNbhO9bEGqi_V_N9uRLOH-_eM5UnKBnEhLTvPrc,18042
|
|
112
119
|
fastmcp/utilities/json_schema.py,sha256=jR-J_6IKVYe3VCwgrDLwiKJOGTdekvgbQJWXnEKJLHs,8824
|
|
113
120
|
fastmcp/utilities/json_schema_type.py,sha256=SX-qEZXC-sgUflOuIi3oi6jeCvIky3QS6m3Riihq6Xc,22273
|
|
114
|
-
fastmcp/utilities/logging.py,sha256=
|
|
121
|
+
fastmcp/utilities/logging.py,sha256=EIWMbCgFM5nWeiOpvkncrJVpe3CBI4Nn9rnw7cUpiBU,7185
|
|
115
122
|
fastmcp/utilities/mcp_config.py,sha256=qATTXMGiYET-7PflOixQOgiw3aOizX-RlloRjAo7nwI,1796
|
|
116
123
|
fastmcp/utilities/openapi.py,sha256=mfkY2XfWAmAOlKexArlrmDdD0Tkdqcn4TshsATaxB_o,63304
|
|
117
|
-
fastmcp/utilities/
|
|
118
|
-
fastmcp/utilities/
|
|
119
|
-
fastmcp/utilities/
|
|
124
|
+
fastmcp/utilities/tests.py,sha256=JJQ1MqmnOG2EyRwMjHhVFgRg39Rcz4tCU4pWm7L0wxM,8934
|
|
125
|
+
fastmcp/utilities/types.py,sha256=ZOgLVKkBwnB7npl6kk6zoS2sK17JWDbfRTzLUzXsrWU,14755
|
|
126
|
+
fastmcp/utilities/ui.py,sha256=Um089bgOO1BD45FWHKxLl31S9YniGVSIAVC3jLPnIqA,14010
|
|
120
127
|
fastmcp/utilities/mcp_server_config/__init__.py,sha256=qbfd0c6aBpi0_SVgwt4IQCQ9siqqxmr9PWSYGiPDJqE,791
|
|
121
128
|
fastmcp/utilities/mcp_server_config/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
122
|
-
fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py,sha256=
|
|
123
|
-
fastmcp/utilities/mcp_server_config/v1/schema.json,sha256=
|
|
129
|
+
fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py,sha256=65ZOxYEEVDg1lT_T99vTT9JZOhgQblNXYXbwgCYNPhc,15437
|
|
130
|
+
fastmcp/utilities/mcp_server_config/v1/schema.json,sha256=ymDNFOWzcpnhIMeJmVPTw9b-NtHoHoru8Mc0WlSVxUY,8602
|
|
124
131
|
fastmcp/utilities/mcp_server_config/v1/environments/__init__.py,sha256=Tkv0dmJ6tKKotOBo-tho09QVdvEjy37iBsvBbEwH0EA,256
|
|
125
132
|
fastmcp/utilities/mcp_server_config/v1/environments/base.py,sha256=FkrUsESEdW5akyn_FeR4tQB6Vlj7dO9VFcCj0YLCghQ,845
|
|
126
|
-
fastmcp/utilities/mcp_server_config/v1/environments/uv.py,sha256=
|
|
133
|
+
fastmcp/utilities/mcp_server_config/v1/environments/uv.py,sha256=DPVAXM5JDTN89wOSQsFnww4khRfNphXY2yzVeiKicNg,9755
|
|
127
134
|
fastmcp/utilities/mcp_server_config/v1/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
128
135
|
fastmcp/utilities/mcp_server_config/v1/sources/base.py,sha256=KWunc5peDLFdSdLX8l3UI9SNxtN-KNq2FOXAZ7XD62c,980
|
|
129
136
|
fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py,sha256=eFX47XNXz2oKHW8MZvx60dqyHkBxdg2FMOrHcyAS28g,8106
|
|
130
|
-
fastmcp-2.
|
|
131
|
-
fastmcp-2.
|
|
132
|
-
fastmcp-2.
|
|
133
|
-
fastmcp-2.
|
|
134
|
-
fastmcp-2.
|
|
137
|
+
fastmcp-2.13.0.dist-info/METADATA,sha256=UTIJvC0c-qWG5SJCoDFYm98dVQioc1E9gIzdHQF377A,20036
|
|
138
|
+
fastmcp-2.13.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
139
|
+
fastmcp-2.13.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
|
|
140
|
+
fastmcp-2.13.0.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
|
141
|
+
fastmcp-2.13.0.dist-info/RECORD,,
|
fastmcp/cli/claude.py
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"""Claude app integration utilities."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import os
|
|
5
|
-
import sys
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Any
|
|
8
|
-
|
|
9
|
-
from fastmcp.utilities.logging import get_logger
|
|
10
|
-
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment
|
|
11
|
-
|
|
12
|
-
logger = get_logger(__name__)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def get_claude_config_path() -> Path | None:
|
|
16
|
-
"""Get the Claude config directory based on platform."""
|
|
17
|
-
if sys.platform == "win32":
|
|
18
|
-
path = Path(Path.home(), "AppData", "Roaming", "Claude")
|
|
19
|
-
elif sys.platform == "darwin":
|
|
20
|
-
path = Path(Path.home(), "Library", "Application Support", "Claude")
|
|
21
|
-
elif sys.platform.startswith("linux"):
|
|
22
|
-
path = Path(
|
|
23
|
-
os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"), "Claude"
|
|
24
|
-
)
|
|
25
|
-
else:
|
|
26
|
-
return None
|
|
27
|
-
|
|
28
|
-
if path.exists():
|
|
29
|
-
return path
|
|
30
|
-
return None
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def update_claude_config(
|
|
34
|
-
file_spec: str,
|
|
35
|
-
server_name: str,
|
|
36
|
-
*,
|
|
37
|
-
with_editable: list[Path] | None = None,
|
|
38
|
-
with_packages: list[str] | None = None,
|
|
39
|
-
env_vars: dict[str, str] | None = None,
|
|
40
|
-
) -> bool:
|
|
41
|
-
"""Add or update a FastMCP server in Claude's configuration.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
file_spec: Path to the server file, optionally with :object suffix
|
|
45
|
-
server_name: Name for the server in Claude's config
|
|
46
|
-
with_editable: Optional list of directories to install in editable mode
|
|
47
|
-
with_packages: Optional list of additional packages to install
|
|
48
|
-
env_vars: Optional dictionary of environment variables. These are merged with
|
|
49
|
-
any existing variables, with new values taking precedence.
|
|
50
|
-
|
|
51
|
-
Raises:
|
|
52
|
-
RuntimeError: If Claude Desktop's config directory is not found, indicating
|
|
53
|
-
Claude Desktop may not be installed or properly set up.
|
|
54
|
-
"""
|
|
55
|
-
config_dir = get_claude_config_path()
|
|
56
|
-
if not config_dir:
|
|
57
|
-
raise RuntimeError(
|
|
58
|
-
"Claude Desktop config directory not found. Please ensure Claude Desktop"
|
|
59
|
-
" is installed and has been run at least once to initialize its config."
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
config_file = config_dir / "claude_desktop_config.json"
|
|
63
|
-
if not config_file.exists():
|
|
64
|
-
try:
|
|
65
|
-
config_file.write_text("{}")
|
|
66
|
-
except Exception as e:
|
|
67
|
-
logger.error(
|
|
68
|
-
"Failed to create Claude config file",
|
|
69
|
-
extra={
|
|
70
|
-
"error": str(e),
|
|
71
|
-
"config_file": str(config_file),
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
return False
|
|
75
|
-
|
|
76
|
-
try:
|
|
77
|
-
config = json.loads(config_file.read_text())
|
|
78
|
-
if "mcpServers" not in config:
|
|
79
|
-
config["mcpServers"] = {}
|
|
80
|
-
|
|
81
|
-
# Always preserve existing env vars and merge with new ones
|
|
82
|
-
if (
|
|
83
|
-
server_name in config["mcpServers"]
|
|
84
|
-
and "env" in config["mcpServers"][server_name]
|
|
85
|
-
):
|
|
86
|
-
existing_env = config["mcpServers"][server_name]["env"]
|
|
87
|
-
if env_vars:
|
|
88
|
-
# New vars take precedence over existing ones
|
|
89
|
-
env_vars = {**existing_env, **env_vars}
|
|
90
|
-
else:
|
|
91
|
-
env_vars = existing_env
|
|
92
|
-
|
|
93
|
-
env_config = UVEnvironment(
|
|
94
|
-
dependencies=(with_packages or []) + ["fastmcp"],
|
|
95
|
-
editable=[str(p) for p in with_editable] if with_editable else None,
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
# Convert file path to absolute before adding to command
|
|
99
|
-
# Split off any :object suffix first
|
|
100
|
-
if ":" in file_spec:
|
|
101
|
-
file_path, server_object = file_spec.rsplit(":", 1)
|
|
102
|
-
file_spec = f"{Path(file_path).resolve()}:{server_object}"
|
|
103
|
-
else:
|
|
104
|
-
file_spec = str(Path(file_spec).resolve())
|
|
105
|
-
|
|
106
|
-
# Build the full command
|
|
107
|
-
full_command = env_config.build_command(["fastmcp", "run", file_spec])
|
|
108
|
-
|
|
109
|
-
# Extract command and args for the config
|
|
110
|
-
server_config: dict[str, Any] = {
|
|
111
|
-
"command": full_command[0],
|
|
112
|
-
"args": full_command[1:],
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
# Add environment variables if specified
|
|
116
|
-
if env_vars:
|
|
117
|
-
server_config["env"] = env_vars
|
|
118
|
-
|
|
119
|
-
config["mcpServers"][server_name] = server_config
|
|
120
|
-
|
|
121
|
-
config_file.write_text(json.dumps(config, indent=2))
|
|
122
|
-
logger.info(
|
|
123
|
-
f"Added server '{server_name}' to Claude config",
|
|
124
|
-
extra={"config_file": str(config_file)},
|
|
125
|
-
)
|
|
126
|
-
return True
|
|
127
|
-
except Exception as e:
|
|
128
|
-
logger.error(
|
|
129
|
-
"Failed to update Claude config",
|
|
130
|
-
extra={
|
|
131
|
-
"error": str(e),
|
|
132
|
-
"config_file": str(config_file),
|
|
133
|
-
},
|
|
134
|
-
)
|
|
135
|
-
return False
|
fastmcp/utilities/storage.py
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
"""Key-value storage utilities for persistent data management."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Any, Protocol
|
|
8
|
-
|
|
9
|
-
import pydantic_core
|
|
10
|
-
|
|
11
|
-
from fastmcp.utilities.logging import get_logger
|
|
12
|
-
|
|
13
|
-
logger = get_logger(__name__)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class KVStorage(Protocol):
|
|
17
|
-
"""Protocol for key-value storage of JSON data."""
|
|
18
|
-
|
|
19
|
-
async def get(self, key: str) -> dict[str, Any] | None:
|
|
20
|
-
"""Get a JSON dict by key."""
|
|
21
|
-
...
|
|
22
|
-
|
|
23
|
-
async def set(self, key: str, value: dict[str, Any]) -> None:
|
|
24
|
-
"""Store a JSON dict by key."""
|
|
25
|
-
...
|
|
26
|
-
|
|
27
|
-
async def delete(self, key: str) -> None:
|
|
28
|
-
"""Delete a value by key."""
|
|
29
|
-
...
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class JSONFileStorage:
|
|
33
|
-
"""File-based key-value storage for JSON data with automatic metadata tracking.
|
|
34
|
-
|
|
35
|
-
Each key-value pair is stored as a separate JSON file on disk.
|
|
36
|
-
Keys are sanitized to be filesystem-safe.
|
|
37
|
-
|
|
38
|
-
The storage automatically wraps all data with metadata:
|
|
39
|
-
- timestamp: Timestamp when the entry was last written
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
cache_dir: Directory for storing JSON files
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
def __init__(self, cache_dir: Path):
|
|
46
|
-
"""Initialize JSON file storage."""
|
|
47
|
-
self.cache_dir = cache_dir
|
|
48
|
-
self.cache_dir.mkdir(exist_ok=True, parents=True)
|
|
49
|
-
|
|
50
|
-
def _get_safe_key(self, key: str) -> str:
|
|
51
|
-
"""Convert key to filesystem-safe string."""
|
|
52
|
-
safe_key = key
|
|
53
|
-
|
|
54
|
-
# Replace problematic characters with underscores
|
|
55
|
-
for char in [".", "/", "\\", ":", "*", "?", '"', "<", ">", "|", " "]:
|
|
56
|
-
safe_key = safe_key.replace(char, "_")
|
|
57
|
-
|
|
58
|
-
# Compress multiple underscores into one
|
|
59
|
-
while "__" in safe_key:
|
|
60
|
-
safe_key = safe_key.replace("__", "_")
|
|
61
|
-
|
|
62
|
-
# Strip leading and trailing underscores
|
|
63
|
-
safe_key = safe_key.strip("_")
|
|
64
|
-
|
|
65
|
-
return safe_key
|
|
66
|
-
|
|
67
|
-
def _get_file_path(self, key: str) -> Path:
|
|
68
|
-
"""Get the file path for a given key."""
|
|
69
|
-
safe_key = self._get_safe_key(key)
|
|
70
|
-
return self.cache_dir / f"{safe_key}.json"
|
|
71
|
-
|
|
72
|
-
async def get(self, key: str) -> dict[str, Any] | None:
|
|
73
|
-
"""Get a JSON dict from storage by key.
|
|
74
|
-
|
|
75
|
-
Args:
|
|
76
|
-
key: The key to retrieve
|
|
77
|
-
|
|
78
|
-
Returns:
|
|
79
|
-
The stored dict or None if not found
|
|
80
|
-
"""
|
|
81
|
-
path = self._get_file_path(key)
|
|
82
|
-
try:
|
|
83
|
-
wrapper = json.loads(path.read_text())
|
|
84
|
-
|
|
85
|
-
# Expect wrapped format with metadata
|
|
86
|
-
if not isinstance(wrapper, dict) or "data" not in wrapper:
|
|
87
|
-
logger.warning(f"Invalid storage format for key '{key}'")
|
|
88
|
-
return None
|
|
89
|
-
|
|
90
|
-
logger.debug(f"Loaded data for key '{key}'")
|
|
91
|
-
return wrapper["data"]
|
|
92
|
-
|
|
93
|
-
except FileNotFoundError:
|
|
94
|
-
logger.debug(f"No data found for key '{key}'")
|
|
95
|
-
return None
|
|
96
|
-
except json.JSONDecodeError as e:
|
|
97
|
-
logger.warning(f"Failed to load data for key '{key}': {e}")
|
|
98
|
-
return None
|
|
99
|
-
|
|
100
|
-
async def set(self, key: str, value: dict[str, Any]) -> None:
|
|
101
|
-
"""Store a JSON dict with metadata.
|
|
102
|
-
|
|
103
|
-
Args:
|
|
104
|
-
key: The key to store under
|
|
105
|
-
value: The dict to store
|
|
106
|
-
"""
|
|
107
|
-
import time
|
|
108
|
-
|
|
109
|
-
path = self._get_file_path(key)
|
|
110
|
-
current_time = time.time()
|
|
111
|
-
|
|
112
|
-
# Create wrapper with metadata
|
|
113
|
-
wrapper = {
|
|
114
|
-
"data": value,
|
|
115
|
-
"timestamp": current_time,
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
# Use pydantic_core for consistent JSON serialization
|
|
119
|
-
json_data = pydantic_core.to_json(wrapper, fallback=str)
|
|
120
|
-
path.write_bytes(json_data)
|
|
121
|
-
logger.debug(f"Saved data for key '{key}'")
|
|
122
|
-
|
|
123
|
-
async def delete(self, key: str) -> None:
|
|
124
|
-
"""Delete a value from storage.
|
|
125
|
-
|
|
126
|
-
Args:
|
|
127
|
-
key: The key to delete
|
|
128
|
-
"""
|
|
129
|
-
path = self._get_file_path(key)
|
|
130
|
-
if path.exists():
|
|
131
|
-
path.unlink()
|
|
132
|
-
logger.debug(f"Deleted data for key '{key}'")
|
|
133
|
-
|
|
134
|
-
async def cleanup_old_entries(
|
|
135
|
-
self,
|
|
136
|
-
max_age_seconds: int = 30 * 24 * 60 * 60, # 30 days default
|
|
137
|
-
) -> int:
|
|
138
|
-
"""Remove entries older than the specified age.
|
|
139
|
-
|
|
140
|
-
Uses the timestamp field to determine age.
|
|
141
|
-
|
|
142
|
-
Args:
|
|
143
|
-
max_age_seconds: Maximum age in seconds (default 30 days)
|
|
144
|
-
|
|
145
|
-
Returns:
|
|
146
|
-
Number of entries removed
|
|
147
|
-
"""
|
|
148
|
-
import time
|
|
149
|
-
|
|
150
|
-
current_time = time.time()
|
|
151
|
-
removed_count = 0
|
|
152
|
-
|
|
153
|
-
for json_file in self.cache_dir.glob("*.json"):
|
|
154
|
-
try:
|
|
155
|
-
# Read the file and check timestamp
|
|
156
|
-
wrapper = json.loads(json_file.read_text())
|
|
157
|
-
|
|
158
|
-
# Check wrapped format
|
|
159
|
-
if not isinstance(wrapper, dict) or "data" not in wrapper:
|
|
160
|
-
continue # Invalid format, skip
|
|
161
|
-
|
|
162
|
-
if "timestamp" not in wrapper:
|
|
163
|
-
continue # No timestamp field, skip
|
|
164
|
-
|
|
165
|
-
entry_age = current_time - wrapper["timestamp"]
|
|
166
|
-
if entry_age > max_age_seconds:
|
|
167
|
-
json_file.unlink()
|
|
168
|
-
removed_count += 1
|
|
169
|
-
logger.debug(
|
|
170
|
-
f"Removed old entry '{json_file.stem}' (age: {entry_age:.0f}s)"
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
except (json.JSONDecodeError, KeyError) as e:
|
|
174
|
-
logger.debug(f"Error reading {json_file.name}: {e}")
|
|
175
|
-
continue
|
|
176
|
-
|
|
177
|
-
if removed_count > 0:
|
|
178
|
-
logger.info(f"Cleaned up {removed_count} old entries from storage")
|
|
179
|
-
|
|
180
|
-
return removed_count
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
class InMemoryStorage:
|
|
184
|
-
"""In-memory key-value storage for JSON data.
|
|
185
|
-
|
|
186
|
-
Simple dict-based storage that doesn't persist across restarts.
|
|
187
|
-
Useful for testing or environments where file storage isn't available.
|
|
188
|
-
"""
|
|
189
|
-
|
|
190
|
-
def __init__(self):
|
|
191
|
-
"""Initialize in-memory storage."""
|
|
192
|
-
self._data: dict[str, dict[str, Any]] = {}
|
|
193
|
-
|
|
194
|
-
async def get(self, key: str) -> dict[str, Any] | None:
|
|
195
|
-
"""Get a JSON dict from memory by key."""
|
|
196
|
-
return self._data.get(key)
|
|
197
|
-
|
|
198
|
-
async def set(self, key: str, value: dict[str, Any]) -> None:
|
|
199
|
-
"""Store a JSON dict in memory."""
|
|
200
|
-
self._data[key] = value
|
|
201
|
-
|
|
202
|
-
async def delete(self, key: str) -> None:
|
|
203
|
-
"""Delete a value from memory."""
|
|
204
|
-
self._data.pop(key, None)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|