Jeremiah Lowin commited on
Commit
b30e5c9
·
1 Parent(s): 3dd2080

Condense client kwargs

Browse files
.gitignore CHANGED
@@ -1,19 +1,62 @@
1
  # Python-generated files
2
  __pycache__/
3
- *.py[oc]
 
4
  build/
5
  dist/
6
  wheels/
7
- *.egg-info
 
 
 
 
 
 
 
 
 
8
 
9
  # Virtual environments
10
  .venv
11
- .DS_Store
 
 
12
  .env
13
 
 
 
14
 
 
15
  src/fastmcp/_version.py
16
 
17
- # editors
18
  .cursorrules
19
  .vscode/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # Python-generated files
2
  __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
  build/
6
  dist/
7
  wheels/
8
+ *.egg-info/
9
+ *.egg
10
+ MANIFEST
11
+ .pytest_cache/
12
+ .coverage
13
+ htmlcov/
14
+ .tox/
15
+ nosetests.xml
16
+ coverage.xml
17
+ *.cover
18
 
19
  # Virtual environments
20
  .venv
21
+ venv/
22
+ env/
23
+ ENV/
24
  .env
25
 
26
+ # System files
27
+ .DS_Store
28
 
29
+ # Version file
30
  src/fastmcp/_version.py
31
 
32
+ # Editors and IDEs
33
  .cursorrules
34
  .vscode/
35
+ .idea/
36
+ *.swp
37
+ *.swo
38
+ *~
39
+ .project
40
+ .pydevproject
41
+ .settings/
42
+
43
+ # Jupyter Notebook
44
+ .ipynb_checkpoints
45
+
46
+ # Type checking
47
+ .mypy_cache/
48
+ .dmypy.json
49
+ dmypy.json
50
+ .pyre/
51
+ .pytype/
52
+
53
+ # Local development
54
+ .python-version
55
+ .envrc
56
+ .direnv/
57
+
58
+ # Logs and databases
59
+ *.log
60
+ *.sqlite
61
+ *.db
62
+ *.ddb
src/fastmcp/client/base.py CHANGED
@@ -1,7 +1,7 @@
1
  import abc
2
  import contextlib
3
  import datetime
4
- from typing import Any, AsyncContextManager, Optional
5
 
6
  import mcp.types
7
  from mcp import ClientSession
@@ -19,6 +19,23 @@ def _get_roots_callback(roots: list[mcp.types.Root]) -> ListRootsFnT | None:
19
  return _roots_callback
