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.
Files changed (57) hide show
  1. {fastmcp-0.3.3 → fastmcp-0.3.4}/PKG-INFO +5 -8
  2. {fastmcp-0.3.3 → fastmcp-0.3.4}/README.md +4 -7
  3. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/cli/claude.py +19 -2
  4. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/base.py +12 -19
  5. {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/ai-labeler.yml +0 -0
  6. {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/release.yml +0 -0
  7. {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/ai-labeler.yml +0 -0
  8. {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/lint.yml +0 -0
  9. {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/publish.yml +0 -0
  10. {fastmcp-0.3.3 → fastmcp-0.3.4}/.github/workflows/run-tests.yml +0 -0
  11. {fastmcp-0.3.3 → fastmcp-0.3.4}/.gitignore +0 -0
  12. {fastmcp-0.3.3 → fastmcp-0.3.4}/.pre-commit-config.yaml +0 -0
  13. {fastmcp-0.3.3 → fastmcp-0.3.4}/.python-version +0 -0
  14. {fastmcp-0.3.3 → fastmcp-0.3.4}/LICENSE +0 -0
  15. {fastmcp-0.3.3 → fastmcp-0.3.4}/docs/assets/demo-inspector.png +0 -0
  16. {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/desktop.py +0 -0
  17. {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/echo.py +0 -0
  18. {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/readme-quickstart.py +0 -0
  19. {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/screenshot.py +0 -0
  20. {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/simple_echo.py +0 -0
  21. {fastmcp-0.3.3 → fastmcp-0.3.4}/examples/text_me.py +0 -0
  22. {fastmcp-0.3.3 → fastmcp-0.3.4}/pyproject.toml +0 -0
  23. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/__init__.py +0 -0
  24. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/cli/__init__.py +0 -0
  25. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/cli/cli.py +0 -0
  26. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/exceptions.py +0 -0
  27. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/__init__.py +0 -0
  28. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/base.py +0 -0
  29. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/manager.py +0 -0
  30. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/prompts/prompt_manager.py +0 -0
  31. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/__init__.py +0 -0
  32. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/resource_manager.py +0 -0
  33. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/templates.py +0 -0
  34. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/resources/types.py +0 -0
  35. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/server.py +0 -0
  36. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/tools/__init__.py +0 -0
  37. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/tools/base.py +0 -0
  38. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/tools/tool_manager.py +0 -0
  39. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/utilities/__init__.py +0 -0
  40. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/utilities/logging.py +0 -0
  41. {fastmcp-0.3.3 → fastmcp-0.3.4}/src/fastmcp/utilities/types.py +0 -0
  42. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/__init__.py +0 -0
  43. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/prompts/__init__.py +0 -0
  44. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/prompts/test_base.py +0 -0
  45. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/prompts/test_manager.py +0 -0
  46. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/__init__.py +0 -0
  47. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_file_resources.py +0 -0
  48. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_function_resources.py +0 -0
  49. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_resource_manager.py +0 -0
  50. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_resource_template.py +0 -0
  51. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/resources/test_resources.py +0 -0
  52. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/servers/__init__.py +0 -0
  53. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/servers/test_file_server.py +0 -0
  54. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/test_cli.py +0 -0
  55. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/test_server.py +0 -0
  56. {fastmcp-0.3.3 → fastmcp-0.3.4}/tests/test_tool_manager.py +0 -0
  57. {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
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
- To use this server, you have two options:
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
- 2. Test it with the MCP Inspector:
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
- To use this server, you have two options:
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
- 2. Test it with the MCP Inspector:
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
- return False
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
- return False
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 Annotated, Union
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: LaxAnyUrl = Field(default=..., description="URI of the resource")
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