fastmcp 2.12.5__py3-none-any.whl → 2.14.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.
Files changed (133) hide show
  1. fastmcp/__init__.py +2 -23
  2. fastmcp/cli/__init__.py +0 -3
  3. fastmcp/cli/__main__.py +5 -0
  4. fastmcp/cli/cli.py +19 -33
  5. fastmcp/cli/install/claude_code.py +6 -6
  6. fastmcp/cli/install/claude_desktop.py +3 -3
  7. fastmcp/cli/install/cursor.py +18 -12
  8. fastmcp/cli/install/gemini_cli.py +3 -3
  9. fastmcp/cli/install/mcp_json.py +3 -3
  10. fastmcp/cli/install/shared.py +0 -15
  11. fastmcp/cli/run.py +13 -8
  12. fastmcp/cli/tasks.py +110 -0
  13. fastmcp/client/__init__.py +9 -9
  14. fastmcp/client/auth/oauth.py +123 -225
  15. fastmcp/client/client.py +697 -95
  16. fastmcp/client/elicitation.py +11 -5
  17. fastmcp/client/logging.py +18 -14
  18. fastmcp/client/messages.py +7 -5
  19. fastmcp/client/oauth_callback.py +85 -171
  20. fastmcp/client/roots.py +2 -1
  21. fastmcp/client/sampling.py +1 -1
  22. fastmcp/client/tasks.py +614 -0
  23. fastmcp/client/transports.py +117 -30
  24. fastmcp/contrib/component_manager/__init__.py +1 -1
  25. fastmcp/contrib/component_manager/component_manager.py +2 -2
  26. fastmcp/contrib/component_manager/component_service.py +10 -26
  27. fastmcp/contrib/mcp_mixin/README.md +32 -1
  28. fastmcp/contrib/mcp_mixin/__init__.py +2 -2
  29. fastmcp/contrib/mcp_mixin/mcp_mixin.py +14 -2
  30. fastmcp/dependencies.py +25 -0
  31. fastmcp/experimental/sampling/handlers/openai.py +3 -3
  32. fastmcp/experimental/server/openapi/__init__.py +20 -21
  33. fastmcp/experimental/utilities/openapi/__init__.py +16 -47
  34. fastmcp/mcp_config.py +3 -4
  35. fastmcp/prompts/__init__.py +1 -1
  36. fastmcp/prompts/prompt.py +54 -51
  37. fastmcp/prompts/prompt_manager.py +16 -101
  38. fastmcp/resources/__init__.py +5 -5
  39. fastmcp/resources/resource.py +43 -21
  40. fastmcp/resources/resource_manager.py +9 -168
  41. fastmcp/resources/template.py +161 -61
  42. fastmcp/resources/types.py +30 -24
  43. fastmcp/server/__init__.py +1 -1
  44. fastmcp/server/auth/__init__.py +9 -14
  45. fastmcp/server/auth/auth.py +197 -46
  46. fastmcp/server/auth/handlers/authorize.py +326 -0
  47. fastmcp/server/auth/jwt_issuer.py +236 -0
  48. fastmcp/server/auth/middleware.py +96 -0
  49. fastmcp/server/auth/oauth_proxy.py +1469 -298
  50. fastmcp/server/auth/oidc_proxy.py +91 -20
  51. fastmcp/server/auth/providers/auth0.py +40 -21
  52. fastmcp/server/auth/providers/aws.py +29 -3
  53. fastmcp/server/auth/providers/azure.py +312 -131
  54. fastmcp/server/auth/providers/debug.py +114 -0
  55. fastmcp/server/auth/providers/descope.py +86 -29
  56. fastmcp/server/auth/providers/discord.py +308 -0
  57. fastmcp/server/auth/providers/github.py +29 -8
  58. fastmcp/server/auth/providers/google.py +48 -9
  59. fastmcp/server/auth/providers/in_memory.py +29 -5
  60. fastmcp/server/auth/providers/introspection.py +281 -0
  61. fastmcp/server/auth/providers/jwt.py +48 -31
  62. fastmcp/server/auth/providers/oci.py +233 -0
  63. fastmcp/server/auth/providers/scalekit.py +238 -0
  64. fastmcp/server/auth/providers/supabase.py +188 -0
  65. fastmcp/server/auth/providers/workos.py +35 -17
  66. fastmcp/server/context.py +236 -116
  67. fastmcp/server/dependencies.py +503 -18
  68. fastmcp/server/elicitation.py +286 -48
  69. fastmcp/server/event_store.py +177 -0
  70. fastmcp/server/http.py +71 -20
  71. fastmcp/server/low_level.py +165 -2
  72. fastmcp/server/middleware/__init__.py +1 -1
  73. fastmcp/server/middleware/caching.py +476 -0
  74. fastmcp/server/middleware/error_handling.py +14 -10
  75. fastmcp/server/middleware/logging.py +50 -39
  76. fastmcp/server/middleware/middleware.py +29 -16
  77. fastmcp/server/middleware/rate_limiting.py +3 -3
  78. fastmcp/server/middleware/tool_injection.py +116 -0
  79. fastmcp/server/openapi/__init__.py +35 -0
  80. fastmcp/{experimental/server → server}/openapi/components.py +15 -10
  81. fastmcp/{experimental/server → server}/openapi/routing.py +3 -3
  82. fastmcp/{experimental/server → server}/openapi/server.py +6 -5
  83. fastmcp/server/proxy.py +72 -48
  84. fastmcp/server/server.py +1415 -733
  85. fastmcp/server/tasks/__init__.py +21 -0
  86. fastmcp/server/tasks/capabilities.py +22 -0
  87. fastmcp/server/tasks/config.py +89 -0
  88. fastmcp/server/tasks/converters.py +205 -0
  89. fastmcp/server/tasks/handlers.py +356 -0
  90. fastmcp/server/tasks/keys.py +93 -0
  91. fastmcp/server/tasks/protocol.py +355 -0
  92. fastmcp/server/tasks/subscriptions.py +205 -0
  93. fastmcp/settings.py +125 -113
  94. fastmcp/tools/__init__.py +1 -1
  95. fastmcp/tools/tool.py +138 -55
  96. fastmcp/tools/tool_manager.py +30 -112
  97. fastmcp/tools/tool_transform.py +12 -21
  98. fastmcp/utilities/cli.py +67 -28
  99. fastmcp/utilities/components.py +10 -5
  100. fastmcp/utilities/inspect.py +79 -23
  101. fastmcp/utilities/json_schema.py +4 -4
  102. fastmcp/utilities/json_schema_type.py +8 -8
  103. fastmcp/utilities/logging.py +118 -8
  104. fastmcp/utilities/mcp_config.py +1 -2
  105. fastmcp/utilities/mcp_server_config/__init__.py +3 -3
  106. fastmcp/utilities/mcp_server_config/v1/environments/base.py +1 -2
  107. fastmcp/utilities/mcp_server_config/v1/environments/uv.py +6 -6
  108. fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +5 -5
  109. fastmcp/utilities/mcp_server_config/v1/schema.json +3 -0
  110. fastmcp/utilities/mcp_server_config/v1/sources/base.py +0 -1
  111. fastmcp/{experimental/utilities → utilities}/openapi/README.md +7 -35
  112. fastmcp/utilities/openapi/__init__.py +63 -0
  113. fastmcp/{experimental/utilities → utilities}/openapi/director.py +14 -15
  114. fastmcp/{experimental/utilities → utilities}/openapi/formatters.py +5 -5
  115. fastmcp/{experimental/utilities → utilities}/openapi/json_schema_converter.py +7 -3
  116. fastmcp/{experimental/utilities → utilities}/openapi/parser.py +37 -16
  117. fastmcp/utilities/tests.py +92 -5
  118. fastmcp/utilities/types.py +86 -16
  119. fastmcp/utilities/ui.py +626 -0
  120. {fastmcp-2.12.5.dist-info → fastmcp-2.14.0.dist-info}/METADATA +24 -15
  121. fastmcp-2.14.0.dist-info/RECORD +156 -0
  122. {fastmcp-2.12.5.dist-info → fastmcp-2.14.0.dist-info}/WHEEL +1 -1
  123. fastmcp/cli/claude.py +0 -135
  124. fastmcp/server/auth/providers/bearer.py +0 -25
  125. fastmcp/server/openapi.py +0 -1083
  126. fastmcp/utilities/openapi.py +0 -1568
  127. fastmcp/utilities/storage.py +0 -204
  128. fastmcp-2.12.5.dist-info/RECORD +0 -134
  129. fastmcp/{experimental/server → server}/openapi/README.md +0 -0
  130. fastmcp/{experimental/utilities → utilities}/openapi/models.py +3 -3
  131. fastmcp/{experimental/utilities → utilities}/openapi/schemas.py +2 -2
  132. {fastmcp-2.12.5.dist-info → fastmcp-2.14.0.dist-info}/entry_points.txt +0 -0
  133. {fastmcp-2.12.5.dist-info → fastmcp-2.14.0.dist-info}/licenses/LICENSE +0 -0
