fastmcp 0.1.0__py3-none-any.whl → 0.2.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/__init__.py CHANGED
@@ -1 +1,2 @@
1
- from .server import FastMCP
1
+ from .server import FastMCP
2
+ from .tools import Image
fastmcp/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1.0'
16
- __version_tuple__ = version_tuple = (0, 1, 0)
15
+ __version__ = version = '0.2.0'
16
+ __version_tuple__ = version_tuple = (0, 2, 0)
fastmcp/cli/claude.py CHANGED
@@ -28,7 +28,9 @@ def update_claude_config(
28
28
  file: Path,
29
29
  server_name: Optional[str] = None,
30
30
  *,
31
- uv_directory: Optional[Path] = None,
31
+ with_editable: Optional[Path] = None,
32
+ with_packages: Optional[list[str]] = None,
33
+ force: bool = False,
32
34
  ) -> bool:
33
35
  """Add the MCP server to Claude's configuration.
34
36
 
@@ -36,7 +38,9 @@ def update_claude_config(
36
38
  file: Path to the server file
37
39
  server_name: Optional custom name for the server. If not provided,
38
40
  defaults to the file stem
39
- uv_directory: Optional directory containing pyproject.toml
41
+ with_editable: Optional directory to install in editable mode
42
+ with_packages: Optional list of additional packages to install
43
+ force: If True, replace existing server with same name
40
44
  """
41
45
  config_dir = get_claude_config_path()
42
46
  if not config_dir:
