mcpmon 0.3.0 → 1.0.0
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.
- package/.github/workflows/release.yml +36 -16
- package/README.md +89 -42
- package/bun.lock +15 -0
- package/gateway.ts +581 -0
- package/index.html +169 -26
- package/{mcpmon.py → mcpmon/__init__.py} +148 -113
- package/mcpmon/__main__.py +6 -0
- package/mcpmon/config.py +101 -0
- package/mcpmon/gateway.py +529 -0
- package/mcpmon/log.py +84 -0
- package/mcpmon.test.ts +127 -0
- package/mcpmon.ts +74 -4
- package/package.json +4 -1
- package/pyproject.toml +2 -1
- package/tests/test_gateway.py +403 -0
- package/tests/test_mcpmon.py +151 -0
- package/tests/test_new_tool_server.py +209 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
name: Release
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
4
7
|
workflow_dispatch:
|
|
5
8
|
inputs:
|
|
6
9
|
bump:
|
|
@@ -14,26 +17,20 @@ on:
|
|
|
14
17
|
- major
|
|
15
18
|
|
|
16
19
|
jobs:
|
|
17
|
-
|
|
20
|
+
# Only runs on workflow_dispatch - bumps version and creates tag
|
|
21
|
+
bump:
|
|
22
|
+
if: github.event_name == 'workflow_dispatch'
|
|
18
23
|
runs-on: ubuntu-latest
|
|
19
24
|
permissions:
|
|
20
25
|
contents: write
|
|
21
|
-
id-token: write
|
|
22
|
-
outputs:
|
|
23
|
-
version: ${{ steps.bump.outputs.version }}
|
|
24
26
|
steps:
|
|
25
27
|
- uses: actions/checkout@v4
|
|
26
28
|
with:
|
|
27
29
|
fetch-depth: 0
|
|
28
30
|
|
|
29
|
-
- uses: actions/setup-python@v5
|
|
30
|
-
with:
|
|
31
|
-
python-version: "3.12"
|
|
32
|
-
|
|
33
31
|
- uses: actions/setup-node@v4
|
|
34
32
|
with:
|
|
35
33
|
node-version: '20'
|
|
36
|
-
# NOTE: No registry-url - npm OIDC trusted publishers require no auth token present
|
|
37
34
|
|
|
38
35
|
- name: Get current version
|
|
39
36
|
id: current
|
|
@@ -56,6 +53,7 @@ jobs:
|
|
|
56
53
|
NEW_VERSION="$major.$minor.$patch"
|
|
57
54
|
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
58
55
|
sed -i "s/version = \"$CURRENT_VERSION\"/version = \"$NEW_VERSION\"/" pyproject.toml
|
|
56
|
+
sed -i "s/__version__ = \"$CURRENT_VERSION\"/__version__ = \"$NEW_VERSION\"/" mcpmon/__init__.py || true
|
|
59
57
|
npm version "$NEW_VERSION" --no-git-tag-version
|
|
60
58
|
|
|
61
59
|
- name: Commit and tag
|
|
@@ -64,16 +62,40 @@ jobs:
|
|
|
64
62
|
run: |
|
|
65
63
|
git config user.name "github-actions[bot]"
|
|
66
64
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
67
|
-
git add pyproject.toml package.json
|
|
65
|
+
git add pyproject.toml package.json mcpmon/__init__.py
|
|
68
66
|
git commit -m "(release): v$NEW_VERSION"
|
|
69
67
|
git tag "v$NEW_VERSION"
|
|
70
68
|
git push && git push --tags
|
|
71
69
|
|
|
70
|
+
# Runs on tag push - publishes to PyPI and npm
|
|
71
|
+
publish:
|
|
72
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
permissions:
|
|
75
|
+
contents: write
|
|
76
|
+
id-token: write
|
|
77
|
+
outputs:
|
|
78
|
+
version: ${{ steps.version.outputs.version }}
|
|
79
|
+
steps:
|
|
80
|
+
- uses: actions/checkout@v4
|
|
81
|
+
|
|
82
|
+
- name: Extract version from tag
|
|
83
|
+
id: version
|
|
84
|
+
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
|
85
|
+
|
|
86
|
+
- uses: actions/setup-python@v5
|
|
87
|
+
with:
|
|
88
|
+
python-version: "3.12"
|
|
89
|
+
|
|
90
|
+
- uses: actions/setup-node@v4
|
|
91
|
+
with:
|
|
92
|
+
node-version: '20'
|
|
93
|
+
|
|
72
94
|
- name: Create release
|
|
73
95
|
env:
|
|
74
96
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
75
|
-
|
|
76
|
-
run: gh release create "v$
|
|
97
|
+
VERSION: ${{ steps.version.outputs.version }}
|
|
98
|
+
run: gh release create "v$VERSION" --generate-notes || true
|
|
77
99
|
|
|
78
100
|
# Publish to PyPI
|
|
79
101
|
- name: Install build
|
|
@@ -93,7 +115,7 @@ jobs:
|
|
|
93
115
|
run: npm publish --provenance --access public
|
|
94
116
|
|
|
95
117
|
build-binaries:
|
|
96
|
-
needs:
|
|
118
|
+
needs: publish
|
|
97
119
|
runs-on: ${{ matrix.os }}
|
|
98
120
|
permissions:
|
|
99
121
|
contents: write
|
|
@@ -108,8 +130,6 @@ jobs:
|
|
|
108
130
|
target: darwin-x64
|
|
109
131
|
steps:
|
|
110
132
|
- uses: actions/checkout@v4
|
|
111
|
-
with:
|
|
112
|
-
ref: v${{ needs.release.outputs.version }}
|
|
113
133
|
|
|
114
134
|
- uses: oven-sh/setup-bun@v2
|
|
115
135
|
with:
|
|
@@ -123,6 +143,6 @@ jobs:
|
|
|
123
143
|
- name: Upload to release
|
|
124
144
|
env:
|
|
125
145
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
126
|
-
VERSION: ${{ needs.
|
|
146
|
+
VERSION: ${{ needs.publish.outputs.version }}
|
|
127
147
|
TARGET: ${{ matrix.target }}
|
|
128
148
|
run: gh release upload "v$VERSION" "mcpmon-$TARGET" --clobber
|
package/README.md
CHANGED
|
@@ -2,31 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
Hot reload for MCP servers. Like nodemon, but for MCP.
|
|
4
4
|
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Hot reload** - Restart server on file changes
|
|
8
|
+
- **Tool refresh** - Sends `notifications/tools/list_changed` so Claude Code sees new tools without session restart
|
|
9
|
+
- **Gateway mode** - Aggregate multiple MCP servers behind one gateway
|
|
10
|
+
- **Dual implementation** - Python and Bun/TypeScript with full feature parity
|
|
11
|
+
|
|
5
12
|
## Install
|
|
6
13
|
|
|
7
14
|
```bash
|
|
8
|
-
#
|
|
9
|
-
|
|
15
|
+
# Python
|
|
16
|
+
pip install mcpmon
|
|
10
17
|
|
|
11
|
-
#
|
|
12
|
-
|
|
18
|
+
# Bun (no install needed)
|
|
19
|
+
bunx mcpmon
|
|
13
20
|
|
|
14
|
-
#
|
|
15
|
-
|
|
21
|
+
# npm
|
|
22
|
+
npm install -g mcpmon
|
|
16
23
|
|
|
17
24
|
# Or download binary from GitHub releases (no dependencies)
|
|
18
25
|
```
|
|
19
26
|
|
|
20
27
|
## Usage
|
|
21
28
|
|
|
29
|
+
### Single Server Mode
|
|
30
|
+
|
|
22
31
|
```bash
|
|
23
32
|
mcpmon --watch src/ -- python -m my_mcp_server
|
|
24
33
|
```
|
|
25
34
|
|
|
26
|
-
###
|
|
35
|
+
### Gateway Mode (Multi-Server)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
mcpmon --config .mcpmon.yaml
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
# .mcpmon.yaml
|
|
43
|
+
servers:
|
|
44
|
+
sage:
|
|
45
|
+
command: sage-mcp
|
|
46
|
+
watch: ~/.sage/src/
|
|
47
|
+
|
|
48
|
+
crucible:
|
|
49
|
+
command: crucible-mcp
|
|
50
|
+
watch: ~/crucible/src/
|
|
51
|
+
|
|
52
|
+
my-server:
|
|
53
|
+
command: python
|
|
54
|
+
args: ["-m", "my_server"]
|
|
55
|
+
watch: ./src/
|
|
56
|
+
extensions: py,json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Gateway aggregates tools with prefixes: `sage__recall`, `crucible__review`, etc.
|
|
60
|
+
|
|
61
|
+
## Options
|
|
27
62
|
|
|
28
63
|
| Option | Description |
|
|
29
64
|
|--------|-------------|
|
|
65
|
+
| `-c, --config <file>` | Config file for multi-server gateway mode |
|
|
30
66
|
| `-w, --watch <dir>` | Directory to watch (default: `.`) |
|
|
31
67
|
| `-e, --ext <exts>` | Extensions to watch, comma-separated (default: `py`) |
|
|
32
68
|
| `-q, --quiet` | Only show errors |
|
|
@@ -41,46 +77,40 @@ mcpmon --watch src/ -- python -m my_mcp_server
|
|
|
41
77
|
--quiet Only errors
|
|
42
78
|
(default) Start, stop, restart events + PID
|
|
43
79
|
--verbose + file change details
|
|
44
|
-
--debug + everything
|
|
80
|
+
--debug + everything
|
|
45
81
|
```
|
|
46
82
|
|
|
47
|
-
|
|
83
|
+
## Examples
|
|
48
84
|
|
|
49
85
|
```bash
|
|
50
|
-
# Basic
|
|
86
|
+
# Basic - watch current directory for .py changes
|
|
51
87
|
mcpmon -- python server.py
|
|
52
88
|
|
|
53
|
-
# Watch
|
|
89
|
+
# Watch specific directory and extensions
|
|
54
90
|
mcpmon --watch src/ --ext py,json -- python -m myserver
|
|
55
91
|
|
|
56
|
-
# With timestamps and
|
|
57
|
-
mcpmon --timestamps --
|
|
58
|
-
|
|
59
|
-
# Log to file for debugging
|
|
60
|
-
mcpmon --debug --log-file mcpmon.log -- python server.py
|
|
61
|
-
|
|
62
|
-
# With crucible-mcp
|
|
63
|
-
mcpmon --watch src/crucible/ -- crucible-mcp
|
|
92
|
+
# With timestamps and log file
|
|
93
|
+
mcpmon --timestamps --log-file mcpmon.log -- python server.py
|
|
64
94
|
|
|
65
|
-
#
|
|
66
|
-
mcpmon --
|
|
95
|
+
# Gateway mode - multiple servers
|
|
96
|
+
mcpmon --config .mcpmon.yaml
|
|
67
97
|
```
|
|
68
98
|
|
|
69
99
|
### Sample Output
|
|
70
100
|
|
|
71
101
|
```
|
|
72
|
-
[mcpmon 16:08:50] Watching
|
|
73
|
-
[mcpmon 16:08:50 pid:53307] Started: python -m
|
|
102
|
+
[mcpmon 16:08:50] Watching src/ for .py changes
|
|
103
|
+
[mcpmon 16:08:50 pid:53307] Started: python -m my_server
|
|
104
|
+
[mcpmon 16:08:54] File modified: tools.py
|
|
74
105
|
[mcpmon 16:08:54 pid:53307] Restarting...
|
|
75
|
-
[mcpmon 16:08:54 pid:53411] Started: python -m
|
|
106
|
+
[mcpmon 16:08:54 pid:53411] Started: python -m my_server
|
|
76
107
|
[mcpmon 16:08:54 pid:53411] Restart #1 complete
|
|
77
|
-
[mcpmon 16:08:
|
|
78
|
-
[mcpmon 16:08:57] Shutdown complete (restarts: 1)
|
|
108
|
+
[mcpmon 16:08:54] Sent tools/list_changed notification
|
|
79
109
|
```
|
|
80
110
|
|
|
81
111
|
## MCP Config
|
|
82
112
|
|
|
83
|
-
|
|
113
|
+
### Single Server
|
|
84
114
|
|
|
85
115
|
```json
|
|
86
116
|
{
|
|
@@ -93,30 +123,47 @@ Use mcpmon in your `.mcp.json` for hot reload during development:
|
|
|
93
123
|
}
|
|
94
124
|
```
|
|
95
125
|
|
|
96
|
-
|
|
126
|
+
### Gateway (Multiple Servers)
|
|
97
127
|
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"mcpServers": {
|
|
131
|
+
"gateway": {
|
|
132
|
+
"command": "mcpmon",
|
|
133
|
+
"args": ["--config", ".mcpmon.yaml"]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## How It Works
|
|
140
|
+
|
|
141
|
+
### Single Server Mode
|
|
98
142
|
1. Starts your MCP server as a subprocess
|
|
99
143
|
2. Watches specified directory for file changes
|
|
100
144
|
3. On change: SIGTERM → wait 2s → SIGKILL → restart
|
|
101
|
-
4.
|
|
102
|
-
|
|
103
|
-
## Dual Implementation
|
|
104
|
-
|
|
105
|
-
mcpmon ships as both:
|
|
106
|
-
- **Bun/TypeScript** (`mcpmon.ts`) - Zero dependencies, fast startup
|
|
107
|
-
- **Python** (`mcpmon.py`) - Uses `watchfiles` for robust file watching
|
|
145
|
+
4. Sends `notifications/tools/list_changed` notification
|
|
146
|
+
5. Claude Code refreshes tool cache automatically
|
|
108
147
|
|
|
109
|
-
|
|
148
|
+
### Gateway Mode
|
|
149
|
+
1. Reads config file, starts all backend servers
|
|
150
|
+
2. Aggregates tools from all backends (prefixed: `backend__tool`)
|
|
151
|
+
3. Routes tool calls to correct backend
|
|
152
|
+
4. Watches each backend's files independently
|
|
153
|
+
5. Hot-reloads individual backends on change
|
|
154
|
+
6. Hot-adds/removes backends when config changes
|
|
110
155
|
|
|
111
156
|
## Development
|
|
112
157
|
|
|
113
158
|
```bash
|
|
114
|
-
#
|
|
159
|
+
# Python
|
|
115
160
|
pip install -e ".[dev]"
|
|
161
|
+
pytest tests/ -v # 42 tests
|
|
116
162
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
# Run Bun/TS tests (12 tests)
|
|
121
|
-
bun test
|
|
163
|
+
# Bun/TypeScript
|
|
164
|
+
bun test # 16 tests
|
|
122
165
|
```
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
package/bun.lock
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "mcpmon",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"yaml": "^2.8.2",
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
"packages": {
|
|
13
|
+
"yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
|
|
14
|
+
}
|
|
15
|
+
}
|