fastmcp/server/proxy.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- import warnings
5
4
  from collections.abc import Awaitable, Callable
6
5
  from pathlib import Path
7
6
  from typing import TYPE_CHECKING, Any, cast
@@ -15,12 +14,12 @@ from mcp.shared.exceptions import McpError
15
14
  from mcp.types import (
16
15
  METHOD_NOT_FOUND,
17
16
  BlobResourceContents,
17
+ ElicitRequestFormParams,
18
18
  GetPromptResult,
19
19
  TextResourceContents,
20
20
  )
21
21
  from pydantic.networks import AnyUrl
22
22
 
23
- import fastmcp
24
23
  from fastmcp.client.client import Client, FastMCP1Server
25
24
  from fastmcp.client.elicitation import ElicitResult
26
25
  from fastmcp.client.logging import LogMessage
@@ -36,6 +35,7 @@ from fastmcp.resources.resource_manager import ResourceManager
36
35
  from fastmcp.server.context import Context
37
36
  from fastmcp.server.dependencies import get_context
38
37
  from fastmcp.server.server import FastMCP
38
+ from fastmcp.server.tasks.config import TaskConfig
39
39
  from fastmcp.tools.tool import Tool, ToolResult
40
40
  from fastmcp.tools.tool_manager import ToolManager
