chuk-mcp-runtime 0.3__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.
- chuk_mcp_runtime-0.3/MANIFEST.in +21 -0
- chuk_mcp_runtime-0.3/PKG-INFO +298 -0
- chuk_mcp_runtime-0.3/README.md +278 -0
- chuk_mcp_runtime-0.3/pyproject.toml +58 -0
- chuk_mcp_runtime-0.3/setup.cfg +4 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/__init__.py +21 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/artifacts/__init__.py +385 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/common/__init__.py +0 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/common/errors.py +32 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/common/mcp_tool_decorator.py +408 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/common/openai_compatibility.py +311 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/common/tool_naming.py +151 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/common/verify_credentials.py +79 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/entry.py +264 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/grid/hub_sandbox.py +248 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/main.py +13 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/proxy/__init__.py +13 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/proxy/manager.py +255 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/proxy/tool_wrapper.py +114 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/proxy_cli.py +167 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/server/__init__.py +0 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/server/config_loader.py +148 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/server/logging_config.py +100 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/server/server.py +611 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/server/server_registry.py +212 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/session/__init__.py +55 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/session/session_bridge.py +109 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/session/session_management.py +196 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/tools/__init__.py +215 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/tools/artifacts_tools.py +723 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime/tools/session_tools.py +387 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime.egg-info/PKG-INFO +298 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime.egg-info/SOURCES.txt +38 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime.egg-info/dependency_links.txt +1 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime.egg-info/entry_points.txt +4 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime.egg-info/requires.txt +12 -0
- chuk_mcp_runtime-0.3/src/chuk_mcp_runtime.egg-info/top_level.txt +1 -0
- chuk_mcp_runtime-0.3/tests/test_entry_basic.py +118 -0
- chuk_mcp_runtime-0.3/tests/test_entry_extended.py +492 -0
- chuk_mcp_runtime-0.3/tests/test_entry_integration.py +322 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Include documentation
|
|
2
|
+
include README.md
|
|
3
|
+
include LICENSE.md
|
|
4
|
+
|
|
5
|
+
# Include package files
|
|
6
|
+
recursive-include src/chuk_mcp_runtime *.py
|
|
7
|
+
|
|
8
|
+
# Include any resources the echo server might need
|
|
9
|
+
recursive-include src/chuk_mcp_runtime/resources *.json *.txt
|
|
10
|
+
|
|
11
|
+
# Exclude development and temporary files
|
|
12
|
+
global-exclude *.py[cod]
|
|
13
|
+
global-exclude __pycache__
|
|
14
|
+
global-exclude *.so
|
|
15
|
+
global-exclude .git*
|
|
16
|
+
global-exclude .DS_Store
|
|
17
|
+
global-exclude *.egg-info
|
|
18
|
+
global-exclude *.egg
|
|
19
|
+
global-exclude .coverage
|
|
20
|
+
global-exclude htmlcov
|
|
21
|
+
global-exclude .pytest_cache
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chuk-mcp-runtime
|
|
3
|
+
Version: 0.3
|
|
4
|
+
Summary: Generic CHUK MCP Runtime for MCP servers
|
|
5
|
+
Author-email: Chris Hay <your.email@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: pydantic>=2.10.6
|
|
10
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
11
|
+
Requires-Dist: pyjwt>=2.10.1
|
|
12
|
+
Requires-Dist: cryptography>=44.0.3
|
|
13
|
+
Requires-Dist: chuk-artifacts>=0.2.2
|
|
14
|
+
Requires-Dist: chuk-tool-processor>=0.4
|
|
15
|
+
Requires-Dist: mcp>=1.6.0
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=8.3.5; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-asyncio>=0.26.0; extra == "dev"
|
|
19
|
+
Requires-Dist: ruff>=0.4.6; extra == "dev"
|
|
20
|
+
|
|
21
|
+
# CHUK MCP Runtime
|
|
22
|
+
|
|
23
|
+
CHUK MCP Runtime is a flexible framework that connects local and remote MCP (Model Context Protocol) servers. It enables you to:
|
|
24
|
+
|
|
25
|
+
- Host your own Python-based MCP tools locally with configurable timeouts
|
|
26
|
+
- Connect to remote MCP servers through stdio or SSE protocols
|
|
27
|
+
- Provide OpenAI-compatible function calling interfaces
|
|
28
|
+
- Create proxy layers that expose multiple MCP servers through a single endpoint
|
|
29
|
+
- Configure per-tool timeout settings for reliable execution
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Basic installation
|
|
35
|
+
uv pip install chuk-mcp-runtime
|
|
36
|
+
|
|
37
|
+
# With optional dependencies
|
|
38
|
+
uv pip install chuk-mcp-runtime[websocket,dev]
|
|
39
|
+
|
|
40
|
+
# Make sure to install tzdata for proper timezone support
|
|
41
|
+
uv pip install tzdata
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Core Components
|
|
45
|
+
|
|
46
|
+
The CHUK MCP Runtime consists of two main command-line tools:
|
|
47
|
+
|
|
48
|
+
1. **`chuk-mcp-server`**: Runs a complete MCP server with local tools and optional proxy support
|
|
49
|
+
2. **`chuk-mcp-proxy`**: Provides a lightweight proxy layer that wraps remote MCP servers
|
|
50
|
+
|
|
51
|
+
## Quick Start: Using the Proxy
|
|
52
|
+
|
|
53
|
+
The proxy layer allows you to expose tools from multiple MCP servers through a unified interface.
|
|
54
|
+
|
|
55
|
+
### Example 1: Basic Command Line Usage
|
|
56
|
+
|
|
57
|
+
Run an MCP proxy with a time server:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Start a proxy to the time server with dot notation (proxy.time.get_current_time)
|
|
61
|
+
uv run -m chuk_mcp_runtime.proxy_cli --stdio time --command uvx --args mcp-server-time --local-timezone America/New_York
|
|
62
|
+
|
|
63
|
+
# Start a proxy with OpenAI-compatible underscore notation (time_get_current_time)
|
|
64
|
+
uv run -m chuk_mcp_runtime.proxy_cli --stdio time --command uvx --args mcp-server-time --local-timezone America/New_York --openai-compatible
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
You can also use the `--` separator for command arguments:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv run -m chuk_mcp_runtime.proxy_cli --stdio time --command uvx -- mcp-server-time --local-timezone America/New_York
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Once the proxy is running, you'll see output like:
|
|
74
|
+
```
|
|
75
|
+
Running servers : time
|
|
76
|
+
Wrapped tools : proxy.time.get_current_time, proxy.time.convert_time
|
|
77
|
+
Smoke-test call : ...
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Example 2: Configuration File
|
|
81
|
+
|
|
82
|
+
Create a YAML configuration file:
|
|
83
|
+
|
|
84
|
+
```yaml
|
|
85
|
+
# stdio_proxy_config.yaml
|
|
86
|
+
proxy:
|
|
87
|
+
enabled: true
|
|
88
|
+
namespace: "proxy"
|
|
89
|
+
openai_compatible: false # Use true for underscore notation (time_get_current_time)
|
|
90
|
+
|
|
91
|
+
mcp_servers:
|
|
92
|
+
time:
|
|
93
|
+
type: "stdio"
|
|
94
|
+
command: "uvx"
|
|
95
|
+
args: ["mcp-server-time", "--local-timezone", "America/New_York"]
|
|
96
|
+
|
|
97
|
+
echo:
|
|
98
|
+
type: "stdio"
|
|
99
|
+
command: "python"
|
|
100
|
+
args: ["examples/echo_server/main.py"]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Run the proxy with the config file:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv run -m chuk_mcp_runtime.proxy_cli --config stdio_proxy_config.yaml
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Example 3: OpenAI-Compatible Mode
|
|
110
|
+
|
|
111
|
+
To expose tools with underscore notation (compatible with OpenAI function calling):
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
# openai_compatible_config.yaml
|
|
115
|
+
proxy:
|
|
116
|
+
enabled: true
|
|
117
|
+
namespace: "proxy"
|
|
118
|
+
openai_compatible: true # Enable underscore notation
|
|
119
|
+
only_openai_tools: true # Only register underscore-notation tools
|
|
120
|
+
|
|
121
|
+
mcp_servers:
|
|
122
|
+
time:
|
|
123
|
+
type: "stdio"
|
|
124
|
+
command: "uvx"
|
|
125
|
+
args: ["mcp-server-time", "--local-timezone", "America/New_York"]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Run with:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
uv run -m chuk_mcp_runtime.proxy_cli --config openai_compatible_config.yaml
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This exposes tools like `time_get_current_time` instead of `proxy.time.get_current_time`.
|
|
135
|
+
|
|
136
|
+
## Creating Local MCP Tools
|
|
137
|
+
|
|
138
|
+
### 1. Create a custom tool
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
# my_tools/tools.py
|
|
142
|
+
from chuk_mcp_runtime.common.mcp_tool_decorator import mcp_tool
|
|
143
|
+
|
|
144
|
+
@mcp_tool(name="get_current_time", description="Get the current time in a timezone")
|
|
145
|
+
async def get_current_time(timezone: str = "UTC") -> str:
|
|
146
|
+
"""Get the current time in the specified timezone."""
|
|
147
|
+
from datetime import datetime
|
|
148
|
+
import pytz
|
|
149
|
+
|
|
150
|
+
tz = pytz.timezone(timezone)
|
|
151
|
+
now = datetime.now(tz)
|
|
152
|
+
return now.strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
153
|
+
|
|
154
|
+
@mcp_tool(name="calculate_sum", description="Calculate the sum of two numbers")
|
|
155
|
+
async def calculate_sum(a: int, b: int) -> dict:
|
|
156
|
+
"""Calculate the sum of two numbers."""
|
|
157
|
+
result = a + b
|
|
158
|
+
return {
|
|
159
|
+
"operation": "addition",
|
|
160
|
+
"operands": [a, b],
|
|
161
|
+
"result": result
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 2. Create a config file
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
# config.yaml
|
|
169
|
+
host:
|
|
170
|
+
name: "my-mcp-server"
|
|
171
|
+
log_level: "INFO"
|
|
172
|
+
|
|
173
|
+
server:
|
|
174
|
+
type: "stdio"
|
|
175
|
+
|
|
176
|
+
tools:
|
|
177
|
+
registry_module: "chuk_mcp_runtime.common.mcp_tool_decorator"
|
|
178
|
+
registry_attr: "TOOLS_REGISTRY"
|
|
179
|
+
|
|
180
|
+
mcp_servers:
|
|
181
|
+
my_tools:
|
|
182
|
+
location: "./my_tools"
|
|
183
|
+
tools:
|
|
184
|
+
module: "my_tools.tools"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 3. Run the server
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
uv run -m chuk_mcp_runtime.main --config config.yaml
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Tool Configuration
|
|
194
|
+
|
|
195
|
+
### Timeout Settings
|
|
196
|
+
|
|
197
|
+
CHUK MCP Runtime supports configurable timeouts for tools to handle long-running operations:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# Tool with custom timeout
|
|
201
|
+
@mcp_tool(
|
|
202
|
+
name="api_call",
|
|
203
|
+
description="Call external API",
|
|
204
|
+
timeout=30 # 30 second timeout
|
|
205
|
+
)
|
|
206
|
+
async def api_call(url: str) -> dict:
|
|
207
|
+
# Implementation here
|
|
208
|
+
pass
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
# config.yaml timeout settings
|
|
213
|
+
tools:
|
|
214
|
+
timeout: 60 # Default timeout for all tools
|
|
215
|
+
tool_configs:
|
|
216
|
+
api_call:
|
|
217
|
+
timeout: 45 # Override specific tool timeout
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Environment variable: `MCP_TOOL_TIMEOUT=60`
|
|
221
|
+
|
|
222
|
+
### Advanced Tool Features
|
|
223
|
+
|
|
224
|
+
Tools support:
|
|
225
|
+
- **Type hints** for automatic schema generation
|
|
226
|
+
- **Docstring parsing** for parameter descriptions
|
|
227
|
+
- **Async execution** with timeout protection
|
|
228
|
+
- **Error handling** with graceful degradation
|
|
229
|
+
- **Session management** for stateful operations
|
|
230
|
+
|
|
231
|
+
## Running a Combined Local + Proxy Server
|
|
232
|
+
|
|
233
|
+
You can run a single server that provides both local tools and proxied remote tools:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
# combined_config.yaml
|
|
237
|
+
host:
|
|
238
|
+
name: "combined-server"
|
|
239
|
+
log_level: "INFO"
|
|
240
|
+
|
|
241
|
+
# Local server configuration
|
|
242
|
+
server:
|
|
243
|
+
type: "stdio"
|
|
244
|
+
|
|
245
|
+
# Local tools
|
|
246
|
+
mcp_servers:
|
|
247
|
+
local_tools:
|
|
248
|
+
location: "./my_tools"
|
|
249
|
+
tools:
|
|
250
|
+
module: "my_tools.tools"
|
|
251
|
+
|
|
252
|
+
# Proxy configuration
|
|
253
|
+
proxy:
|
|
254
|
+
enabled: true
|
|
255
|
+
namespace: "proxy"
|
|
256
|
+
openai_compatible: false
|
|
257
|
+
|
|
258
|
+
# Remote servers
|
|
259
|
+
mcp_servers:
|
|
260
|
+
time:
|
|
261
|
+
type: "stdio"
|
|
262
|
+
command: "uvx"
|
|
263
|
+
args: ["mcp-server-time", "--local-timezone", "America/New_York"]
|
|
264
|
+
|
|
265
|
+
echo:
|
|
266
|
+
type: "stdio"
|
|
267
|
+
command: "python"
|
|
268
|
+
args: ["examples/echo_server/main.py"]
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Start the combined server:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
uv run -m chuk_mcp_runtime.main --config combined_config.yaml
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Command Reference
|
|
278
|
+
|
|
279
|
+
### chuk-mcp-proxy
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
chuk-mcp-proxy [OPTIONS]
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Options:
|
|
286
|
+
- `--config FILE`: YAML config file (optional, can be combined with flags below)
|
|
287
|
+
- `--stdio NAME`: Add a local stdio MCP server (repeatable)
|
|
288
|
+
- `--sse NAME`: Add a remote SSE MCP server (repeatable)
|
|
289
|
+
- `--command CMD`: Executable for stdio servers (default: python)
|
|
290
|
+
- `--cwd DIR`: Working directory for stdio server
|
|
291
|
+
- `--args ...`: Additional args for the stdio command
|
|
292
|
+
- `--url URL`: SSE base URL
|
|
293
|
+
- `--api-key KEY`: SSE API key (or set API_KEY env var)
|
|
294
|
+
- `--openai-compatible`: Use OpenAI-compatible tool names (underscores)
|
|
295
|
+
|
|
296
|
+
### chuk-mcp-server
|
|
297
|
+
|
|
298
|
+
```
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# CHUK MCP Runtime
|
|
2
|
+
|
|
3
|
+
CHUK MCP Runtime is a flexible framework that connects local and remote MCP (Model Context Protocol) servers. It enables you to:
|
|
4
|
+
|
|
5
|
+
- Host your own Python-based MCP tools locally with configurable timeouts
|
|
6
|
+
- Connect to remote MCP servers through stdio or SSE protocols
|
|
7
|
+
- Provide OpenAI-compatible function calling interfaces
|
|
8
|
+
- Create proxy layers that expose multiple MCP servers through a single endpoint
|
|
9
|
+
- Configure per-tool timeout settings for reliable execution
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Basic installation
|
|
15
|
+
uv pip install chuk-mcp-runtime
|
|
16
|
+
|
|
17
|
+
# With optional dependencies
|
|
18
|
+
uv pip install chuk-mcp-runtime[websocket,dev]
|
|
19
|
+
|
|
20
|
+
# Make sure to install tzdata for proper timezone support
|
|
21
|
+
uv pip install tzdata
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Core Components
|
|
25
|
+
|
|
26
|
+
The CHUK MCP Runtime consists of two main command-line tools:
|
|
27
|
+
|
|
28
|
+
1. **`chuk-mcp-server`**: Runs a complete MCP server with local tools and optional proxy support
|
|
29
|
+
2. **`chuk-mcp-proxy`**: Provides a lightweight proxy layer that wraps remote MCP servers
|
|
30
|
+
|
|
31
|
+
## Quick Start: Using the Proxy
|
|
32
|
+
|
|
33
|
+
The proxy layer allows you to expose tools from multiple MCP servers through a unified interface.
|
|
34
|
+
|
|
35
|
+
### Example 1: Basic Command Line Usage
|
|
36
|
+
|
|
37
|
+
Run an MCP proxy with a time server:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Start a proxy to the time server with dot notation (proxy.time.get_current_time)
|
|
41
|
+
uv run -m chuk_mcp_runtime.proxy_cli --stdio time --command uvx --args mcp-server-time --local-timezone America/New_York
|
|
42
|
+
|
|
43
|
+
# Start a proxy with OpenAI-compatible underscore notation (time_get_current_time)
|
|
44
|
+
uv run -m chuk_mcp_runtime.proxy_cli --stdio time --command uvx --args mcp-server-time --local-timezone America/New_York --openai-compatible
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
You can also use the `--` separator for command arguments:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv run -m chuk_mcp_runtime.proxy_cli --stdio time --command uvx -- mcp-server-time --local-timezone America/New_York
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Once the proxy is running, you'll see output like:
|
|
54
|
+
```
|
|
55
|
+
Running servers : time
|
|
56
|
+
Wrapped tools : proxy.time.get_current_time, proxy.time.convert_time
|
|
57
|
+
Smoke-test call : ...
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Example 2: Configuration File
|
|
61
|
+
|
|
62
|
+
Create a YAML configuration file:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# stdio_proxy_config.yaml
|
|
66
|
+
proxy:
|
|
67
|
+
enabled: true
|
|
68
|
+
namespace: "proxy"
|
|
69
|
+
openai_compatible: false # Use true for underscore notation (time_get_current_time)
|
|
70
|
+
|
|
71
|
+
mcp_servers:
|
|
72
|
+
time:
|
|
73
|
+
type: "stdio"
|
|
74
|
+
command: "uvx"
|
|
75
|
+
args: ["mcp-server-time", "--local-timezone", "America/New_York"]
|
|
76
|
+
|
|
77
|
+
echo:
|
|
78
|
+
type: "stdio"
|
|
79
|
+
command: "python"
|
|
80
|
+
args: ["examples/echo_server/main.py"]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Run the proxy with the config file:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
uv run -m chuk_mcp_runtime.proxy_cli --config stdio_proxy_config.yaml
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Example 3: OpenAI-Compatible Mode
|
|
90
|
+
|
|
91
|
+
To expose tools with underscore notation (compatible with OpenAI function calling):
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
# openai_compatible_config.yaml
|
|
95
|
+
proxy:
|
|
96
|
+
enabled: true
|
|
97
|
+
namespace: "proxy"
|
|
98
|
+
openai_compatible: true # Enable underscore notation
|
|
99
|
+
only_openai_tools: true # Only register underscore-notation tools
|
|
100
|
+
|
|
101
|
+
mcp_servers:
|
|
102
|
+
time:
|
|
103
|
+
type: "stdio"
|
|
104
|
+
command: "uvx"
|
|
105
|
+
args: ["mcp-server-time", "--local-timezone", "America/New_York"]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Run with:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
uv run -m chuk_mcp_runtime.proxy_cli --config openai_compatible_config.yaml
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This exposes tools like `time_get_current_time` instead of `proxy.time.get_current_time`.
|
|
115
|
+
|
|
116
|
+
## Creating Local MCP Tools
|
|
117
|
+
|
|
118
|
+
### 1. Create a custom tool
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
# my_tools/tools.py
|
|
122
|
+
from chuk_mcp_runtime.common.mcp_tool_decorator import mcp_tool
|
|
123
|
+
|
|
124
|
+
@mcp_tool(name="get_current_time", description="Get the current time in a timezone")
|
|
125
|
+
async def get_current_time(timezone: str = "UTC") -> str:
|
|
126
|
+
"""Get the current time in the specified timezone."""
|
|
127
|
+
from datetime import datetime
|
|
128
|
+
import pytz
|
|
129
|
+
|
|
130
|
+
tz = pytz.timezone(timezone)
|
|
131
|
+
now = datetime.now(tz)
|
|
132
|
+
return now.strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
133
|
+
|
|
134
|
+
@mcp_tool(name="calculate_sum", description="Calculate the sum of two numbers")
|
|
135
|
+
async def calculate_sum(a: int, b: int) -> dict:
|
|
136
|
+
"""Calculate the sum of two numbers."""
|
|
137
|
+
result = a + b
|
|
138
|
+
return {
|
|
139
|
+
"operation": "addition",
|
|
140
|
+
"operands": [a, b],
|
|
141
|
+
"result": result
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 2. Create a config file
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
# config.yaml
|
|
149
|
+
host:
|
|
150
|
+
name: "my-mcp-server"
|
|
151
|
+
log_level: "INFO"
|
|
152
|
+
|
|
153
|
+
server:
|
|
154
|
+
type: "stdio"
|
|
155
|
+
|
|
156
|
+
tools:
|
|
157
|
+
registry_module: "chuk_mcp_runtime.common.mcp_tool_decorator"
|
|
158
|
+
registry_attr: "TOOLS_REGISTRY"
|
|
159
|
+
|
|
160
|
+
mcp_servers:
|
|
161
|
+
my_tools:
|
|
162
|
+
location: "./my_tools"
|
|
163
|
+
tools:
|
|
164
|
+
module: "my_tools.tools"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 3. Run the server
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
uv run -m chuk_mcp_runtime.main --config config.yaml
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Tool Configuration
|
|
174
|
+
|
|
175
|
+
### Timeout Settings
|
|
176
|
+
|
|
177
|
+
CHUK MCP Runtime supports configurable timeouts for tools to handle long-running operations:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
# Tool with custom timeout
|
|
181
|
+
@mcp_tool(
|
|
182
|
+
name="api_call",
|
|
183
|
+
description="Call external API",
|
|
184
|
+
timeout=30 # 30 second timeout
|
|
185
|
+
)
|
|
186
|
+
async def api_call(url: str) -> dict:
|
|
187
|
+
# Implementation here
|
|
188
|
+
pass
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
# config.yaml timeout settings
|
|
193
|
+
tools:
|
|
194
|
+
timeout: 60 # Default timeout for all tools
|
|
195
|
+
tool_configs:
|
|
196
|
+
api_call:
|
|
197
|
+
timeout: 45 # Override specific tool timeout
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Environment variable: `MCP_TOOL_TIMEOUT=60`
|
|
201
|
+
|
|
202
|
+
### Advanced Tool Features
|
|
203
|
+
|
|
204
|
+
Tools support:
|
|
205
|
+
- **Type hints** for automatic schema generation
|
|
206
|
+
- **Docstring parsing** for parameter descriptions
|
|
207
|
+
- **Async execution** with timeout protection
|
|
208
|
+
- **Error handling** with graceful degradation
|
|
209
|
+
- **Session management** for stateful operations
|
|
210
|
+
|
|
211
|
+
## Running a Combined Local + Proxy Server
|
|
212
|
+
|
|
213
|
+
You can run a single server that provides both local tools and proxied remote tools:
|
|
214
|
+
|
|
215
|
+
```yaml
|
|
216
|
+
# combined_config.yaml
|
|
217
|
+
host:
|
|
218
|
+
name: "combined-server"
|
|
219
|
+
log_level: "INFO"
|
|
220
|
+
|
|
221
|
+
# Local server configuration
|
|
222
|
+
server:
|
|
223
|
+
type: "stdio"
|
|
224
|
+
|
|
225
|
+
# Local tools
|
|
226
|
+
mcp_servers:
|
|
227
|
+
local_tools:
|
|
228
|
+
location: "./my_tools"
|
|
229
|
+
tools:
|
|
230
|
+
module: "my_tools.tools"
|
|
231
|
+
|
|
232
|
+
# Proxy configuration
|
|
233
|
+
proxy:
|
|
234
|
+
enabled: true
|
|
235
|
+
namespace: "proxy"
|
|
236
|
+
openai_compatible: false
|
|
237
|
+
|
|
238
|
+
# Remote servers
|
|
239
|
+
mcp_servers:
|
|
240
|
+
time:
|
|
241
|
+
type: "stdio"
|
|
242
|
+
command: "uvx"
|
|
243
|
+
args: ["mcp-server-time", "--local-timezone", "America/New_York"]
|
|
244
|
+
|
|
245
|
+
echo:
|
|
246
|
+
type: "stdio"
|
|
247
|
+
command: "python"
|
|
248
|
+
args: ["examples/echo_server/main.py"]
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Start the combined server:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
uv run -m chuk_mcp_runtime.main --config combined_config.yaml
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Command Reference
|
|
258
|
+
|
|
259
|
+
### chuk-mcp-proxy
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
chuk-mcp-proxy [OPTIONS]
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Options:
|
|
266
|
+
- `--config FILE`: YAML config file (optional, can be combined with flags below)
|
|
267
|
+
- `--stdio NAME`: Add a local stdio MCP server (repeatable)
|
|
268
|
+
- `--sse NAME`: Add a remote SSE MCP server (repeatable)
|
|
269
|
+
- `--command CMD`: Executable for stdio servers (default: python)
|
|
270
|
+
- `--cwd DIR`: Working directory for stdio server
|
|
271
|
+
- `--args ...`: Additional args for the stdio command
|
|
272
|
+
- `--url URL`: SSE base URL
|
|
273
|
+
- `--api-key KEY`: SSE API key (or set API_KEY env var)
|
|
274
|
+
- `--openai-compatible`: Use OpenAI-compatible tool names (underscores)
|
|
275
|
+
|
|
276
|
+
### chuk-mcp-server
|
|
277
|
+
|
|
278
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "chuk-mcp-runtime"
|
|
7
|
+
version = "0.3"
|
|
8
|
+
description = "Generic CHUK MCP Runtime for MCP servers"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [{name = "Chris Hay", email = "your.email@example.com"}]
|
|
13
|
+
|
|
14
|
+
dependencies = [
|
|
15
|
+
"pydantic>=2.10.6",
|
|
16
|
+
"pyyaml>=6.0.2",
|
|
17
|
+
"pyjwt>=2.10.1",
|
|
18
|
+
"cryptography>=44.0.3",
|
|
19
|
+
"chuk-artifacts>=0.2.2",
|
|
20
|
+
"chuk-tool-processor>=0.4",
|
|
21
|
+
"mcp>=1.6.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
dev = [
|
|
26
|
+
"pytest>=8.3.5",
|
|
27
|
+
"pytest-asyncio>=0.26.0",
|
|
28
|
+
"ruff>=0.4.6",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
chuk-mcp-runtime = "chuk_mcp_runtime.main:main"
|
|
33
|
+
chuk-mcp-server = "chuk_mcp_runtime.main:main"
|
|
34
|
+
chuk-mcp-proxy = "chuk_mcp_runtime.proxy_cli:cli"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
where = ["src"]
|
|
38
|
+
include = ["chuk_mcp_runtime*"]
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.package-data]
|
|
41
|
+
chuk_mcp_runtime = [
|
|
42
|
+
"config.yaml", # default runtime config
|
|
43
|
+
"py.typed", # typing marker
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[dependency-groups]
|
|
47
|
+
dev = [
|
|
48
|
+
"mcp>=1.6.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
testpaths = ["tests"]
|
|
53
|
+
pythonpath = ["src"]
|
|
54
|
+
addopts = "-v"
|
|
55
|
+
asyncio_mode = "strict"
|
|
56
|
+
|
|
57
|
+
[tool.setuptools]
|
|
58
|
+
license-files = []
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# chuk_mcp_runtime/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
CHUK MCP Runtime Package
|
|
4
|
+
|
|
5
|
+
This package provides a runtime for CHUK MCP (Messaging Control Protocol) servers
|
|
6
|
+
with integrated proxy support for connecting to remote MCP servers.
|
|
7
|
+
|
|
8
|
+
Fully async-native implementation.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__version__ = "0.2.0"
|
|
12
|
+
|
|
13
|
+
# Import key functions from entry module
|
|
14
|
+
from chuk_mcp_runtime.entry import run_runtime, run_runtime_async, main, main_async
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
'run_runtime',
|
|
18
|
+
'run_runtime_async',
|
|
19
|
+
'main',
|
|
20
|
+
'main_async',
|
|
21
|
+
]
|