20
 
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  class BaseClient(abc.ABC):
23
  def __init__(
24
  self,
@@ -48,6 +65,15 @@ class BaseClient(abc.ABC):
48
  self._message_handler = message_handler
49
  self._read_timeout_seconds = read_timeout_seconds
50
 
 
 
 
 
 
 
 
 
 
51
  @property
52
  def transport(self):
53
  """Get the current transport connection"""
@@ -71,13 +97,7 @@ class BaseClient(abc.ABC):
71
  return self._session is not None
72
 
73
  @abc.abstractmethod
74
- def _connect(
75
- self,
76
- sampling_callback: SamplingFnT | None = None,
77
- list_roots_callback: ListRootsFnT | None = None,
78
- logging_callback: LoggingFnT | None = None,
79
- message_handler: MessageHandlerFnT | None = None,
80
- ) -> AsyncContextManager:
81
  """Return an async context manager that handles connection lifecycle.
82
  This will be called by __aenter__ to establish the connection."""
83
  raise NotImplementedError("Subclasses must implement this method")
 
1
  import abc
2
  import contextlib
3
  import datetime
4
+ from typing import Any, AsyncContextManager, Optional, TypedDict
5
 
6
  import mcp.types
7
  from mcp import ClientSession
 
19
  return _roots_callback
20
 
21
 
22
+ class ClientKwargs(TypedDict, total=False):
23
+ roots: list[mcp.types.Root] | None
24
+ sampling_callback: SamplingFnT | None
25
+ list_roots_callback: ListRootsFnT | None
26
+ logging_callback: LoggingFnT | None
27
+ message_handler: MessageHandlerFnT | None
28
+ read_timeout_seconds: datetime.timedelta | None
29
+
30
+
31
+ class SessionKwargs(TypedDict, total=False):
32
+ sampling_callback: SamplingFnT | None
33
+ list_roots_callback: ListRootsFnT | None
34
+ logging_callback: LoggingFnT | None
35
+ message_handler: MessageHandlerFnT | None
36
+ read_timeout_seconds: datetime.timedelta | None
37
+
38
+
39
  class BaseClient(abc.ABC):
40
  def __init__(
41
  self,
 
65
  self._message_handler = message_handler
66
  self._read_timeout_seconds = read_timeout_seconds
67
 
68
+ def _session_kwargs(self) -> SessionKwargs:
69
+ return SessionKwargs(
70
+ sampling_callback=self._sampling_callback,
71
+ list_roots_callback=self._list_roots_callback,
72
+ logging_callback=self._logging_callback,
73
+ message_handler=self._message_handler,
74
+ read_timeout_seconds=self._read_timeout_seconds,
75
+ )
76
+
77
  @property
78
  def transport(self):
79
  """Get the current transport connection"""
 
97
  return self._session is not None
98
 
99
  @abc.abstractmethod
100
+ def _connect(self) -> AsyncContextManager:
 
 
 
 
 
 
101
  """Return an async context manager that handles connection lifecycle.
102
  This will be called by __aenter__ to establish the connection."""
103
  raise NotImplementedError("Subclasses must implement this method")
src/fastmcp/client/sse.py CHANGED
@@ -1,17 +1,10 @@
1
  import contextlib
2
- import datetime
3
 
4
- import mcp.types
5
  from mcp import ClientSession
6
  from mcp.client.sse import sse_client
 
7
 
8
- from fastmcp.client.base import (
9
- BaseClient,
10
- ListRootsFnT,
11
- LoggingFnT,
12
- MessageHandlerFnT,
13
- SamplingFnT,
14
- )
15
 
16
 
17
  class SSEClient(BaseClient):
@@ -19,21 +12,9 @@ class SSEClient(BaseClient):
19
  self,
20
  url: str,
21
  headers: dict[str, str] | None = None,
22
- roots: list[mcp.types.Root] | None = None,
23
- sampling_callback: SamplingFnT | None = None,
24
- list_roots_callback: ListRootsFnT | None = None,
25
- logging_callback: LoggingFnT | None = None,
26
- message_handler: MessageHandlerFnT | None = None,
27
- read_timeout_seconds: datetime.timedelta | None = None,
28
  ):
29
- super().__init__(
30
- roots=roots,
31
- sampling_callback=sampling_callback,
32
- list_roots_callback=list_roots_callback,
33
- logging_callback=logging_callback,
34
- message_handler=message_handler,
35
- read_timeout_seconds=read_timeout_seconds,
36
- )
37
  self.url = url
38
  self.headers = headers or {}
39
 
@@ -45,11 +26,7 @@ class SSEClient(BaseClient):
45
  async with ClientSession(
46
  read_stream=read_stream,
47
  write_stream=write_stream,
48
- sampling_callback=self._sampling_callback,
49
- list_roots_callback=self._list_roots_callback,
50
- logging_callback=self._logging_callback,
51
- message_handler=self._message_handler,
52
- read_timeout_seconds=self._read_timeout_seconds,
53
  ) as session:
54
  async with self._set_session(transport, session):
55
  yield self
 
1
  import contextlib
 
2
 
 
3
  from mcp import ClientSession
4
  from mcp.client.sse import sse_client
5
+ from typing_extensions import Unpack
6
 
7
+ from fastmcp.client.base import BaseClient, ClientKwargs
 
 
 
 
 
 
8
 
9
 
10
  class SSEClient(BaseClient):
 
12
  self,
13
  url: str,
14
  headers: dict[str, str] | None = None,
15
+ **kwargs: Unpack[ClientKwargs],
 
 
 
 
 
16
  ):
17
+ super().__init__(**kwargs)
 
 
 
 
 
 
 
18
  self.url = url
19
  self.headers = headers or {}
20
 
 
26
  async with ClientSession(
27
  read_stream=read_stream,
28
  write_stream=write_stream,
29
+ **self._session_kwargs(),
 
 
 
 
30
  ) as session:
31
  async with self._set_session(transport, session):
32
  yield self
src/fastmcp/client/stdio.py CHANGED
@@ -1,38 +1,19 @@
1
  import contextlib
2
- import datetime
3
 
4
- import mcp.types
5
  from mcp import ClientSession, StdioServerParameters
6
  from mcp.client.stdio import stdio_client
 
7
 
8
- from fastmcp.client.base import (
9
- BaseClient,
10
- ListRootsFnT,
11
- LoggingFnT,
12
- MessageHandlerFnT,
13
- SamplingFnT,
14
- )
15
 
16
 
17
  class StdioClient(BaseClient):
18
  def __init__(
19
  self,
20
  server_script_path: str,
21
- roots: list[mcp.types.Root] | None = None,
22
- sampling_callback: SamplingFnT | None = None,
23
- list_roots_callback: ListRootsFnT | None = None,
24
- logging_callback: LoggingFnT | None = None,
25
- message_handler: MessageHandlerFnT | None = None,
26
- read_timeout_seconds: datetime.timedelta | None = None,
27
  ):