41
41
  from fastmcp.tools.tool_transform import (
@@ -69,7 +69,7 @@ class ProxyManagerMixin:
69
69
  class ProxyToolManager(ToolManager, ProxyManagerMixin):
70
70
  """A ToolManager that sources its tools from a remote client in addition to local and mounted tools."""
71
71
 
72
- def __init__(self, client_factory: ClientFactoryT, **kwargs):
72
+ def __init__(self, client_factory: ClientFactoryT, **kwargs: Any):
73
73
  super().__init__(**kwargs)
74
74
  self.client_factory = client_factory
75
75
 
@@ -117,13 +117,14 @@ class ProxyToolManager(ToolManager, ProxyManagerMixin):
117
117
  return ToolResult(
118
118
  content=result.content,
119
119
  structured_content=result.structured_content,
120
+ meta=result.meta,
120
121
  )
121
122
 
122
123
 
123
124
  class ProxyResourceManager(ResourceManager, ProxyManagerMixin):
124
125
  """A ResourceManager that sources its resources from a remote client in addition to local and mounted resources."""
125
126
 
126
- def __init__(self, client_factory: ClientFactoryT, **kwargs):
127
+ def __init__(self, client_factory: ClientFactoryT, **kwargs: Any):
127
128
  super().__init__(**kwargs)
128
129
  self.client_factory = client_factory
129
130
 
@@ -198,13 +199,15 @@ class ProxyResourceManager(ResourceManager, ProxyManagerMixin):
198
199
  elif isinstance(result[0], BlobResourceContents):
199
200
  return result[0].blob
200
201
  else:
201
- raise ResourceError(f"Unsupported content type: {type(result[0])}")
202
+ raise ResourceError(
203
+ f"Unsupported content type: {type(result[0])}"
204
+ ) from None
202
205
 
203
206
 
204
207
  class ProxyPromptManager(PromptManager, ProxyManagerMixin):
205
208
  """A PromptManager that sources its prompts from a remote client in addition to local and mounted prompts."""
206
209
 
207
- def __init__(self, client_factory: ClientFactoryT, **kwargs):
210
+ def __init__(self, client_factory: ClientFactoryT, **kwargs: Any):
208
211
  super().__init__(**kwargs)
209
212
  self.client_factory = client_factory
210
213
 
@@ -258,7 +261,9 @@ class ProxyTool(Tool, MirroredComponent):
258
261
  A Tool that represents and executes a tool on a remote server.
259
262
  """
260
263
 
261
- def __init__(self, client: Client, **kwargs):
264
+ task_config: TaskConfig = TaskConfig(mode="forbidden")
265
+
266
+ def __init__(self, client: Client, **kwargs: Any):
262
267
  super().__init__(**kwargs)
263
268
  self._client = client
264
269
 
@@ -268,10 +273,12 @@ class ProxyTool(Tool, MirroredComponent):
268
273
  return cls(
269
274
  client=client,
270
275
  name=mcp_tool.name,
276
+ title=mcp_tool.title,
271
277
  description=mcp_tool.description,
272
278
  parameters=mcp_tool.inputSchema,
273
279
  annotations=mcp_tool.annotations,
274
280
  output_schema=mcp_tool.outputSchema,
281
+ icons=mcp_tool.icons,
275
282
  meta=mcp_tool.meta,
276
283
  tags=(mcp_tool.meta or {}).get("_fastmcp", {}).get("tags", []),
277
284
  _mirrored=True,
@@ -284,15 +291,37 @@ class ProxyTool(Tool, MirroredComponent):
284
291
  ) -> ToolResult:
285
292
  """Executes the tool by making a call through the client."""
286
293
  async with self._client:
294
+ context = get_context()
295
+ # Build meta dict from request context
296
+ meta: dict[str, Any] | None = None
297
+ if hasattr(context, "request_context"):
298
+ req_ctx = context.request_context
299
+ # Start with existing meta if present
300
+ if hasattr(req_ctx, "meta") and req_ctx.meta:
301
+ meta = dict(req_ctx.meta)
302
+ # Add task metadata if this is a task request
303
+ if (
304
+ hasattr(req_ctx, "experimental")
305
+ and hasattr(req_ctx.experimental, "is_task")
306
+ and req_ctx.experimental.is_task
307
+ ):
308
+ task_metadata = req_ctx.experimental.task_metadata
309
+ if task_metadata:
310
+ meta = meta or {}
311
+ meta["modelcontextprotocol.io/task"] = task_metadata.model_dump(
312
+ exclude_none=True
313
+ )
314
+
287
315
  result = await self._client.call_tool_mcp(
288
- name=self.name,
289
- arguments=arguments,
316
+ name=self.name, arguments=arguments, meta=meta
290
317
  )
291
318
  if result.isError:
292
319
  raise ToolError(cast(mcp.types.TextContent, result.content[0]).text)
320
+ # Preserve backend's meta (includes task metadata for background tasks)
293
321
  return ToolResult(
294
322
  content=result.content,
295
323
  structured_content=result.structuredContent,
324
+ meta=result.meta,
296
325
  )
297
326
 
298
327
 
@@ -301,6 +330,7 @@ class ProxyResource(Resource, MirroredComponent):
301
330
  A Resource that represents and reads a resource from a remote server.
302
331
  """
303
332
 
333
+ task_config: TaskConfig = TaskConfig(mode="forbidden")
304
334
  _client: Client
305
335
  _value: str | bytes | None = None
306
336
 
@@ -327,10 +357,13 @@ class ProxyResource(Resource, MirroredComponent):
327
357
  client=client,
328
358
  uri=mcp_resource.uri,
329
359
  name=mcp_resource.name,
360
+ title=mcp_resource.title,
330
361
  description=mcp_resource.description,
331
362
  mime_type=mcp_resource.mimeType or "text/plain",
363
+ icons=mcp_resource.icons,
332
364
  meta=mcp_resource.meta,
333
365
  tags=(mcp_resource.meta or {}).get("_fastmcp", {}).get("tags", []),
366
+ task_config=TaskConfig(mode="forbidden"),
334
367
  _mirrored=True,
335
368
  )
