fastmcp 0.3.3__tar.gz → 0.3.4__tar.gz
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-0.3.3 → fastmcp-0.3.4}/PKG-INFO +5 -8
- {fastmcp-0.3.3 → fastmcp-0.3.4}/README.md +4 -7
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/cli/claude.py +19 -2
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/base.py +12 -19
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/ai-labeler.yml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/release.yml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/ai-labeler.yml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/lint.yml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/publish.yml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/run-tests.yml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.gitignore +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.pre-commit-config.yaml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/.python-version +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/LICENSE +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/docs/assets/demo-inspector.png +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/desktop.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/echo.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/readme-quickstart.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/screenshot.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/simple_echo.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/text_me.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/pyproject.toml +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/cli/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/cli/cli.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/exceptions.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/base.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/manager.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/prompt_manager.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/resource_manager.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/templates.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/types.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/server.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/tools/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/tools/base.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/tools/tool_manager.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/utilities/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/utilities/logging.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/utilities/types.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/prompts/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/prompts/test_base.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/prompts/test_manager.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_file_resources.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_function_resources.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_resource_manager.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_resource_template.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_resources.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/servers/__init__.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/servers/test_file_server.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/test_cli.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/test_server.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/test_tool_manager.py +0 -0
- {fastmcp-0.3.3 → fastmcp-0.3.4}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: fastmcp
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A more ergonomic interface for MCP servers
|
|
5
5
|
Author: Jeremiah Lowin
|
|
6
6
|
License: Apache-2.0
|
|
@@ -122,6 +122,8 @@ pip install fastmcp
|
|
|
122
122
|
Let's create a simple MCP server that exposes a calculator tool and some data:
|
|
123
123
|
|
|
124
124
|
```python
|
|
125
|
+
# server.py
|
|
126
|
+
|
|
125
127
|
from fastmcp import FastMCP
|
|
126
128
|
|
|
127
129
|
|
|
@@ -143,14 +145,12 @@ def get_greeting(name: str) -> str:
|
|
|
143
145
|
return f"Hello, {name}!"
|
|
144
146
|
```
|
|
145
147
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
1. Install it in [Claude Desktop](https://claude.ai/download):
|
|
148
|
+
You can install this server in [Claude Desktop](https://claude.ai/download) and interact with it right away by running:
|
|
149
149
|
```bash
|
|
150
150
|
fastmcp install server.py
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
Alternatively, you can test it with the MCP Inspector:
|
|
154
154
|
```bash
|
|
155
155
|
fastmcp dev server.py
|
|
156
156
|
```
|
|
@@ -181,9 +181,6 @@ from fastmcp import FastMCP
|
|
|
181
181
|
# Create a named server
|
|
182
182
|
mcp = FastMCP("My App")
|
|
183
183
|
|
|
184
|
-
# Configure host/port for HTTP transport (optional)
|
|
185
|
-
mcp = FastMCP("My App", host="localhost", port=8000)
|
|
186
|
-
|
|
187
184
|
# Specify dependencies for deployment and development
|
|
188
185
|
mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
|
|
189
186
|
```
|
|
@@ -98,6 +98,8 @@ pip install fastmcp
|
|
|
98
98
|
Let's create a simple MCP server that exposes a calculator tool and some data:
|
|
99
99
|
|
|
100
100
|
```python
|
|
101
|
+
# server.py
|
|
102
|
+
|
|
101
103
|
from fastmcp import FastMCP
|
|
102
104
|
|
|
103
105
|
|
|
@@ -119,14 +121,12 @@ def get_greeting(name: str) -> str:
|
|
|
119
121
|
return f"Hello, {name}!"
|
|
120
122
|
```
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
1. Install it in [Claude Desktop](https://claude.ai/download):
|
|
124
|
+
You can install this server in [Claude Desktop](https://claude.ai/download) and interact with it right away by running:
|
|
125
125
|
```bash
|
|
126
126
|
fastmcp install server.py
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
Alternatively, you can test it with the MCP Inspector:
|
|
130
130
|
```bash
|
|
131
131
|
fastmcp dev server.py
|
|
132
132
|
```
|
|
@@ -157,9 +157,6 @@ from fastmcp import FastMCP
|
|
|
157
157
|
# Create a named server
|
|
158
158
|
mcp = FastMCP("My App")
|
|
159
159
|
|
|
160
|
-
# Configure host/port for HTTP transport (optional)
|
|
161
|
-
mcp = FastMCP("My App", host="localhost", port=8000)
|
|
162
|
-
|
|
163
160
|
# Specify dependencies for deployment and development
|
|
164
161
|
mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
|
|
165
162
|
```
|
|
@@ -41,14 +41,31 @@ def update_claude_config(
|
|
|
41
41
|
with_packages: Optional list of additional packages to install
|
|
42
42
|
env_vars: Optional dictionary of environment variables. These are merged with
|
|
43
43
|
any existing variables, with new values taking precedence.
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
RuntimeError: If Claude Desktop's config directory is not found, indicating
|
|
47
|
+
Claude Desktop may not be installed or properly set up.
|
|
44
48
|
"""
|
|
45
49
|
config_dir = get_claude_config_path()
|
|
46
50
|
if not config_dir:
|
|
47
|
-
|
|
51
|
+
raise RuntimeError(
|
|
52
|
+
"Claude Desktop config directory not found. Please ensure Claude Desktop "
|
|
53
|
+
"is installed and has been run at least once to initialize its configuration."
|
|
54
|
+
)
|
|
48
55
|
|
|
49
56
|
config_file = config_dir / "claude_desktop_config.json"
|
|
50
57
|
if not config_file.exists():
|
|
51
|
-
|
|
58
|
+
try:
|
|
59
|
+
config_file.write_text("{}")
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.error(
|
|
62
|
+
"Failed to create Claude config file",
|
|
63
|
+
extra={
|
|
64
|
+
"error": str(e),
|
|
65
|
+
"config_file": str(config_file),
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
return False
|
|
52
69
|
|
|
53
70
|
try:
|
|
54
71
|
config = json.loads(config_file.read_text())
|
|
@@ -1,34 +1,17 @@
|
|
|
1
1
|
"""Base classes and interfaces for FastMCP resources."""
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Union
|
|
5
5
|
|
|
6
6
|
from pydantic import (
|
|
7
7
|
AnyUrl,
|
|
8
8
|
BaseModel,
|
|
9
|
-
BeforeValidator,
|
|
10
9
|
ConfigDict,
|
|
11
10
|
Field,
|
|
12
11
|
FileUrl,
|
|
13
12
|
ValidationInfo,
|
|
14
13
|
field_validator,
|
|
15
14
|
)
|
|
16
|
-
from pydantic.networks import _BaseUrl # TODO: remove this once pydantic is updated
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def maybe_cast_str_to_any_url(x) -> AnyUrl:
|
|
20
|
-
if isinstance(x, FileUrl):
|
|
21
|
-
return x
|
|
22
|
-
elif isinstance(x, AnyUrl):
|
|
23
|
-
return x
|
|
24
|
-
elif isinstance(x, str):
|
|
25
|
-
if x.startswith("file://"):
|
|
26
|
-
return FileUrl(x)
|
|
27
|
-
return AnyUrl(x)
|
|
28
|
-
raise ValueError(f"Expected str or AnyUrl, got {type(x)}")
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
LaxAnyUrl = Annotated[_BaseUrl | str, BeforeValidator(maybe_cast_str_to_any_url)]
|
|
32
15
|
|
|
33
16
|
|
|
34
17
|
class Resource(BaseModel, abc.ABC):
|
|
@@ -36,7 +19,8 @@ class Resource(BaseModel, abc.ABC):
|
|
|
36
19
|
|
|
37
20
|
model_config = ConfigDict(validate_default=True)
|
|
38
21
|
|
|
39
|
-
uri:
|
|
22
|
+
# uri: Annotated[AnyUrl, BeforeValidator(maybe_cast_str_to_any_url)] = Field(
|
|
23
|
+
uri: AnyUrl = Field(default=..., description="URI of the resource")
|
|
40
24
|
name: str | None = Field(description="Name of the resource", default=None)
|
|
41
25
|
description: str | None = Field(
|
|
42
26
|
description="Description of the resource", default=None
|
|
@@ -47,6 +31,15 @@ class Resource(BaseModel, abc.ABC):
|
|
|
47
31
|
pattern=r"^[a-zA-Z0-9]+/[a-zA-Z0-9\-+.]+$",
|
|
48
32
|
)
|
|
49
33
|
|
|
34
|
+
@field_validator("uri", mode="before")
|
|
35
|
+
def validate_uri(cls, uri: AnyUrl | str) -> AnyUrl:
|
|
36
|
+
if isinstance(uri, str):
|
|
37
|
+
# AnyUrl doesn't support triple-slashes, but files do ("file:///absolute/path")
|
|
38
|
+
if uri.startswith("file://"):
|
|
39
|
+
return FileUrl(uri)
|
|
40
|
+
return AnyUrl(uri)
|
|
41
|
+
return uri
|
|
42
|
+
|
|
50
43
|
@field_validator("name", mode="before")
|
|
51
44
|
@classmethod
|
|
52
45
|
def set_default_name(cls, name: str | None, info: ValidationInfo) -> str:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|