@@ -54,17 +58,34 @@ def update_claude_config(
54
58
  # Use provided server_name or fall back to file stem
55
59
  name = server_name or file.stem
56
60
  if name in config["mcpServers"]:
57
- logger.warning(
58
- f"Server '{name}' already exists in Claude config",
61
+ if not force:
62
+ logger.warning(
63
+ f"Server '{name}' already exists in Claude config. "
64
+ "Use `--force` to replace.",
65
+ extra={"config_file": str(config_file)},
66
+ )
67
+ return False
68
+ logger.info(
69
+ f"Replacing existing server '{name}' in Claude config",
59
70
  extra={"config_file": str(config_file)},
60
71
  )
61
- return False
62
72
 
63
73
  # Build uv run command
64
- args = []
65
- if uv_directory:
66
- args.extend(["--directory", str(uv_directory)])
67
- args.extend(["run", str(file)])
74
+ args = ["run"]
75
+
76
+ if with_editable:
77
+ args.extend(["--with-editable", str(with_editable)])
78
+
79
+ # Always include fastmcp
80
+ args.extend(["--with", "fastmcp"])
81
+
82
+ # Add additional packages
83
+ if with_packages:
84
+ for pkg in with_packages:
85
+ if pkg:
86
+ args.extend(["--with", pkg])
87
+
88
+ args.append(str(file))
68
89
 
69
90
  config["mcpServers"][name] = {
70
91
  "command": "uv",
fastmcp/cli/cli.py CHANGED
@@ -25,15 +25,23 @@ app = typer.Typer(
25
25
 
26
26
  def _build_uv_command(
27
27
  file: Path,
28
- uv_directory: Optional[Path] = None,
28
+ with_editable: Optional[Path] = None,
29
+ with_packages: Optional[list[str]] = None,
29
30
  ) -> list[str]:
30
31
  """Build the uv run command."""
31
32
  cmd = ["uv"]
32
33
 
33
- if uv_directory:
34
- cmd.extend(["--directory", str(uv_directory)])
34
+ cmd.extend(["run", "--with", "fastmcp"])
35
35
 
36
- cmd.extend(["run", str(file)])
36
+ if with_editable:
37
+ cmd.extend(["--with-editable", str(with_editable)])
38
+
39
+ if with_packages:
40
+ for pkg in with_packages:
41
+ if pkg:
42
+ cmd.extend(["--with", pkg])
43
+
44
+ cmd.append(str(file))
37
45
  return cmd
38
46
 
39
47
 
@@ -137,17 +145,24 @@ def dev(
137
145
  ...,
138
146
  help="Python file to run, optionally with :object suffix",
139
147
  ),
140
- uv_directory: Annotated[
148
+ with_editable: Annotated[
141
149
  Optional[Path],
142
150
  typer.Option(
143
- "--uv-directory",
144
- "-d",
145
- help="Directory containing pyproject.toml (defaults to current directory)",
151
+ "--with-editable",
152
+ "-e",
153
+ help="Directory containing pyproject.toml to install in editable mode",
146
154
  exists=True,
147
155
  file_okay=False,
148
156
  resolve_path=True,
149
157
  ),
150
158
  ] = None,
159
+ with_packages: Annotated[
160
+ list[str],
161
+ typer.Option(
162
+ "--with",
163
+ help="Additional packages to install",
164
+ ),
165
+ ] = [],
151
166
  ) -> None:
152
167
  """Run a FastMCP server with the MCP Inspector."""
153
168
  file, server_object = _parse_file_path(file_spec)
@@ -157,12 +172,13 @@ def dev(
157
172
  extra={
158
173
  "file": str(file),
159
174
  "server_object": server_object,
160
- "uv_directory": str(uv_directory) if uv_directory else None,
175
+ "with_editable": str(with_editable) if with_editable else None,
176
+ "with_packages": with_packages,
161
177
  },
162
178
  )
163
179
 
164
180
  try:
165
- uv_cmd = _build_uv_command(file, uv_directory)
181
+ uv_cmd = _build_uv_command(file, with_editable, with_packages)
166
182
  # Run the MCP Inspector command
167
183
  process = subprocess.run(
168
184
  ["npx", "@modelcontextprotocol/inspector"] + uv_cmd,
@@ -201,12 +217,12 @@ def run(
201
217
  help="Transport protocol to use (stdio or sse)",
202
218
  ),
203
219
  ] = None,
204
- uv_directory: Annotated[
220
+ with_editable: Annotated[
205
221
  Optional[Path],
206
222
  typer.Option(
207
- "--uv-directory",
208
- "-d",
209
- help="Directory containing pyproject.toml (defaults to current directory)",
223
+ "--with-editable",
224
+ "-e",
225
+ help="Directory containing pyproject.toml to install in editable mode",
210
226
  exists=True,
211
227
  file_okay=False,
212
228
  resolve_path=True,
@@ -222,13 +238,11 @@ def run(
222
238
  "file": str(file),
223
239
  "server_object": server_object,
224
240
  "transport": transport,
225
- "uv_directory": str(uv_directory) if uv_directory else None,
241
+ "with_editable": str(with_editable) if with_editable else None,
226
242
  },
227
243
  )
228
244
 
229
245
  try:
230
- uv_cmd = _build_uv_command(file, uv_directory)
231
-
232
246
  # Import and get server object
233
247
  server = _import_server(file, server_object)
234
248
 
@@ -261,20 +275,35 @@ def install(
261
275
  typer.Option(
262
276
  "--name",
263
277
  "-n",
264
- help="Custom name for the server (defaults to file name)",
278
+ help="Custom name for the server (defaults to server's name attribute or file name)",
265
279
  ),
266
280
  ] = None,
267
- uv_directory: Annotated[
281
+ with_editable: Annotated[
268
282
  Optional[Path],
269
283
  typer.Option(
270
- "--uv-directory",
271
- "-d",
272
- help="Directory containing pyproject.toml (defaults to current directory)",
284
+ "--with-editable",
285
+ "-e",
286
+ help="Directory containing pyproject.toml to install in editable mode",
273
287
  exists=True,
274
288
  file_okay=False,
275
289
  resolve_path=True,
276
290
  ),
277
291
  ] = None,
292
+ with_packages: Annotated[
293
+ list[str],
294
+ typer.Option(
295
+ "--with",
296
+ help="Additional packages to install",
297
+ ),
298
+ ] = [],
299
+ force: Annotated[
300
+ bool,
301
+ typer.Option(
302
+ "--force",
303
+ "-f",
304
+ help="Replace existing server if one exists with the same name",
305
+ ),
306
+ ] = False,
278
307
  ) -> None:
279
308
  """Install a FastMCP server in the Claude desktop app."""
280
309
  file, server_object = _parse_file_path(file_spec)
@@ -285,7 +314,9 @@ def install(
285
314
  "file": str(file),
286
315
  "server_name": server_name,
287
316
  "server_object": server_object,
288
- "uv_directory": str(uv_directory) if uv_directory else None,
317
+ "with_editable": str(with_editable) if with_editable else None,
318
+ "with_packages": with_packages,
319
+ "force": force,
289
320
  },
290
321
  )
291
322
 
@@ -293,11 +324,28 @@ def install(
293
324
  logger.error("Claude app not found")
294
325
  sys.exit(1)
295
326
 
296
- if claude.update_claude_config(file, server_name, uv_directory=uv_directory):
297
- name = server_name or file.stem
327
+ # Try to import server to get its name, but fall back to file name if dependencies missing
328
+ name = server_name
329
+ if not name:
330
+ try:
331
+ server = _import_server(file, server_object)
332
+ name = server.name
333
+ except (ImportError, ModuleNotFoundError) as e:
334
+ logger.debug(
335
+ "Could not import server (likely missing dependencies), using file name",
336
+ extra={"error": str(e)},
337
+ )
338
+ name = file.stem
339
+
340
+ if claude.update_claude_config(
341
+ file,
342
+ name,
343
+ with_editable=with_editable,
344
+ with_packages=with_packages,
345
+ force=force,
346
+ ):
298
347
  print(f"Successfully installed {name} in Claude app")
299
348
  else:
300
- name = server_name or file.stem
301
349
  print(f"Failed to install {name} in Claude app")
302
350
  sys.exit(1)
303
351
 
fastmcp/resources.py CHANGED
@@ -16,12 +16,18 @@ logger = get_logger(__name__)
16
16
 
17
17
 
18
18
  class Resource(BaseModel):
19
- """Base class for all resources."""
19
+ """Base class for all resources.
20
+
21
+ Resources can contain either text (UTF-8 encoded) or binary data.
22
+ Text resources are suitable for source code, logs, JSON, etc.
23
+ Binary resources are suitable for images, PDFs, audio, etc.
24
+ """
20
25
 
21
26
  uri: _BaseUrl
22
27
  name: str
23
28
  description: Optional[str] = None
24
- mime_type: str = "text/plain"
29
+ mime_type: Optional[str] = None
30
+ is_binary: bool = False
25
31
 
26
32
  @field_validator("name", mode="before")
27
33
  @classmethod
@@ -36,15 +42,20 @@ class Resource(BaseModel):
36
42
  raise ValueError("Either name or uri must be provided")
37
43
 
38
44
  @abc.abstractmethod
39
- async def read(self) -> str:
40
- """Read the resource content."""
45
+ async def read(self) -> Union[str, bytes]:
46
+ """Read the resource content.
47
+
48
+ Returns:
49
+ Union[str, bytes]: Text content as str for text resources,
50
+ binary content as bytes for binary resources
51
+ """
41
52
  return ""
42
53
 
43
54
 
44
55
  class FunctionResource(Resource):
45
56
  """A resource that is generated by a function call.
46
57
 
47
- The function can be sync or async and must return a string
58
+ The function can be sync or async and must return a string, bytes,
48
59
  or another Resource.
49
60
  """
50
61
 
@@ -55,7 +66,7 @@ class FunctionResource(Resource):
55
66
  super().__init__(**data)
56
67
  self.is_async = asyncio.iscoroutinefunction(self.func)
57
68
 
58
- async def read(self) -> str:
69
+ async def read(self) -> Union[str, bytes]:
59
70
  """Read the resource content by calling the function."""
60
71
  try:
61
72
  result = (
@@ -67,7 +78,7 @@ class FunctionResource(Resource):
67
78
  if isinstance(result, Resource):
68
79
  return await result.read()
69
80
  if isinstance(result, bytes):
70
- return result.decode()
81
+ return result
71
82
  if not isinstance(result, str):
72
83
  try:
73
84
  return json.dumps(result, default=pydantic.json.pydantic_encoder)
@@ -91,9 +102,11 @@ class FileResource(Resource):
91
102
  raise ValueError(f"Path must be absolute: {path}")
92
103
  return path
93
104
 
94
- async def read(self) -> str:
105
+ async def read(self) -> Union[str, bytes]:
95
106
  """Read the file content."""
96
107
  try:
108
+ if self.is_binary:
109
+ return await asyncio.to_thread(self.path.read_bytes)
97
110
  return await asyncio.to_thread(self.path.read_text)
98
111
  except FileNotFoundError:
99
112
  raise FileNotFoundError(f"File not found: {self.path}")
@@ -109,13 +122,13 @@ class HttpResource(Resource):
109
122
  url: str
110
123
  headers: Optional[Dict[str, str]] = None
111
124
 
112
- async def read(self) -> str:
125
+ async def read(self) -> Union[str, bytes]:
113
126
  """Read the HTTP resource content."""
114
127
  try:
115
128
  async with httpx.AsyncClient() as client:
116
129
  response = await client.get(self.url, headers=self.headers)
117
130
  response.raise_for_status()
118
- return response.text
131
+ return response.content if self.is_binary else response.text
119
132
  except httpx.HTTPStatusError as e:
120
133
  raise ValueError(f"HTTP error {e.response.status_code}: {e}")
121
134
  except httpx.RequestError as e:
@@ -128,7 +141,7 @@ class DirectoryResource(Resource):
128
141
  path: Path
129
142
  recursive: bool = False
130
143
  pattern: Optional[str] = None
131
- mime_type: str = "application/json"
144
+ mime_type: Optional[str] = "application/json"
132
145
 
133
146
  @field_validator("path")
134
147
  @classmethod
@@ -160,7 +173,7 @@ class DirectoryResource(Resource):
160
173
  except Exception as e:
161
174
  raise ValueError(f"Error listing directory {self.path}: {e}")
162
175
 
163
- async def read(self) -> str:
176
+ async def read(self) -> str: # Always returns JSON string
164
177
  """Read the directory listing."""
165
178
  try:
166
179
  files = await asyncio.to_thread(self.list_files)
fastmcp/server.py CHANGED
@@ -1,22 +1,27 @@
1
1
  """FastMCP - A more ergonomic interface for MCP servers."""
2
2
 
3
3
  import asyncio
4
- import base64
5
4
  import functools
6
5
  import json
6
+ import logging
7
7
  from typing import Any, Callable, Optional, Sequence, Union, Literal
8
8
 
9
+ import pydantic.json
9
10
  from mcp.server import Server as MCPServer
10
11
  from mcp.server.stdio import stdio_server
11
12
  from mcp.server.sse import SseServerTransport
12
- from mcp.types import Resource as MCPResource
13
- from mcp.types import Tool, TextContent, ImageContent, EmbeddedResource
14
- from pydantic import BaseModel
13
+ from mcp.types import (
14
+ Resource as MCPResource,
15
+ Tool,
16
+ TextContent,
17
+ ImageContent,
18
+ )
15
19
  from pydantic_settings import BaseSettings
16
20
  from pydantic.networks import _BaseUrl
21
+
17
22
  from .exceptions import ResourceError
18
23
  from .resources import Resource, FunctionResource, ResourceManager
19
- from .tools import ToolManager
24
+ from .tools import ToolManager, Image
20
25
  from .utilities.logging import get_logger, configure_logging
21
26
 
22
27
  logger = get_logger(__name__)
@@ -33,7 +38,9 @@ class Settings(BaseSettings):
33
38
 
34
39
  # Server settings
35
40
  debug: bool = False
36
- log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO"
41
+ log_level: Literal[
42
+ logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL
43
+ ] = logging.INFO
37
44
 
38
45
  # HTTP settings
39
46
  host: str = "0.0.0.0"
@@ -73,12 +80,14 @@ class FastMCP:
73
80
  Args:
74
81
  transport: Transport protocol to use ("stdio" or "sse")
75
82
  """
83
+ TRANSPORTS = Literal["stdio", "sse"]
84
+ if transport not in TRANSPORTS.__args__: # type: ignore
85
+ raise ValueError(f"Unknown transport: {transport}")
86
+
76
87
  if transport == "stdio":
77
88
  asyncio.run(self.run_stdio_async())
78
- elif transport == "sse":
89
+ else: # transport == "sse"
79
90
  asyncio.run(self.run_sse_async())
80
- else:
81
- raise ValueError(f"Unknown transport: {transport}")
82
91
 
83
92
  def _setup_handlers(self) -> None:
84
93
  """Set up core MCP protocol handlers."""
@@ -101,13 +110,24 @@ class FastMCP:
101
110
 
102
111
  async def call_tool(
103
112
  self, name: str, arguments: dict
104
- ) -> Sequence[Union[TextContent, ImageContent, EmbeddedResource]]:
113
+ ) -> Sequence[Union[TextContent, ImageContent]]:
105
114
  """Call a tool by name with arguments."""
106
- result = await self._tool_manager.call_tool(name, arguments)
107
- return [self._convert_to_content(result)]
115
+ try:
116
+ result = await self._tool_manager.call_tool(name, arguments)
117
+ return self._convert_to_content(result)
118
+ except Exception as e:
119
+ logger.error(f"Error calling tool {name}: {e}")
120
+ return [
121
+ TextContent(
122
+ type="text",
123
+ text=str(e),
124
+ is_error=True,
125
+ )
126
+ ]
108
127
 
109
128
  async def list_resources(self) -> list[MCPResource]:
110
129
  """List all available resources."""
130
+
111
131
  resources = self._resource_manager.list_resources()
112
132
  return [
113
133
  MCPResource(
@@ -133,21 +153,48 @@ class FastMCP:
133
153
 
134
154
  def _convert_to_content(
135
155
  self, value: Any
136
- ) -> Union[TextContent, ImageContent, EmbeddedResource]:
137
- """Convert Python values to MCP content types."""
138
- if isinstance(value, (dict, list)):
139
- return TextContent(type="text", text=json.dumps(value, indent=2))
140
- if isinstance(value, str):
141
- return TextContent(type="text", text=value)
142
- if isinstance(value, bytes):
143
- return ImageContent(
144
- type="image",
145
- data=base64.b64encode(value).decode(),
146
- mimeType="application/octet-stream",
156
+ ) -> Sequence[Union[TextContent, ImageContent]]:
157
+ """Convert a tool result to MCP content types."""
158
+
159
+ # Already a sequence of valid content types
160
+ if isinstance(value, (list, tuple)):
161
+ if all(isinstance(x, (TextContent, ImageContent)) for x in value):
162
+ return value
163
+ # Handle mixed content including Image objects
164
+ result = []
165
+ for item in value:
166
+ if isinstance(item, (TextContent, ImageContent)):
167
+ result.append(item)
168
+ elif isinstance(item, Image):
169
+ result.append(item.to_image_content())
170
+ else:
171
+ result.append(
172
+ TextContent(
173
+ type="text",
174
+ text=json.dumps(
175
+ item, indent=2, default=pydantic.json.pydantic_encoder
176
+ ),
177
+ )
178
+ )
179
+ return result
180
+
181
+ # Single content type
182
+ if isinstance(value, (TextContent, ImageContent)):
183
+ return [value]
184
+
185
+ # Image helper
186
+ if isinstance(value, Image):
187
+ return [value.to_image_content()]
188
+
189
+ # All other types - convert to JSON string with pydantic encoder
190
+ return [
191
+ TextContent(
192
+ type="text",
193
+ text=json.dumps(
194
+ value, indent=2, default=pydantic.json.pydantic_encoder
195
+ ),
147
196
  )
148
- if isinstance(value, BaseModel):
149
- return TextContent(type="text", text=value.model_dump_json(indent=2))
150
- return TextContent(type="text", text=str(value))
197
+ ]
151
198
 
152
199
  def add_tool(
153
200
  self,
fastmcp/tools.py CHANGED
@@ -1,8 +1,11 @@
1
1
  """Tool management for FastMCP."""
2
2
 
3
+ import base64
3
4
  import inspect
4
- from typing import Any, Callable, Dict, Optional
5
+ from pathlib import Path
6
+ from typing import Any, Callable, Dict, Optional, Union
5
7
 
8
+ from mcp.types import ImageContent
6
9
  from pydantic import BaseModel, Field, TypeAdapter, validate_call
7
10
 
8
11
  from .exceptions import ToolError
@@ -11,6 +14,52 @@ from .utilities.logging import get_logger
11
14
  logger = get_logger(__name__)
12
15
 
13
16
 
17
+ class Image:
18
+ """Helper class for returning images from tools."""
19
+
20
+ def __init__(
21
+ self,
22
+ path: Optional[Union[str, Path]] = None,
23
+ data: Optional[bytes] = None,
24
+ format: Optional[str] = None,
25
+ ):
26
+ if path is None and data is None:
27
+ raise ValueError("Either path or data must be provided")
28
+ if path is not None and data is not None:
29
+ raise ValueError("Only one of path or data can be provided")
30
+
31
+ self.path = Path(path) if path else None
32
+ self.data = data
33
+ self._format = format
34
+ self._mime_type = self._get_mime_type()
35
+
36
+ def _get_mime_type(self) -> str:
37
+ """Get MIME type from format or guess from file extension."""
38
+ if self._format:
39
+ return f"image/{self._format.lower()}"
40
+
41
+ if self.path:
42
+ suffix = self.path.suffix.lower()
43
+ return {
44
+ ".png": "image/png",
45
+ ".jpg": "image/jpeg",
46
+ ".jpeg": "image/jpeg",
47
+ ".gif": "image/gif",
48
+ ".webp": "image/webp",
49
+ }.get(suffix, "application/octet-stream")
50
+ return "image/png" # default for raw binary data
51
+
52
+ def to_image_content(self) -> ImageContent:
53
+ """Convert to MCP ImageContent."""
54
+ if self.path:
55
+ with open(self.path, "rb") as f:
56
+ data = base64.b64encode(f.read()).decode()
57
+ else:
58
+ data = base64.b64encode(self.data).decode()
59
+
60
+ return ImageContent(type="image", data=data, mimeType=self._mime_type)
61
+
62
+
14
63
  class Tool(BaseModel):
15
64
  """Internal tool registration info."""
16
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastmcp
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: A more ergonomic interface for MCP servers
5
5
  Author: Jeremiah Lowin
6
6
  License: Apache-2.0
@@ -95,15 +95,37 @@ def calculate(x: int, y: int) -> int:
95
95
  FastMCP includes a development server with the MCP Inspector for testing your server:
96
96
 
97
97
  ```bash
98
+ # Basic usage
98
99
  fastmcp dev your_server.py
100
+
101
+ # Install package in editable mode from current directory
102
+ fastmcp dev your_server.py --with-editable .
103
+
104
+ # Install additional packages
105
+ fastmcp dev your_server.py --with pandas --with numpy
106
+
107
+ # Combine both
108
+ fastmcp dev your_server.py --with-editable . --with pandas --with numpy
99
109
  ```
100
110
 
111
+ The `--with` flag automatically includes `fastmcp` and any additional packages you specify. The `--with-editable` flag installs the package from the specified directory in editable mode, which is useful during development.
112
+
101
113
  ### Installing in Claude
102
114
 
103
115
  To use your server with Claude Desktop:
104
116
 
105
117
  ```bash
118
+ # Basic usage
106
119
  fastmcp install your_server.py --name "My Server"
120
+
121
+ # Install package in editable mode
122
+ fastmcp install your_server.py --with-editable .
123
+
124
+ # Install additional packages
125
+ fastmcp install your_server.py --with pandas --with numpy
126
+
127
+ # Combine options
128
+ fastmcp install your_server.py --with-editable . --with pandas --with numpy
107
129
  ```
108
130
 
109
131
 
@@ -0,0 +1,17 @@
1
+ fastmcp/__init__.py,sha256=3E3aQizHaMEwjxRUALigtM5J4lPTvaviMEr4hf975mY,53
2
+ fastmcp/_version.py,sha256=H-qsvrxCpdhaQzyddR-yajEqI71hPxLa4KxzpP3uS1g,411
3
+ fastmcp/app.py,sha256=RjtnF_4ApkIjxWfQlRmshb03icP6_nlNVV0LKnZGA5w,89
4
+ fastmcp/exceptions.py,sha256=K0rCgXsUVlws39hz98Tb4BBf_BzIql_zXFZgqbkNTiE,348
5
+ fastmcp/resources.py,sha256=efuEEnir4qCWp8qFrOyQW50sxACcLdKJpnuTZ99eYhM,7708
6
+ fastmcp/server.py,sha256=ufsuoUbfGhA5PnGjAlYgxtkv2WRBMwd74duHJ3m58E8,10519
7
+ fastmcp/tools.py,sha256=K4NspegydDmEvZyLHw56WyYBU9QHv9D8HsD4nHp_oYA,4858
8
+ fastmcp/cli/__init__.py,sha256=RUaBw4rNUJ7CjHrzVazB2jl60E6KA0Wo0x4OqHByL6c,68
9
+ fastmcp/cli/claude.py,sha256=rgJWxLPsdqV-UAQenafbAEREsyVuW_PFEyEsX92sHrg,3185
10
+ fastmcp/cli/cli.py,sha256=LP6wQ2CMwHURWN8UHq1aUFWN4JveiUr0Ap_dWT4raXI,9627
11
+ fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31
12
+ fastmcp/utilities/logging.py,sha256=t2w5bwtrkxHxioWSy5vY8esxLQxyxN8tfFZ1FI3Cb6E,704
13
+ fastmcp-0.2.0.dist-info/METADATA,sha256=PvjUvOjHjrSR3XyJhusgbnn-FXbp99lXXWqKSn43eKY,3730
14
+ fastmcp-0.2.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
15
+ fastmcp-0.2.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
16
+ fastmcp-0.2.0.dist-info/top_level.txt,sha256=9NvhdRmSJxxf5iTz58rYyea0DtTsKgvGQHMRZaa7NN4,8
17
+ fastmcp-0.2.0.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- fastmcp/__init__.py,sha256=r_Qr4WYOFDNF1SSkJY9c3L3ZasYVKB7_U7EM31D5yfE,27
2
- fastmcp/_version.py,sha256=IMl2Pr_Sy4LVRKy_Sm4CdwUl1Gryous6ncL96EMYsnM,411
3
- fastmcp/cli.py,sha256=RjtnF_4ApkIjxWfQlRmshb03icP6_nlNVV0LKnZGA5w,89
4
- fastmcp/exceptions.py,sha256=K0rCgXsUVlws39hz98Tb4BBf_BzIql_zXFZgqbkNTiE,348
5
- fastmcp/resources.py,sha256=Y1VwYEU7xBl0brHNZarBAgFmDdOZf4Q7xdbYxK7osnU,7065
6
- fastmcp/server.py,sha256=oDIid6XLXhqUNVliMw2x_SN2QC0BEcjSDAdi3YRRWeM,9311
7
- fastmcp/tools.py,sha256=EAkST81hTkMch7IlEGl4WC7npIDjGICLMEaXjPbttSo,3210
8
- fastmcp/cli/__init__.py,sha256=RUaBw4rNUJ7CjHrzVazB2jl60E6KA0Wo0x4OqHByL6c,68
9
- fastmcp/cli/claude.py,sha256=_kkDTlFdqkhl1GElVWtCd15txyw1liTYpmBVl8CA2VE,2458
10
- fastmcp/cli/cli.py,sha256=4Ld9ohDmJMMaveDpe_Wm4RtlnFyLeKaU-4tPhX-CQRA,8276
11
- fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31
12
- fastmcp/utilities/logging.py,sha256=t2w5bwtrkxHxioWSy5vY8esxLQxyxN8tfFZ1FI3Cb6E,704
13
- fastmcp-0.1.0.dist-info/METADATA,sha256=3oRrtc8oV24OH6GIjE0bxDBojjDpU95x_T8M1O2F5XM,2932
14
- fastmcp-0.1.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
15
- fastmcp-0.1.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
16
- fastmcp-0.1.0.dist-info/top_level.txt,sha256=9NvhdRmSJxxf5iTz58rYyea0DtTsKgvGQHMRZaa7NN4,8
17
- fastmcp-0.1.0.dist-info/RECORD,,
File without changes