336
369
 
@@ -354,12 +387,14 @@ class ProxyTemplate(ResourceTemplate, MirroredComponent):
354
387
  A ResourceTemplate that represents and creates resources from a remote server template.
355
388
  """
356
389
 
357
- def __init__(self, client: Client, **kwargs):
390
+ task_config: TaskConfig = TaskConfig(mode="forbidden")
391
+
392
+ def __init__(self, client: Client, **kwargs: Any):
358
393
  super().__init__(**kwargs)
359
394
  self._client = client
360
395
 
361
396
  @classmethod
362
- def from_mcp_template(
397
+ def from_mcp_template( # type: ignore[override]
363
398
  cls, client: Client, mcp_template: mcp.types.ResourceTemplate
364
399
  ) -> ProxyTemplate:
365
400
  """Factory method to create a ProxyTemplate from a raw MCP template schema."""
@@ -367,11 +402,14 @@ class ProxyTemplate(ResourceTemplate, MirroredComponent):
367
402
  client=client,
368
403
  uri_template=mcp_template.uriTemplate,
369
404
  name=mcp_template.name,
405
+ title=mcp_template.title,
370
406
  description=mcp_template.description,
371
407
  mime_type=mcp_template.mimeType or "text/plain",
408
+ icons=mcp_template.icons,
372
409
  parameters={}, # Remote templates don't have local parameters
373
410
  meta=mcp_template.meta,
374
411
  tags=(mcp_template.meta or {}).get("_fastmcp", {}).get("tags", []),
412
+ task_config=TaskConfig(mode="forbidden"),
375
413
  _mirrored=True,
376
414
  )
377
415
 
@@ -402,8 +440,10 @@ class ProxyTemplate(ResourceTemplate, MirroredComponent):
402
440
  client=self._client,
403
441
  uri=parameterized_uri,
404
442
  name=self.name,
443
+ title=self.title,
405
444
  description=self.description,
406
445
  mime_type=result[0].mimeType,
446
+ icons=self.icons,
407
447
  meta=self.meta,
408
448
  tags=(self.meta or {}).get("_fastmcp", {}).get("tags", []),
409
449
  _value=value,
@@ -415,6 +455,7 @@ class ProxyPrompt(Prompt, MirroredComponent):
415
455
  A Prompt that represents and renders a prompt from a remote server.
416
456
  """