28
- super().__init__(
29
- roots=roots,
30
- sampling_callback=sampling_callback,
31
- list_roots_callback=list_roots_callback,
32
- logging_callback=logging_callback,
33
- message_handler=message_handler,
34
- read_timeout_seconds=read_timeout_seconds,
35
- )
36
  self.server_script_path = server_script_path
37
 
38
  @contextlib.asynccontextmanager
@@ -54,11 +35,7 @@ class StdioClient(BaseClient):
54
  async with ClientSession(
55
  read_stream=stdio,
56
  write_stream=write,
57
- sampling_callback=self._sampling_callback,
58
- list_roots_callback=self._list_roots_callback,
59
- logging_callback=self._logging_callback,
60
- message_handler=self._message_handler,
61
- read_timeout_seconds=self._read_timeout_seconds,
62
  ) as session:
63
  async with self._set_session(transport, session):
64
  yield self
 
1
  import contextlib
 
2
 
 
3
  from mcp import ClientSession, StdioServerParameters
4
  from mcp.client.stdio import stdio_client
5
+ from typing_extensions import Unpack
6
 
7
+ from fastmcp.client.base import BaseClient, ClientKwargs
 
 
 
 
 
 
8
 
9
 
10
  class StdioClient(BaseClient):
11
  def __init__(
12
  self,
13
  server_script_path: str,
14
+ **kwargs: Unpack[ClientKwargs],
 
 
 
 
 
15
  ):
16
+ super().__init__(**kwargs)
 
 
 
 
 
 
 
17
  self.server_script_path = server_script_path
18
 
19
  @contextlib.asynccontextmanager
 
35
  async with ClientSession(
36
  read_stream=stdio,
37
  write_stream=write,
38
+ **self._session_kwargs(),
 
 
 
 
39
  ) as session:
40
  async with self._set_session(transport, session):
41
  yield self
src/fastmcp/client/websocket.py CHANGED
@@ -1,38 +1,19 @@
1
  import contextlib
2
- import datetime
3
 
4
- import mcp.types
5
  from mcp import ClientSession
6
  from mcp.client.websocket import websocket_client
 
7
 
8
- from fastmcp.client.base import (
9
- BaseClient,
10
- ListRootsFnT,
11
- LoggingFnT,
12
- MessageHandlerFnT,
13
- SamplingFnT,
14
- )
15
 
16
 
17
  class WebSocketClient(BaseClient):
18
  def __init__(
19
  self,
20
  url: str,
21
- roots: list[mcp.types.Root] | None = None,
22
- sampling_callback: SamplingFnT | None = None,
23
- list_roots_callback: ListRootsFnT | None = None,
24
- logging_callback: LoggingFnT | None = None,
25
- message_handler: MessageHandlerFnT | None = None,
26
- read_timeout_seconds: datetime.timedelta | None = None,
27
  ):
28
- super().__init__(
29
- roots=roots,
30
- sampling_callback=sampling_callback,
31
- list_roots_callback=list_roots_callback,
32
- logging_callback=logging_callback,
33
- message_handler=message_handler,
34
- read_timeout_seconds=read_timeout_seconds,
35
- )
36
  self.url = url
37
 
38
  @contextlib.asynccontextmanager
@@ -44,11 +25,7 @@ class WebSocketClient(BaseClient):
44
  async with ClientSession(
45
  read_stream=read_stream,
46
  write_stream=write_stream,
47
- sampling_callback=self._sampling_callback,
48
- list_roots_callback=self._list_roots_callback,
49
- logging_callback=self._logging_callback,
50
- message_handler=self._message_handler,
51
- read_timeout_seconds=self._read_timeout_seconds,
52
  ) as session:
53
  async with self._set_session(transport, session):
54
  yield self
 
1
  import contextlib
 
2
 
 
3
  from mcp import ClientSession
4
  from mcp.client.websocket import websocket_client
5
+ from typing_extensions import Unpack
6
 
7
+ from fastmcp.client.base import BaseClient, ClientKwargs
 
 
 
 
 
 
8
 
9
 
10
  class WebSocketClient(BaseClient):
11
  def __init__(
12
  self,
13
  url: str,
14
+ **kwargs: Unpack[ClientKwargs],
 
 
 
 
 
15
  ):
16
+ super().__init__(**kwargs)
 
 
 
 
 
 
 
17
  self.url = url
18
 
19
  @contextlib.asynccontextmanager
 
25
  async with ClientSession(
26
  read_stream=read_stream,
27
  write_stream=write_stream,
28
+ **self._session_kwargs(),
 
 
 
 
29
  ) as session:
30
  async with self._set_session(transport, session):
31
  yield self