You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
|[`hmr-daemon`](./packages/hmr-daemon/)| Background daemon that refreshes modules on changes |
49
+
|[`fastapi-reloader`](./packages/fastapi-reloader/)| Browser auto-refresh middleware for automatic page reloading |
50
+
39
51
> [!TIP]
40
-
> The hmr ecosystem is now production-ready. It has been carefully designed to handle many common edge cases and Pythonic *magic* patterns, including lazy imports, circular dependencies, dynamic imports, module-level `__getattr__`, decorators, and more. You can confidently use hmr in production environments if needed.
52
+
> The hmr ecosystem is basically stable and production-ready for most use cases. It has been carefully designed to handle many common edge cases and Pythonic *magic* patterns, including lazy imports, dynamic imports, module-level `__getattr__`, decorators, and more. However, circular dependencies in some edge cases may still cause unexpected behavior. Use with caution if you have a lot of code in `__init__.py`.
Now you can view the resources and tools as normal. Then change them in `main.py` and save the file WITHOUT clicking "Restart" in the inspector. Any call to get the resource / run the tool will reflect the updated code.
It uses the MCP server defined in `main.py`. Now open your favorite editor and modify `main.py` to see the printing update in real-time!
37
+
38
+
## What to Observe
39
+
40
+
- Try changing the `echo` tool's return value or the `greet` resource's content.
41
+
- You will see the client output update to reflect your changes without restarting the connection.
42
+
43
+
This demo shows how to use `mcp-hmr` to enable seamless hot reloading for MCP servers, maintaining the connection between client and server while updating the code on-the-fly.
Copy file name to clipboardExpand all lines: packages/mcp-hmr/README.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,22 +5,22 @@
5
5
6
6
Provides [Hot Module Reloading](https://pyth-on-line.promplate.dev/hmr) for MCP/FastMCP servers.
7
7
8
-
It acts as **a drop-in replacement for `mcp run module:app` or `fastmcp run module:app`.** Both [FastMCP v2](https://github.com/jlowin/fastmcp) and the [official python SDK](https://github.com/modelcontextprotocol/python-sdk) are supported.
8
+
It acts as **a drop-in replacement for `mcp run path:app` or `fastmcp run path:app`.** Both [FastMCP v2](https://github.com/jlowin/fastmcp) and the [official python SDK](https://github.com/modelcontextprotocol/python-sdk) are supported.
9
9
10
10
## Usage
11
11
12
-
If your server instance is named `app` in `path/to/main.py`, you can run:
12
+
If your server instance is named `app` in `./path/to/main.py`, you can run:
13
13
14
14
```sh
15
-
mcp-hmr path.to.main:app
15
+
mcp-hmr ./path/to/main.py:app
16
16
```
17
17
18
-
Which will be equivalent to the following code but with [HMR](https://github.com/promplate/hmr) enabled:
18
+
Which will be equivalent to `fastmcp run ./path/to/main.py:app` but with [HMR](https://github.com/promplate/hmr) enabled.
19
19
20
-
```py
21
-
from path.to.main import app
20
+
Or using module import format:
22
21
23
-
app.run("stdio")
22
+
```sh
23
+
mcp-hmr main:app
24
24
```
25
25
26
26
Now, whenever you save changes to your source code, the server will automatically reload without dropping the connection to the client.
parser.exit(1, f"The target argument must be in the format 'module:attr', e.g. 'main:app'. Got: '{target}'")
117
+
if":"notintarget[1:-1]:
118
+
parser.exit(1, f"The target argument must be in the format 'module:attr' (e.g. 'main:app') or 'path:attr' (e.g. './path/to/main.py:app'). Got: '{target}'")
105
119
106
120
fromcontextlibimportsuppress
107
-
frompathlibimportPath
108
121
109
122
fromanyioimportrun
110
123
111
124
if (cwd:=str(Path.cwd())) notinsys.path:
112
125
sys.path.append(cwd)
113
126
127
+
if (file:=Path(module_or_path:=target[: target.rindex(":")])).is_file():
128
+
sys.path.insert(0, str(file.parent))
129
+
else:
130
+
if"."inmodule_or_path: # find_spec may cause implicit imports of parent packages
131
+
fromreactivity.hmr.coreimportpatch_meta_path
132
+
133
+
patch_meta_path()
134
+
135
+
iffind_spec(module_or_path) isNone:
136
+
parser.exit(1, f"The target '{module_or_path}' not found. Please provide a valid module name or a file path.")
0 commit comments