417
457
 
458
+ task_config: TaskConfig = TaskConfig(mode="forbidden")
418
459
  _client: Client
419
460
 
420
461
  def __init__(self, client: Client, **kwargs):
@@ -437,14 +478,17 @@ class ProxyPrompt(Prompt, MirroredComponent):
437
478
  return cls(
438
479
  client=client,
439
480
  name=mcp_prompt.name,
481
+ title=mcp_prompt.title,
440
482
  description=mcp_prompt.description,
441
483
  arguments=arguments,
484
+ icons=mcp_prompt.icons,
442
485
  meta=mcp_prompt.meta,
443
486
  tags=(mcp_prompt.meta or {}).get("_fastmcp", {}).get("tags", []),
487
+ task_config=TaskConfig(mode="forbidden"),
444
488
  _mirrored=True,
445
489
  )
446
490
 
447
- async def render(self, arguments: dict[str, Any]) -> list[PromptMessage]:
491
+ async def render(self, arguments: dict[str, Any]) -> list[PromptMessage]: # type: ignore[override]
448
492
  """Render the prompt by making a call through the client."""
449
493
  async with self._client:
450
494
  result = await self._client.get_prompt(self.name, arguments)
@@ -459,9 +503,8 @@ class FastMCPProxy(FastMCP):
459
503
 
460
504
  def __init__(
461
505
  self,
462
- client: Client | None = None,
463
506
  *,
464
- client_factory: ClientFactoryT | None = None,
507
+ client_factory: ClientFactoryT,
465
508
  **kwargs,
466
509
  ):
