mcp-server-framework 1.1.0__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 (43) hide show
  1. mcp_server_framework-1.1.0/LICENSE +21 -0
  2. mcp_server_framework-1.1.0/PKG-INFO +429 -0
  3. mcp_server_framework-1.1.0/README.md +397 -0
  4. mcp_server_framework-1.1.0/pyproject.toml +53 -0
  5. mcp_server_framework-1.1.0/setup.cfg +4 -0
  6. mcp_server_framework-1.1.0/src/mcp_server_factory/__init__.py +11 -0
  7. mcp_server_framework-1.1.0/src/mcp_server_factory/commands.py +80 -0
  8. mcp_server_framework-1.1.0/src/mcp_server_factory/factory.py +113 -0
  9. mcp_server_framework-1.1.0/src/mcp_server_factory/loader.py +10 -0
  10. mcp_server_framework-1.1.0/src/mcp_server_factory/plugins/__init__.py +1 -0
  11. mcp_server_framework-1.1.0/src/mcp_server_factory/plugins/logging.py +121 -0
  12. mcp_server_framework-1.1.0/src/mcp_server_factory/plugins/management.py +52 -0
  13. mcp_server_framework-1.1.0/src/mcp_server_factory/py.typed +0 -0
  14. mcp_server_framework-1.1.0/src/mcp_server_factory/tracker.py +8 -0
  15. mcp_server_framework-1.1.0/src/mcp_server_framework/__init__.py +36 -0
  16. mcp_server_framework-1.1.0/src/mcp_server_framework/config.py +109 -0
  17. mcp_server_framework-1.1.0/src/mcp_server_framework/health.py +153 -0
  18. mcp_server_framework-1.1.0/src/mcp_server_framework/logging.py +60 -0
  19. mcp_server_framework-1.1.0/src/mcp_server_framework/oauth.py +179 -0
  20. mcp_server_framework-1.1.0/src/mcp_server_framework/plugins/__init__.py +16 -0
  21. mcp_server_framework-1.1.0/src/mcp_server_framework/plugins/loader.py +205 -0
  22. mcp_server_framework-1.1.0/src/mcp_server_framework/plugins/models.py +21 -0
  23. mcp_server_framework-1.1.0/src/mcp_server_framework/plugins/tracker.py +160 -0
  24. mcp_server_framework-1.1.0/src/mcp_server_framework/py.typed +0 -0
  25. mcp_server_framework-1.1.0/src/mcp_server_framework/server.py +116 -0
  26. mcp_server_framework-1.1.0/src/mcp_server_framework/utils/__init__.py +1 -0
  27. mcp_server_framework-1.1.0/src/mcp_server_framework.egg-info/PKG-INFO +429 -0
  28. mcp_server_framework-1.1.0/src/mcp_server_framework.egg-info/SOURCES.txt +41 -0
  29. mcp_server_framework-1.1.0/src/mcp_server_framework.egg-info/dependency_links.txt +1 -0
  30. mcp_server_framework-1.1.0/src/mcp_server_framework.egg-info/entry_points.txt +3 -0
  31. mcp_server_framework-1.1.0/src/mcp_server_framework.egg-info/requires.txt +10 -0
  32. mcp_server_framework-1.1.0/src/mcp_server_framework.egg-info/top_level.txt +3 -0
  33. mcp_server_framework-1.1.0/src/mcp_server_proxy/__init__.py +11 -0
  34. mcp_server_framework-1.1.0/src/mcp_server_proxy/cli.py +54 -0
  35. mcp_server_framework-1.1.0/src/mcp_server_proxy/client.py +74 -0
  36. mcp_server_framework-1.1.0/src/mcp_server_proxy/commands.py +21 -0
  37. mcp_server_framework-1.1.0/src/mcp_server_proxy/management.py +129 -0
  38. mcp_server_framework-1.1.0/src/mcp_server_proxy/plugins/__init__.py +0 -0
  39. mcp_server_framework-1.1.0/src/mcp_server_proxy/plugins/management.py +136 -0
  40. mcp_server_framework-1.1.0/src/mcp_server_proxy/proxy.py +237 -0
  41. mcp_server_framework-1.1.0/src/mcp_server_proxy/py.typed +0 -0
  42. mcp_server_framework-1.1.0/src/mcp_server_proxy/serve.py +118 -0
  43. mcp_server_framework-1.1.0/src/mcp_server_proxy/tool_log.py +104 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 cuber-it
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,429 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-server-framework
3
+ Version: 1.1.0
4
+ Summary: MCP Server Toolkit — Framework, Factory and Proxy for building MCP servers
5
+ Author-email: cuber IT service <info@uc-it.de>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://www.uc-it.de
8
+ Project-URL: Repository, https://github.com/cuber-it/mcp_server_toolkit
9
+ Project-URL: Issues, https://github.com/cuber-it/mcp_server_toolkit/issues
10
+ Keywords: mcp,model-context-protocol,framework,factory,proxy,llm,ai,plugins
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: mcp>=1.26.0
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: fastapi>=0.100.0
25
+ Requires-Dist: uvicorn>=0.20.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
29
+ Requires-Dist: httpx>=0.24; extra == "dev"
30
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # MCP Server Toolkit
34
+
35
+ A Python toolkit for building MCP (Model Context Protocol) servers.
36
+
37
+ Three packages, one ecosystem:
38
+
39
+ | Package | Role |
40
+ |---------|------|
41
+ | **mcp_server_framework** | Shared library: config, transport, health, plugin infrastructure |
42
+ | **mcp_server_factory** | Static plugin loading at startup (CLI tool) |
43
+ | **mcp_server_proxy** | Dynamic plugin loading at runtime (daemon with management API) |
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ pip install -e ".[dev]"
49
+ ```
50
+
51
+ ### Factory — Build a static server from plugins
52
+
53
+ ```bash
54
+ mcp-factory --plugins echo --http 12201 --plugin-dir ./plugins
55
+ ```
56
+
57
+ ### Proxy — Dynamic server with runtime plugin management
58
+
59
+ ```bash
60
+ # Start proxy with echo plugin on HTTP
61
+ mcp-proxy serve --autoload echo --http 12200 --plugin-dir ./plugins
62
+
63
+ # Manage plugins at runtime (separate terminal)
64
+ mcp-proxy status
65
+ mcp-proxy load shell
66
+ mcp-proxy unload echo
67
+ mcp-proxy reload shell
68
+ ```
69
+
70
+ ### Framework — Build a standalone server
71
+
72
+ ```python
73
+ from mcp_server_framework import load_config, create_server, run_server
74
+
75
+ config = load_config()
76
+ mcp = create_server(config)
77
+
78
+ @mcp.tool()
79
+ def hello(name: str) -> str:
80
+ """Says hello."""
81
+ return f"Hello, {name}!"
82
+
83
+ run_server(mcp, config)
84
+ ```
85
+
86
+ ## Plugin Interface
87
+
88
+ Every plugin implements one function:
89
+
90
+ ```python
91
+ def register(mcp, config: dict) -> None:
92
+ @mcp.tool()
93
+ def my_tool(param: str) -> str:
94
+ """Tool description for the LLM."""
95
+ return do_something(param)
96
+ ```
97
+
98
+ Works with Factory and Proxy without changes.
99
+
100
+ ### Create a New Plugin
101
+
102
+ ```bash
103
+ ./scripts/new-plugin.sh myservice # creates plugins/myservice/
104
+ ./scripts/new-plugin.sh myservice ./src # custom target directory
105
+ ```
106
+
107
+ Generates `__init__.py` (MCP wiring) and `tools.py` (pure logic) with annotated
108
+ examples — start editing `tools.py`, restart the proxy, done.
109
+
110
+ ### Recommended Plugin Structure
111
+
112
+ ```
113
+ plugins/myservice/
114
+ ├── __init__.py # register(mcp, config) — thin MCP wrapper
115
+ ├── client.py # HTTP client (pure Python, no MCP)
116
+ └── tools.py # Tool logic (pure Python, no MCP)
117
+ ```
118
+
119
+ This separation keeps your business logic testable and reusable
120
+ without MCP dependencies.
121
+
122
+ ## Included Plugins
123
+
124
+ | Plugin | Tools | Description |
125
+ |--------|-------|-------------|
126
+ | `echo` | 2 | Minimal example — echo and echo_upper |
127
+ | `greet` | 1 | Minimal example — greet by name |
128
+ | `mattermost` | 5 | Mattermost REST API (send, channels, posts, search, user) |
129
+ | `wekan` | 18 | Wekan Kanban REST API (boards, cards, checklists, labels) |
130
+ | `shell` | 33 | Filesystem, editor, search, shell, git, systemd, HTTP, packages, diagnostics |
131
+
132
+ ## Proxy Features
133
+
134
+ ### Management API
135
+
136
+ The proxy runs a FastAPI management server on a separate port (default: 12299):
137
+
138
+ ```
139
+ GET /proxy/status All plugins and tools
140
+ GET /proxy/plugins Plugin name list
141
+ POST /proxy/load {"plugin": "name"}
142
+ POST /proxy/unload {"plugin": "name"}
143
+ POST /proxy/reload {"plugin": "name"}
144
+ GET /proxy/commands Registered management extensions
145
+ POST /proxy/command/{name} Run a management extension
146
+ ```
147
+
148
+ ### Management API Authentication
149
+
150
+ Optionally protect the management API with a Bearer token:
151
+
152
+ ```yaml
153
+ # proxy.yaml
154
+ management_token: "${MCP_MGMT_TOKEN}"
155
+ ```
156
+
157
+ ```bash
158
+ # Or via CLI
159
+ mcp-proxy serve --mgmt-token "my-secret" --autoload echo
160
+
161
+ # Client commands with token
162
+ mcp-proxy status --token "my-secret"
163
+ mcp-proxy load shell --token "my-secret"
164
+
165
+ # Or via environment variable (works for both server and client)
166
+ export MCP_MGMT_TOKEN="my-secret"
167
+ mcp-proxy serve --autoload echo
168
+ mcp-proxy status
169
+ ```
170
+
171
+ Without a token configured, no authentication is required (development default).
172
+
173
+ ### Auto-Prefix
174
+
175
+ Avoid tool name collisions when loading multiple plugins:
176
+
177
+ ```yaml
178
+ # proxy.yaml
179
+ auto_prefix: true # tool "send" from plugin "mm" becomes "mm_send"
180
+
181
+ plugins:
182
+ mattermost:
183
+ prefix: "mm" # custom prefix (overrides plugin name)
184
+ echo:
185
+ prefix: false # disable prefix for this plugin
186
+ ```
187
+
188
+ Tools that already start with their plugin's prefix are not double-prefixed.
189
+
190
+ ### Health Endpoint
191
+
192
+ When running on HTTP, the health server includes plugin status:
193
+
194
+ ```
195
+ GET /health Simple status
196
+ GET /health/detailed Uptime, requests, errors
197
+ GET /health/ready Readiness check (verifies plugins loaded)
198
+ GET /health/plugins Current plugin and tool inventory
199
+ ```
200
+
201
+ ### Management Command Extensions
202
+
203
+ Extend the proxy with custom management commands:
204
+
205
+ ```python
206
+ def register(mcp, config: dict) -> None:
207
+ proxy = config.get("_proxy")
208
+ if proxy:
209
+ proxy.register_command("stats", lambda p: f"{len(p.plugins)} plugins")
210
+ ```
211
+
212
+ Commands are available via MCP tools and the REST management API.
213
+
214
+ ## OAuth Authentication
215
+
216
+ OAuth is **enabled by default** for HTTP transport (ignored for stdio).
217
+ Uses RFC 7662 Token Introspection — no extra dependencies needed (uses httpx from MCP SDK).
218
+ Valid tokens are cached for 8 hours (configurable via `oauth_cache_ttl`) to reduce introspection load.
219
+
220
+ Configure via YAML or environment variables:
221
+
222
+ ```yaml
223
+ # config.yaml
224
+ oauth_enabled: true # default: true
225
+ oauth_server_url: "https://auth.example.com" # OAuth introspection endpoint
226
+ oauth_public_url: "https://mcp.example.com" # Public URL of this server
227
+ oauth_cache_ttl: 28800 # token cache in seconds (default: 8h)
228
+ ```
229
+
230
+ ```bash
231
+ # Or via environment
232
+ export MCP_OAUTH_ENABLED=true
233
+ export MCP_OAUTH_SERVER_URL=https://auth.example.com
234
+ export MCP_PUBLIC_URL=https://mcp.example.com
235
+ ```
236
+
237
+ **Behavior:**
238
+ - HTTP + OAuth configured → full token verification via introspection
239
+ - HTTP + OAuth enabled but URLs missing → **warning**, runs without auth
240
+ - HTTP + `oauth_enabled: false` → no auth, no warning
241
+ - stdio → OAuth ignored regardless of config
242
+
243
+ To explicitly disable:
244
+ ```yaml
245
+ oauth_enabled: false
246
+ ```
247
+
248
+ ## Security
249
+
250
+ ### Shell Plugin Boundaries
251
+
252
+ The shell plugin supports configurable security boundaries:
253
+
254
+ ```yaml
255
+ plugins:
256
+ shell:
257
+ enabled: true
258
+ allowed_paths: # restrict filesystem access
259
+ - "/home/user/projects"
260
+ - "/tmp"
261
+ blocked_commands: # block dangerous commands
262
+ - "sudo"
263
+ - "rm -rf /"
264
+ - "chmod"
265
+ ```
266
+
267
+ Without boundaries configured, the shell plugin has unrestricted access
268
+ (suitable for local development). For shared or production deployments,
269
+ configure `allowed_paths` and `blocked_commands`.
270
+
271
+ ### Pre-Call Validation
272
+
273
+ Register a custom validator that runs before every tool invocation:
274
+
275
+ ```python
276
+ from mcp_server_framework.plugins import set_pre_call_validator
277
+
278
+ def my_validator(tool_name: str, params: dict) -> str | None:
279
+ """Return error string to reject, None to allow."""
280
+ if len(str(params)) > 100_000:
281
+ return "Input too large"
282
+ return None
283
+
284
+ set_pre_call_validator(my_validator)
285
+ ```
286
+
287
+ ## Logging
288
+
289
+ Configure log format via config or environment:
290
+
291
+ ```yaml
292
+ log_level: INFO
293
+ log_format: json # "json" for machine-readable, "text" (default) for humans
294
+ ```
295
+
296
+ JSON output example:
297
+ ```json
298
+ {"ts": "2026-03-11T10:30:00+00:00", "level": "INFO", "logger": "mcp_server_proxy.proxy", "msg": "Plugin 'echo' loaded: 2 tools ['echo', 'echo_upper']"}
299
+ ```
300
+
301
+ ### Tool Call Logging (Proxy)
302
+
303
+ The proxy automatically logs every tool call to `~/.mcp_proxy/logs/tool_calls.jsonl`:
304
+
305
+ ```json
306
+ {"ts": "2026-03-11T14:30:00", "tool": "shell_exec", "params": {"command": "ls"}, "result": "...", "ok": true}
307
+ ```
308
+
309
+ - Daily rotation with gzip compression (`YYYY-MM-DD.jsonl.gz`)
310
+ - 90-day retention with automatic cleanup
311
+ - Safe — never raises, never blocks tool execution
312
+
313
+ ## Interactive Test Client
314
+
315
+ Debug and explore any MCP server from the terminal:
316
+
317
+ ```bash
318
+ # Connect via stdio
319
+ python examples/mcp_client.py -v stdio -- mcp-proxy --autoload echo
320
+
321
+ # Connect via HTTP
322
+ python examples/mcp_client.py http http://localhost:12200/mcp
323
+ ```
324
+
325
+ REPL commands: `tools`, `call <name>`, `resources`, `prompts`, `info`, `quit`
326
+
327
+ Tool shorthand — call tools directly by name:
328
+
329
+ ```
330
+ mcp> echo hello # single-arg shorthand
331
+ mcp> echo_upper world
332
+ mcp> greet Claude
333
+ mcp> proxy__status # no-arg tools work too
334
+ mcp> call echo # interactive mode (prompts for args)
335
+ ```
336
+
337
+ ## Examples
338
+
339
+ Ready-to-run scripts in `examples/`:
340
+
341
+ ```bash
342
+ ./examples/run_factory_echo.sh # Factory + Echo (stdio, all-in-one)
343
+ ./examples/run_proxy_http.sh # Proxy + Echo (HTTP)
344
+ ./examples/run_proxy_shell.sh # Proxy + Shell (HTTP)
345
+ ./examples/run_proxy_full.sh # Proxy + Echo + Shell (HTTP)
346
+ ./examples/connect_proxy_http.sh # Client → running proxy
347
+ ```
348
+
349
+ See [examples/README.md](examples/README.md) for details.
350
+
351
+ ## Configuration
352
+
353
+ YAML config with environment variable overrides (`MCP_*`):
354
+
355
+ ```yaml
356
+ server_name: "My Proxy"
357
+ transport: http # stdio | http
358
+ host: "0.0.0.0"
359
+ port: 12200
360
+ health_port: 12201
361
+ management_port: 12299
362
+ log_level: INFO
363
+ log_format: text # text | json
364
+ auto_prefix: true
365
+
366
+ # OAuth (enabled by default for HTTP, set false to disable)
367
+ oauth_server_url: "https://auth.example.com"
368
+ oauth_public_url: "https://mcp.example.com"
369
+ oauth_cache_ttl: 28800 # token cache seconds (default: 8h, 0 = disabled)
370
+
371
+ # Management API auth (separate from OAuth, optional)
372
+ management_token: "${MCP_MGMT_TOKEN}"
373
+
374
+ autoload:
375
+ - echo
376
+ - shell
377
+
378
+ plugins:
379
+ echo:
380
+ enabled: true
381
+ shell:
382
+ enabled: true
383
+ timeout: 60
384
+ allowed_paths:
385
+ - "/home/user/projects"
386
+ blocked_commands:
387
+ - "sudo"
388
+ mattermost:
389
+ enabled: true
390
+ url: "https://mm.example.com"
391
+ token: "${MM_TOKEN}"
392
+ ```
393
+
394
+ Example configs in `config/` and `examples/configs/`.
395
+
396
+ ## Tests
397
+
398
+ ```bash
399
+ pytest # 159 tests
400
+ pytest -v # verbose
401
+ pytest tests/proxy/ # proxy only
402
+ ```
403
+
404
+ ## Project Structure
405
+
406
+ ```
407
+ src/
408
+ ├── mcp_server_framework/ # Shared: config, server, health, logging, plugins
409
+ ├── mcp_server_factory/ # Static loader + CLI
410
+ └── mcp_server_proxy/ # Dynamic loader + management API + CLI
411
+ plugins/
412
+ ├── echo.py # Minimal example
413
+ ├── greet.py # Minimal example
414
+ ├── mattermost/ # REST adapter (Mattermost)
415
+ ├── wekan/ # REST adapter (Wekan Kanban)
416
+ └── shell/ # 33 workstation tools (filesystem, editor, search, shell, git, system, HTTP, packages)
417
+ examples/
418
+ ├── mcp_client.py # Interactive test client
419
+ ├── configs/ # Ready-to-use YAML configs
420
+ └── *.sh # Launch scripts
421
+ scripts/
422
+ └── new-plugin.sh # Plugin scaffold generator
423
+ tests/ # 159 tests (framework, factory, proxy, plugins)
424
+ config/ # Example configs + systemd service
425
+ ```
426
+
427
+ ## License
428
+
429
+ MIT