fastmcp 0.2.0__py3-none-any.whl → 0.3.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.
@@ -0,0 +1,4 @@
1
+ from .base import Tool
2
+ from .tool_manager import ToolManager
3
+
4
+ __all__ = ["Tool", "ToolManager"]
fastmcp/tools/base.py ADDED
@@ -0,0 +1,79 @@
1
+ import fastmcp
2
+ from fastmcp.exceptions import ToolError
3
+
4
+
5
+ from pydantic import BaseModel, Field, TypeAdapter, validate_call
6
+
7
+
8
+ import inspect
9
+ from typing import TYPE_CHECKING, Any, Callable, Optional
10
+
11
+ if TYPE_CHECKING:
12
+ from fastmcp.server import Context
13
+
14
+
15
+ class Tool(BaseModel):
16
+ """Internal tool registration info."""
17
+
18
+ fn: Callable = Field(exclude=True)
19
+ name: str = Field(description="Name of the tool")
20
+ description: str = Field(description="Description of what the tool does")
21
+ parameters: dict = Field(description="JSON schema for tool parameters")
22
+ is_async: bool = Field(description="Whether the tool is async")
23
+ context_kwarg: Optional[str] = Field(
24
+ None, description="Name of the kwarg that should receive context"
25
+ )
26
+
27
+ @classmethod
28
+ def from_function(
29
+ cls,
30
+ fn: Callable,
31
+ name: Optional[str] = None,
32
+ description: Optional[str] = None,
33
+ context_kwarg: Optional[str] = None,
34
+ ) -> "Tool":
35
+ """Create a Tool from a function."""
36
+ func_name = name or fn.__name__
37
+
38
+ if func_name == "<lambda>":
39
+ raise ValueError("You must provide a name for lambda functions")
40
+
41
+ func_doc = description or fn.__doc__ or ""
42
+ is_async = inspect.iscoroutinefunction(fn)
43
+
44
+ # Get schema from TypeAdapter - will fail if function isn't properly typed
45
+ parameters = TypeAdapter(fn).json_schema()
46
+
47
+ # Find context parameter if it exists
48
+ if context_kwarg is None:
49
+ sig = inspect.signature(fn)
50
+ for param_name, param in sig.parameters.items():
51
+ if param.annotation is fastmcp.Context:
52
+ context_kwarg = param_name
53
+ break
54
+
55
+ # ensure the arguments are properly cast
56
+ fn = validate_call(fn)
57
+
58
+ return cls(
59
+ fn=fn,
60
+ name=func_name,
61
+ description=func_doc,
62
+ parameters=parameters,
63
+ is_async=is_async,
64
+ context_kwarg=context_kwarg,
65
+ )
66
+
67
+ async def run(self, arguments: dict, context: Optional["Context"] = None) -> Any:
68
+ """Run the tool with arguments."""
69
+ try:
70
+ # Inject context if needed
71
+ if self.context_kwarg:
72
+ arguments[self.context_kwarg] = context
73
+
74
+ # Call function with proper async handling
75
+ if self.is_async:
76
+ return await self.fn(**arguments)
77
+ return self.fn(**arguments)
78
+ except Exception as e:
79
+ raise ToolError(f"Error executing tool {self.name}: {e}") from e
@@ -0,0 +1,55 @@
1
+ from fastmcp.exceptions import ToolError
2
+
3
+ from fastmcp.tools.base import Tool
4
+
5
+
6
+ from typing import Any, Callable, Dict, Optional, TYPE_CHECKING
7
+
8
+ from fastmcp.utilities.logging import get_logger
9
+
10
+ if TYPE_CHECKING:
11
+ from fastmcp.server import Context
12
+
13
+ logger = get_logger(__name__)
14
+
15
+
16
+ class ToolManager:
17
+ """Manages FastMCP tools."""
18
+
19
+ def __init__(self, warn_on_duplicate_tools: bool = True):
20
+ self._tools: Dict[str, Tool] = {}
21
+ self.warn_on_duplicate_tools = warn_on_duplicate_tools
22
+
23
+ def get_tool(self, name: str) -> Optional[Tool]:
24
+ """Get tool by name."""
25
+ return self._tools.get(name)
26
+
27
+ def list_tools(self) -> list[Tool]:
28
+ """List all registered tools."""
29
+ return list(self._tools.values())
30
+
31
+ def add_tool(
32
+ self,
33
+ fn: Callable,
34
+ name: Optional[str] = None,
35
+ description: Optional[str] = None,
36
+ ) -> Tool:
37
+ """Add a tool to the server."""
38
+ tool = Tool.from_function(fn, name=name, description=description)
39
+ existing = self._tools.get(tool.name)
40
+ if existing:
41
+ if self.warn_on_duplicate_tools:
42
+ logger.warning(f"Tool already exists: {tool.name}")
43
+ return existing
44
+ self._tools[tool.name] = tool
45
+ return tool
46
+
47
+ async def call_tool(
48
+ self, name: str, arguments: dict, context: Optional["Context"] = None
49
+ ) -> Any:
50
+ """Call a tool by name with arguments."""
51
+ tool = self.get_tool(name)
52
+ if not tool:
53
+ raise ToolError(f"Unknown tool: {name}")
54
+
55
+ return await tool.run(arguments, context=context)
@@ -0,0 +1,53 @@
1
+ """Common types used across FastMCP."""
2
+
3
+ import base64
4
+ from pathlib import Path
5
+ from typing import Optional, Union
6
+
7
+ from mcp.types import ImageContent
8
+
9
+
10
+ class Image:
11
+ """Helper class for returning images from tools."""
12
+
13
+ def __init__(
14
+ self,
15
+ path: Optional[Union[str, Path]] = None,
16
+ data: Optional[bytes] = None,
17
+ format: Optional[str] = None,
18
+ ):
19
+ if path is None and data is None:
20
+ raise ValueError("Either path or data must be provided")
21
+ if path is not None and data is not None:
22
+ raise ValueError("Only one of path or data can be provided")
23
+
24
+ self.path = Path(path) if path else None
25
+ self.data = data
26
+ self._format = format
27
+ self._mime_type = self._get_mime_type()
28
+
29
+ def _get_mime_type(self) -> str:
30
+ """Get MIME type from format or guess from file extension."""
31
+ if self._format:
32
+ return f"image/{self._format.lower()}"
33
+
34
+ if self.path:
35
+ suffix = self.path.suffix.lower()
36
+ return {
37
+ ".png": "image/png",
38
+ ".jpg": "image/jpeg",
39
+ ".jpeg": "image/jpeg",
40
+ ".gif": "image/gif",
41
+ ".webp": "image/webp",
42
+ }.get(suffix, "application/octet-stream")
43
+ return "image/png" # default for raw binary data
44
+
45
+ def to_image_content(self) -> ImageContent:
46
+ """Convert to MCP ImageContent."""
47
+ if self.path:
48
+ with open(self.path, "rb") as f:
49
+ data = base64.b64encode(f.read()).decode()
50
+ else:
51
+ data = base64.b64encode(self.data).decode()
52
+
53
+ return ImageContent(type="image", data=data, mimeType=self._mime_type)
@@ -0,0 +1,385 @@
1
+ Metadata-Version: 2.3
2
+ Name: fastmcp
3
+ Version: 0.3.0
4
+ Summary: A more ergonomic interface for MCP servers
5
+ Author: Jeremiah Lowin
6
+ License: Apache-2.0
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: httpx>=0.26.0
9
+ Requires-Dist: mcp<2.0.0,>=1.0.0
10
+ Requires-Dist: pydantic-settings>=2.6.1
11
+ Requires-Dist: pydantic<3.0.0,>=2.5.3
12
+ Requires-Dist: typer>=0.9.0
13
+ Provides-Extra: dev
14
+ Requires-Dist: copychat>=0.5.2; extra == 'dev'
15
+ Requires-Dist: ipython>=8.12.3; extra == 'dev'
16
+ Requires-Dist: pdbpp>=0.10.3; extra == 'dev'
17
+ Requires-Dist: pre-commit; extra == 'dev'
18
+ Requires-Dist: pytest-asyncio>=0.23.5; extra == 'dev'
19
+ Requires-Dist: pytest-xdist>=3.6.1; extra == 'dev'
20
+ Requires-Dist: pytest>=8.3.3; extra == 'dev'
21
+ Requires-Dist: ruff; extra == 'dev'
22
+ Description-Content-Type: text/markdown
23
+
24
+ <!-- omit in toc -->
25
+ # FastMCP
26
+
27
+ <div align="center">
28
+
29
+ [![PyPI - Version](https://img.shields.io/pypi/v/fastmcp.svg)](https://pypi.org/project/fastmcp)
30
+ [![Tests](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml/badge.svg)](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml)
31
+ [![License](https://img.shields.io/github/license/jlowin/fastmcp.svg)](https://github.com/jlowin/fastmcp/blob/main/LICENSE)
32
+
33
+ </div>
34
+
35
+ FastMCP is a high-level, intuitive framework for building [Model Context Protocol (MCP)](https://modelcontextprotocol.io) servers with Python. While MCP is a powerful protocol that enables LLMs to interact with local data and tools in a secure, standardized way, the specification can be cumbersome to implement directly. FastMCP lets you build fully compliant MCP servers in the most Pythonic way possible - in many cases, simply decorating a function is all that's required.
36
+
37
+ 🚧 *Note: FastMCP is under active development, as is the low-level MCP Python SDK* 🏗️
38
+
39
+ Key features:
40
+ * **Intuitive**: Designed to feel familiar to Python developers, with powerful type hints and editor support
41
+ * **Simple**: Build compliant MCP servers with minimal boilerplate
42
+ * **Fast**: High-performance async implementation
43
+ * **Full-featured**: Complete implementation of the MCP specification
44
+
45
+ <!-- omit in toc -->
46
+ ## Table of Contents
47
+
48
+ - [Installation](#installation)
49
+ - [Quickstart](#quickstart)
50
+ - [What is MCP?](#what-is-mcp)
51
+ - [Core Concepts](#core-concepts)
52
+ - [Server](#server)
53
+ - [Resources](#resources)
54
+ - [Tools](#tools)
55
+ - [Prompts](#prompts)
56
+ - [Images](#images)
57
+ - [Context](#context)
58
+ - [Deployment](#deployment)
59
+ - [Development](#development)
60
+ - [Claude Desktop](#claude-desktop)
61
+ - [Examples](#examples)
62
+ - [Echo Server](#echo-server)
63
+ - [SQLite Explorer](#sqlite-explorer)
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ # We strongly recommend installing with uv
69
+ brew install uv # on macOS
70
+ uv pip install fastmcp
71
+ ```
72
+
73
+ Or with pip:
74
+ ```bash
75
+ pip install fastmcp
76
+ ```
77
+
78
+ ## Quickstart
79
+
80
+ Let's create a simple MCP server that exposes a calculator tool and some data:
81
+
82
+ ```python
83
+ from fastmcp import FastMCP
84
+
85
+
86
+ # Create an MCP server
87
+ mcp = FastMCP("Demo")
88
+
89
+
90
+ # Add an addition tool
91
+ @mcp.tool()
92
+ def add(a: int, b: int) -> int:
93
+ """Add two numbers"""
94
+ return a + b
95
+
96
+
97
+ # Add a dynamic greeting resource
98
+ @mcp.resource("greeting://{name}")
99
+ def get_greeting(name: str) -> str:
100
+ """Get a personalized greeting"""
101
+ return f"Hello, {name}!"
102
+ ```
103
+
104
+ To use this server, you have two options:
105
+
106
+ 1. Install it in [Claude Desktop](https://claude.ai/download):
107
+ ```bash
108
+ fastmcp install server.py
109
+ ```
110
+
111
+ 2. Test it with the MCP Inspector:
112
+ ```bash
113
+ fastmcp dev server.py
114
+ ```
115
+
116
+ ![MCP Inspector](docs/images/mcp-inspector.png)
117
+
118
+ ## What is MCP?
119
+
120
+ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
121
+
122
+ - Expose data through **Resources** (like GET endpoints)
123
+ - Provide functionality through **Tools** (like POST endpoints)
124
+ - Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
125
+
126
+ ## Core Concepts
127
+
128
+ *Note: All code examples below assume you've created a FastMCP server instance called `mcp`.*
129
+
130
+ ### Server
131
+
132
+ The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
133
+
134
+ ```python
135
+ from fastmcp import FastMCP
136
+
137
+ # Create a named server
138
+ mcp = FastMCP("My App")
139
+
140
+ # Configure host/port for HTTP transport (optional)
141
+ mcp = FastMCP("My App", host="localhost", port=8000)
142
+ ```
143
+
144
+ ### Resources
145
+
146
+ Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects. Some examples:
147
+
148
+ - File contents
149
+ - Database schemas
150
+ - API responses
151
+ - System information
152
+
153
+ Resources can be static:
154
+ ```python
155
+ @mcp.resource("config://app")
156
+ def get_config() -> str:
157
+ """Static configuration data"""
158
+ return "App configuration here"
159
+ ```
160
+
161
+ Or dynamic with parameters (FastMCP automatically handles these as MCP templates):
162
+ ```python
163
+ @mcp.resource("users://{user_id}/profile")
164
+ def get_user_profile(user_id: str) -> str:
165
+ """Dynamic user data"""
166
+ return f"Profile data for user {user_id}"
167
+ ```
168
+
169
+ ### Tools
170
+
171
+ Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects. They're similar to POST endpoints in a REST API.
172
+
173
+ Simple calculation example:
174
+ ```python
175
+ @mcp.tool()
176
+ def calculate_bmi(weight_kg: float, height_m: float) -> float:
177
+ """Calculate BMI given weight in kg and height in meters"""
178
+ return weight_kg / (height_m ** 2)
179
+ ```
180
+
181
+ HTTP request example:
182
+ ```python
183
+ import httpx
184
+
185
+ @mcp.tool()
186
+ async def fetch_weather(city: str) -> str:
187
+ """Fetch current weather for a city"""
188
+ async with httpx.AsyncClient() as client:
189
+ response = await client.get(
190
+ f"https://api.weather.com/{city}"
191
+ )
192
+ return response.text
193
+ ```
194
+
195
+ ### Prompts
196
+
197
+ Prompts are reusable templates that help LLMs interact with your server effectively. They're like "best practices" encoded into your server. A prompt can be as simple as a string:
198
+
199
+ ```python
200
+ @mcp.prompt()
201
+ def review_code(code: str) -> str:
202
+ return f"Please review this code:\n\n{code}"
203
+ ```
204
+
205
+ Or a more structured sequence of messages:
206
+ ```python
207
+ from fastmcp.prompts.base import UserMessage, AssistantMessage
208
+
209
+ @mcp.prompt()
210
+ def debug_error(error: str) -> list[Message]:
211
+ return [
212
+ UserMessage("I'm seeing this error:"),
213
+ UserMessage(error),
214
+ AssistantMessage("I'll help debug that. What have you tried so far?")
215
+ ]
216
+ ```
217
+
218
+
219
+ ### Images
220
+
221
+ FastMCP provides an `Image` class that automatically handles image data in your server:
222
+
223
+ ```python
224
+ from fastmcp import FastMCP, Image
225
+ from PIL import Image as PILImage
226
+
227
+ @mcp.tool()
228
+ def create_thumbnail(image_path: str) -> Image:
229
+ """Create a thumbnail from an image"""
230
+ img = PILImage.open(image_path)
231
+ img.thumbnail((100, 100))
232
+
233
+ # FastMCP automatically handles conversion and MIME types
234
+ return Image(data=img.tobytes(), format="png")
235
+
236
+ @mcp.tool()
237
+ def load_image(path: str) -> Image:
238
+ """Load an image from disk"""
239
+ # FastMCP handles reading and format detection
240
+ return Image(path=path)
241
+ ```
242
+
243
+ Images can be used as the result of both tools and resources.
244
+
245
+ ### Context
246
+
247
+ The Context object gives your tools and resources access to MCP capabilities. To use it, add a parameter annotated with `fastmcp.Context`:
248
+
249
+ ```python
250
+ from fastmcp import FastMCP, Context
251
+
252
+ @mcp.tool()
253
+ async def long_task(files: list[str], ctx: Context) -> str:
254
+ """Process multiple files with progress tracking"""
255
+ for i, file in enumerate(files):
256
+ ctx.info(f"Processing {file}")
257
+ await ctx.report_progress(i, len(files))
258
+
259
+ # Read another resource if needed
260
+ data = await ctx.read_resource(f"file://{file}")
261
+
262
+ return "Processing complete"
263
+ ```
264
+
265
+ The Context object provides:
266
+ - Progress reporting through `report_progress()`
267
+ - Logging via `debug()`, `info()`, `warning()`, and `error()`
268
+ - Resource access through `read_resource()`
269
+ - Request metadata via `request_id` and `client_id`
270
+
271
+ ## Deployment
272
+
273
+ The FastMCP CLI helps you develop and deploy MCP servers.
274
+
275
+ Note that for all deployment commands, you are expected to provide the fully qualified path to your server object. For example, if you have a file `server.py` that contains a FastMCP server named `my_server`, you would provide `path/to/server.py:my_server`.
276
+
277
+ If your server variable has one of the standard names (`mcp`, `server`, or `app`), you can omit the server name from the path and just provide the file: `path/to/server.py`.
278
+
279
+ ### Development
280
+
281
+ Test and debug your server with the MCP Inspector:
282
+ ```bash
283
+ # Provide the fully qualified path to your server
284
+ fastmcp dev server.py:my_mcp_server
285
+
286
+ # Or just the file if your server is named 'mcp', 'server', or 'app'
287
+ fastmcp dev server.py
288
+ ```
289
+
290
+ Your server is run in an isolated environment, so you'll need to indicate any dependencies with the `--with` flag. FastMCP is automatically included. If you are working on a uv project, you can use the `--with-editable` flag to mount your current directory:
291
+
292
+ ```bash
293
+ # With additional packages
294
+ fastmcp dev server.py --with pandas --with numpy
295
+
296
+ # Using your project's dependencies and up-to-date code
297
+ fastmcp dev server.py --with-editable .
298
+ ```
299
+
300
+ ### Claude Desktop
301
+
302
+ Install your server in Claude Desktop:
303
+ ```bash
304
+ # Basic usage (name is taken from your FastMCP instance)
305
+ fastmcp install server.py
306
+
307
+ # With a custom name
308
+ fastmcp install server.py --name "My Server"
309
+
310
+ # With dependencies
311
+ fastmcp install server.py --with pandas --with numpy
312
+
313
+ # Replace an existing server
314
+ fastmcp install server.py --force
315
+ ```
316
+
317
+ The server name in Claude will be:
318
+ 1. The `--name` parameter if provided
319
+ 2. The `name` from your FastMCP instance
320
+ 3. The filename if the server can't be imported
321
+
322
+ ## Examples
323
+
324
+ ### Echo Server
325
+ A simple server demonstrating resources, tools, and prompts:
326
+
327
+ ```python
328
+ from fastmcp import FastMCP
329
+
330
+ mcp = FastMCP("Echo")
331
+
332
+ @mcp.resource("echo://{message}")
333
+ def echo_resource(message: str) -> str:
334
+ """Echo a message as a resource"""
335
+ return f"Resource echo: {message}"
336
+
337
+ @mcp.tool()
338
+ def echo_tool(message: str) -> str:
339
+ """Echo a message as a tool"""
340
+ return f"Tool echo: {message}"
341
+
342
+ @mcp.prompt()
343
+ def echo_prompt(message: str) -> str:
344
+ """Create an echo prompt"""
345
+ return f"Please process this message: {message}"
346
+ ```
347
+
348
+ ### SQLite Explorer
349
+ A more complex example showing database integration:
350
+
351
+ ```python
352
+ from fastmcp import FastMCP
353
+ import sqlite3
354
+
355
+ mcp = FastMCP("SQLite Explorer")
356
+
357
+ @mcp.resource("schema://main")
358
+ def get_schema() -> str:
359
+ """Provide the database schema as a resource"""
360
+ conn = sqlite3.connect("database.db")
361
+ schema = conn.execute(
362
+ "SELECT sql FROM sqlite_master WHERE type='table'"
363
+ ).fetchall()
364
+ return "\n".join(sql[0] for sql in schema if sql[0])
365
+
366
+ @mcp.tool()
367
+ def query_data(sql: str) -> str:
368
+ """Execute SQL queries safely"""
369
+ conn = sqlite3.connect("database.db")
370
+ try:
371
+ result = conn.execute(sql).fetchall()
372
+ return "\n".join(str(row) for row in result)
373
+ except Exception as e:
374
+ return f"Error: {str(e)}"
375
+
376
+ @mcp.prompt()
377
+ def analyze_table(table: str) -> str:
378
+ """Create a prompt template for analyzing tables"""
379
+ return f"""Please analyze this database table:
380
+ Table: {table}
381
+ Schema:
382
+ {get_schema()}
383
+
384
+ What insights can you provide about the structure and relationships?"""
385
+ ```
@@ -0,0 +1,26 @@
1
+ fastmcp/__init__.py,sha256=Y5dHGBwyQPgNP5gzOyNIItefvMZ3vJLdom1oV8A1u_k,248
2
+ fastmcp/exceptions.py,sha256=K0rCgXsUVlws39hz98Tb4BBf_BzIql_zXFZgqbkNTiE,348
3
+ fastmcp/server.py,sha256=gZCl4ppLWYjM4L6MXJxr-jh9ngjHjaFSFTLpofmgtmA,21987
4
+ fastmcp/cli/__init__.py,sha256=7hrwtCHX9nMd9qcz7R_JFSoqbL71fC35cBLXBS430mg,88
5
+ fastmcp/cli/claude.py,sha256=hId0cTmAfCrav72Hg5LeO0SPPNyEVtIOcoKVAy8gD3k,3390
6
+ fastmcp/cli/cli.py,sha256=Mru5j0_apXBnLBEd6DMICGPUk52DN3eyjSc1B973M2M,10028
7
+ fastmcp/prompts/__init__.py,sha256=4BsMxoYolpoxg74xkkkzCFL8vvdkLVJ5cIPNs1ND1Jo,99
8
+ fastmcp/prompts/base.py,sha256=WaSsfyFSsUPUbcApkGy3Pm-Ne-Gk-5ZwU3efqRYn1mQ,4996
9
+ fastmcp/prompts/manager.py,sha256=EkexOB_N4QNtC-UlZmIcWcau91ceO2O1K4_kD75pA_A,1485
10
+ fastmcp/prompts/prompt_manager.py,sha256=5uR14gsi7l0YHwbxFH7N5b_ACHHRWyTtBAH3R0-G5rk,1129
11
+ fastmcp/resources/__init__.py,sha256=9QShop6ckX3Khh3BQLZNkB6R2ZhwskAcnh7-sIuX-W8,464
12
+ fastmcp/resources/base.py,sha256=glGLpHp8Eq-LKq7YLJx3LRDiCktLlLaTTmltNcdWzHg,1818
13
+ fastmcp/resources/resource_manager.py,sha256=b0PKpG-pKi7x2Yx-qaeknjv0mqL17zixSIYOz2V5G6o,3271
14
+ fastmcp/resources/templates.py,sha256=EmLlI-ddBBzSTAUiA6-knFnHCE3MPMW2ZoH9WswPKvI,2868
15
+ fastmcp/resources/types.py,sha256=ofE6bfeQQfPSmaWrLGDf3qjCP0kGjKmvupsHDYkSrj0,5658
16
+ fastmcp/tools/__init__.py,sha256=ZboxhyMJDl87Svjov8YwNYwNZi55P9VhmpTjBZLesnk,96
17
+ fastmcp/tools/base.py,sha256=JPdTx8SAl5pKsHyIVxnsLG88f3fbjnopDTOAZ_PoVQE,2585
18
+ fastmcp/tools/tool_manager.py,sha256=PT6XHcQWzhdC6kfdsJaddRn7VLps4nAs5FMG8l1j8Zc,1617
19
+ fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31
20
+ fastmcp/utilities/logging.py,sha256=t2w5bwtrkxHxioWSy5vY8esxLQxyxN8tfFZ1FI3Cb6E,704
21
+ fastmcp/utilities/types.py,sha256=jFlZMZsKrJg4NWc1vTBIILLoHpTVwSd-vxO7ycoRuig,1718
22
+ fastmcp-0.3.0.dist-info/METADATA,sha256=Nu76qWE1nxUHiHF4pczCTMUl8C2hKpXfIeo2Sp1UHxo,11452
23
+ fastmcp-0.3.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
24
+ fastmcp-0.3.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
25
+ fastmcp-0.3.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
26
+ fastmcp-0.3.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: hatchling 1.26.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-