467
510
  """
@@ -471,9 +514,6 @@ class FastMCPProxy(FastMCP):
471
514
  Use FastMCP.as_proxy() for convenience with automatic session strategy.
472
515
 
473
516
  Args:
474
- client: [DEPRECATED] A Client instance. Use client_factory instead for explicit
475
- session management. When provided, a client_factory will be automatically
476
- created that provides session isolation for backwards compatibility.
477
517
  client_factory: A callable that returns a Client instance when called.
478
518
  This gives you full control over session creation and reuse.
479
519
  Can be either a synchronous or asynchronous function.
@@ -482,29 +522,7 @@ class FastMCPProxy(FastMCP):
482
522
 
483
523
  super().__init__(**kwargs)
484
524
 
485
- # Handle client and client_factory parameters
486
- if client is not None and client_factory is not None:
487
- raise ValueError("Cannot specify both 'client' and 'client_factory'")
488
-
489
- if client is not None:
490
- # Deprecated in 2.10.3
491
- if fastmcp.settings.deprecation_warnings:
492
- warnings.warn(
493
- "Passing 'client' to FastMCPProxy is deprecated. Use 'client_factory' instead for explicit session management. "
494
- "For automatic session strategy, use FastMCP.as_proxy().",
495
- DeprecationWarning,
496
- stacklevel=2,
497
- )
498
-
499
- # Create a factory that provides session isolation for backwards compatibility
500
- def deprecated_client_factory():
501
- return client.new()
502
-
503
- self.client_factory = deprecated_client_factory
504
- elif client_factory is not None:
505
- self.client_factory = client_factory
506
- else:
507
- raise ValueError("Must specify 'client_factory'")
525
+ self.client_factory = client_factory
508
526
 
509
527
  # Replace the default managers with our specialized proxy managers.
510
528
  self._tool_manager = ProxyToolManager(
@@ -537,7 +555,7 @@ class ProxyClient(Client[ClientTransportT]):
537
555
  def __init__(
538
556
  self,
539
557
  transport: ClientTransportT
540
- | FastMCP
558
+ | FastMCP[Any]
541
559
  | FastMCP1Server
542
560
  | AnyUrl
543
561
  | Path
@@ -558,7 +576,7 @@ class ProxyClient(Client[ClientTransportT]):
558
576
  kwargs["log_handler"] = ProxyClient.default_log_handler
559
577
  if "progress_handler" not in kwargs:
560
578
  kwargs["progress_handler"] = ProxyClient.default_progress_handler
561
- super().__init__(**kwargs | dict(transport=transport))
579
+ super().__init__(**kwargs | {"transport": transport})
562
580
 
563
581
  @classmethod
564
582
  async def default_sampling_handler(
@@ -572,7 +590,7 @@ class ProxyClient(Client[ClientTransportT]):
572
590
  """
573
591
  ctx = get_context()
574
592
  content = await ctx.sample(
575
- [msg for msg in messages],
593
+ list(messages),
576
594
  system_prompt=params.systemPrompt,
577
595
  temperature=params.temperature,
578
596
  max_tokens=params.maxTokens,
@@ -583,7 +601,8 @@ class ProxyClient(Client[ClientTransportT]):
583
601
  return mcp.types.CreateMessageResult(
584
602
  role="assistant",
585
603
  model="fastmcp-client",
586
- content=content,
604
+ # TODO(ty): remove when ty supports isinstance exclusion narrowing
605
+ content=content, # type: ignore[arg-type]
587
606
  )
588
607
 
589
608
  @classmethod
@@ -598,9 +617,15 @@ class ProxyClient(Client[ClientTransportT]):
598
617
  A handler that forwards the elicitation request from the remote server to the proxy's connected clients and relays the response back to the remote server.
599
618
  """
600
619
  ctx = get_context()
620
+ # requestedSchema only exists on ElicitRequestFormParams, not ElicitRequestURLParams
621
+ requested_schema = (
622
+ params.requestedSchema
623
+ if isinstance(params, ElicitRequestFormParams)
624
+ else {"type": "object", "properties": {}}
625
+ )
601
626
  result = await ctx.session.elicit(
602
627
  message=message,
603
- requestedSchema=params.requestedSchema,
628
+ requestedSchema=requested_schema,
604
629
  related_request_id=ctx.request_id,
605
630
  )
606
631
  return ElicitResult(action=result.action, content=result.content)
@@ -640,16 +665,15 @@ class StatefulProxyClient(ProxyClient[ClientTransportT]):
640
665
  Note that it is essential to ensure that the proxy server itself is also stateful.
641
666
  """
642
667
 
643
- def __init__(self, *args, **kwargs):
668
+ def __init__(self, *args: Any, **kwargs: Any):
644
669
  super().__init__(*args, **kwargs)
645
670
  self._caches: dict[ServerSession, Client[ClientTransportT]] = {}
646
671
 
647
- async def __aexit__(self, exc_type, exc_value, traceback) -> None:
672
+ async def __aexit__(self, exc_type, exc_value, traceback) -> None: # type: ignore[override]
648
673
  """
649
674
  The stateful proxy client will be forced disconnected when the session is exited.
650
675
  So we do nothing here.
651
676
  """
652
- pass
653
677
 
654
678
  async def clear(self):
655
679
  """