raindrop-mcp 0.0.1__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.
- raindrop_mcp-0.0.1/.gitignore +114 -0
- raindrop_mcp-0.0.1/LICENSE +21 -0
- raindrop_mcp-0.0.1/PKG-INFO +127 -0
- raindrop_mcp-0.0.1/README.md +109 -0
- raindrop_mcp-0.0.1/conformance/driver.py +306 -0
- raindrop_mcp-0.0.1/conformance/failures.txt +1 -0
- raindrop_mcp-0.0.1/conformance/mcp_e2e.py +247 -0
- raindrop_mcp-0.0.1/conformance/mcp_e2e_launcher.py +23 -0
- raindrop_mcp-0.0.1/pyproject.toml +40 -0
- raindrop_mcp-0.0.1/raindrop_mcp/__init__.py +6 -0
- raindrop_mcp-0.0.1/raindrop_mcp/py.typed +0 -0
- raindrop_mcp-0.0.1/raindrop_mcp/wrapper.py +1185 -0
- raindrop_mcp-0.0.1/tests/__init__.py +0 -0
- raindrop_mcp-0.0.1/tests/conftest.py +173 -0
- raindrop_mcp-0.0.1/tests/test_app_git.py +84 -0
- raindrop_mcp-0.0.1/tests/test_standalone_fastmcp.py +168 -0
- raindrop_mcp-0.0.1/tests/test_wrapper.py +489 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
.zodprompt-eval.sqlite
|
|
2
|
+
.topicmatch-eval.sqlite
|
|
3
|
+
# Local customer repositories and simulation workspaces
|
|
4
|
+
/.simulation-code/
|
|
5
|
+
# Logs
|
|
6
|
+
logs
|
|
7
|
+
*.log
|
|
8
|
+
npm-debug.log*
|
|
9
|
+
yarn-debug.log*
|
|
10
|
+
yarn-error.log*
|
|
11
|
+
pnpm-debug.log*
|
|
12
|
+
lerna-debug.log*
|
|
13
|
+
env/
|
|
14
|
+
temp
|
|
15
|
+
.env*
|
|
16
|
+
node_modules
|
|
17
|
+
dist
|
|
18
|
+
dist-ssr
|
|
19
|
+
*.local
|
|
20
|
+
.env
|
|
21
|
+
.yarn
|
|
22
|
+
.yarnrc.yml
|
|
23
|
+
.pnpm-store
|
|
24
|
+
package-lock.json
|
|
25
|
+
.turbo
|
|
26
|
+
*.tsbuildinfo
|
|
27
|
+
apps/**/secrets/**
|
|
28
|
+
*/*/eval-results
|
|
29
|
+
apps/dashboard/eval-results/metadata/
|
|
30
|
+
# Editor directories and files
|
|
31
|
+
.vscode/*
|
|
32
|
+
!.vscode/extensions.json
|
|
33
|
+
!.vscode/settings.json
|
|
34
|
+
!.vscode/tasks.json
|
|
35
|
+
!.vscode/launch.json
|
|
36
|
+
.idea
|
|
37
|
+
.DS_Store
|
|
38
|
+
*.suo
|
|
39
|
+
*.ntvs*
|
|
40
|
+
*.njsproj
|
|
41
|
+
*.sln
|
|
42
|
+
*.sw?
|
|
43
|
+
*bite-sight-prompts.txt
|
|
44
|
+
|
|
45
|
+
# Python files
|
|
46
|
+
*.pyc
|
|
47
|
+
__pycache__/
|
|
48
|
+
.venv/
|
|
49
|
+
|
|
50
|
+
myenv/
|
|
51
|
+
|
|
52
|
+
build/
|
|
53
|
+
*.egg-info/
|
|
54
|
+
|
|
55
|
+
.next/
|
|
56
|
+
|
|
57
|
+
.vercel
|
|
58
|
+
|
|
59
|
+
.extra
|
|
60
|
+
|
|
61
|
+
packages/scripts/local-configs
|
|
62
|
+
|
|
63
|
+
gcp-auth.json
|
|
64
|
+
|
|
65
|
+
.crush/
|
|
66
|
+
mcp.json
|
|
67
|
+
.tinyb
|
|
68
|
+
|
|
69
|
+
# Don't commit local dev setup SST state
|
|
70
|
+
infra/.sst
|
|
71
|
+
plans/
|
|
72
|
+
!apps/dawn/app/api/v1/plans/
|
|
73
|
+
.evals/
|
|
74
|
+
apps/dawn/app/api/internal/evals/
|
|
75
|
+
.sst/
|
|
76
|
+
sample-*.json
|
|
77
|
+
results.txt
|
|
78
|
+
|
|
79
|
+
# Dev logs
|
|
80
|
+
.logs/
|
|
81
|
+
tmp/
|
|
82
|
+
|
|
83
|
+
# Supabase local
|
|
84
|
+
**/supabase/.branches
|
|
85
|
+
**/supabase/.temp
|
|
86
|
+
**/supabase/seeds/
|
|
87
|
+
|
|
88
|
+
# Coding Agents
|
|
89
|
+
.claude/
|
|
90
|
+
.codex/
|
|
91
|
+
**/opencode/
|
|
92
|
+
**/opencode/**
|
|
93
|
+
|
|
94
|
+
# Bun lockfile — this repo uses pnpm
|
|
95
|
+
bun.lock
|
|
96
|
+
|
|
97
|
+
.zed/
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# Topic Doctor E2E harness artifacts (contain raw prod event text — never commit)
|
|
101
|
+
.topic-doctor-e2e/
|
|
102
|
+
apps/dawn/.code-runner/
|
|
103
|
+
apps/dawn/.convo-usecases/
|
|
104
|
+
apps/dawn/.raindrop-evals/
|
|
105
|
+
raindrop-js/
|
|
106
|
+
workshop/
|
|
107
|
+
/apps/client/src/pages/Evals/verify/
|
|
108
|
+
/apps/client/src/pages/Evals/create/verify/
|
|
109
|
+
/demo/evals-replay/presenter/
|
|
110
|
+
/apps/client/src/pages/Evals/calibrate/draftCalibrationPreview.test.ts
|
|
111
|
+
/tools/full-local/check-local-stack.test.mjs
|
|
112
|
+
|
|
113
|
+
# Generated local Workshop replay bundle
|
|
114
|
+
/.raindrop/world/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Raindrop AI
|
|
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,127 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: raindrop-mcp
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Raindrop instrumentation for Python MCP servers: one event per turn, one tool span per call, for any FastMCP / MCPServer.
|
|
5
|
+
Project-URL: Homepage, https://raindrop.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/invisible-tools/dawn
|
|
7
|
+
Author-email: Raindrop AI <sdk@raindrop.ai>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Typing :: Typed
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Requires-Dist: mcp>=1.10.0
|
|
13
|
+
Requires-Dist: raindrop-ai>=0.0.70
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# raindrop-mcp
|
|
20
|
+
|
|
21
|
+
Raindrop instrumentation for Python MCP servers. Works with the official SDK's `mcp` 1.x (`FastMCP`) and `mcp` 2.x (`MCPServer`), with the standalone [`fastmcp`](https://pypi.org/project/fastmcp/) package (2.x and 3.x+), and with any server built on them: wrap it once and every tool call lands in Raindrop as a tool span on an `mcp_activity` event. Python twin of [`@raindrop-ai/mcp`](https://github.com/raindrop-ai/raindrop-js/tree/main/packages/mcp).
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install raindrop-mcp
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import os
|
|
33
|
+
from mcp.server.fastmcp import FastMCP # mcp 2.x: from mcp.server.mcpserver import MCPServer
|
|
34
|
+
from raindrop_mcp import RaindropMcp
|
|
35
|
+
|
|
36
|
+
raindrop = RaindropMcp(api_key=os.environ.get("RAINDROP_API_KEY"))
|
|
37
|
+
mcp = raindrop.wrap(FastMCP("my-server"))
|
|
38
|
+
|
|
39
|
+
@mcp.tool()
|
|
40
|
+
def search(query: str) -> str:
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
mcp.run()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Omitting `api_key` disables shipping (a warning is emitted) but never crashes the server.
|
|
47
|
+
|
|
48
|
+
Third-party servers usually build their own `FastMCP` at import time. Wrap the class before importing them, or wrap the instance afterwards (tools already registered are instrumented too):
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from mcp.server.fastmcp import FastMCP
|
|
52
|
+
from raindrop_mcp import RaindropMcp
|
|
53
|
+
|
|
54
|
+
RaindropMcp(api_key=...).wrap(FastMCP) # every FastMCP built from now on
|
|
55
|
+
import some_mcp_server # noqa: E402
|
|
56
|
+
some_mcp_server.mcp.run()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The standalone `fastmcp` package works the same way:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from fastmcp import FastMCP
|
|
63
|
+
from raindrop_mcp import RaindropMcp
|
|
64
|
+
|
|
65
|
+
mcp = RaindropMcp(api_key=...).wrap(FastMCP("Demo"))
|
|
66
|
+
|
|
67
|
+
@mcp.tool
|
|
68
|
+
def add(a: int, b: int) -> int:
|
|
69
|
+
return a + b
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Turn tracking
|
|
73
|
+
|
|
74
|
+
MCP has no turn boundary, so by default every tool advertises an optional `_turn_id` argument and every result ends with a `_turn_id: <id>` text block. The model copies it on its next call and omits it on a new prompt, so the calls of one prompt share one event (one trace, one tool span per call). The argument is removed before your tool runs. A tool that raises still echoes the id, so the model's next call stays on the same event.
|
|
75
|
+
|
|
76
|
+
If the client sends `_meta["io.modelcontextprotocol/aiInvocation"].turnId` (SEP-2817), that id is used and nothing is echoed.
|
|
77
|
+
|
|
78
|
+
`turn_tracking=False` leaves schemas and results untouched (this also disables `intent`); every call is then its own event.
|
|
79
|
+
|
|
80
|
+
## Intent and client
|
|
81
|
+
|
|
82
|
+
Every tool also advertises an optional `_intent` argument: one sentence on what the user is trying to accomplish, which the model fills on the first call of a prompt. It is stripped before your tool runs, recorded as the `mcp.intent` property, and appended to the event input under a `Session intent:` line after `MCP session started`. Set `intent=False` to leave it out. It is free text the model wrote, so the key-based secret redaction does not apply to it; list `_intent` in `redact_arguments` to keep the field advertised but out of telemetry.
|
|
83
|
+
|
|
84
|
+
The MCP client that made the call (`clientInfo`, e.g. `claude-code 2.1.0`, `Cursor`, `codex-mcp-client`) is recorded as `mcp.client_name` / `mcp.client_version` on every span and event. It comes from the per-request `_meta` of 2026-era clients, or from the `initialize` handshake on older ones.
|
|
85
|
+
|
|
86
|
+
## Options
|
|
87
|
+
|
|
88
|
+
| Option | Default | Description |
|
|
89
|
+
| ---------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
90
|
+
| `api_key` | – | Raindrop write key. Without one, nothing ships and a warning is emitted. |
|
|
91
|
+
| `endpoint` | `https://api.raindrop.ai/v1/` | Ingest endpoint. |
|
|
92
|
+
| `project_id` | – | Raindrop project slug. |
|
|
93
|
+
| `event_name` | `mcp_activity` | Event name. |
|
|
94
|
+
| `turn_tracking` | `True` | Advertise and echo `_turn_id` to group a prompt's calls into one event. |
|
|
95
|
+
| `intent` | `True` | Advertise `_intent` so the model states the user's goal on the first call of a prompt. |
|
|
96
|
+
| `user_id` | OAuth subject → hashed bearer token → `session:<id>` → `anonymous` | Fixed id or `callable(call) -> str \| None`. Returning `None` skips the call. |
|
|
97
|
+
| `convo_id` | transport session, else the caller's UTC day | Fixed id or `callable(call) -> str \| None`. |
|
|
98
|
+
| `properties` | – | Extra event properties, a dict or `callable(call) -> dict`. |
|
|
99
|
+
| `redact_arguments` | `[]` | Argument names never captured. Keys that look like secrets (`password`, `authorization`, `api_key`, …) are always redacted. |
|
|
100
|
+
| `redact_results` | `[]` | Tools whose results are never captured, e.g. ones that return credentials. |
|
|
101
|
+
| `await_delivery` | `True` | Wait (at most 5s, off the event loop) for delivery before returning each tool result. Needed on serverless. Set `False` on long-running servers to keep tool latency unchanged. |
|
|
102
|
+
| `max_text_field_chars` | `1,000,000` | Per-field character cap for captured arguments and results. |
|
|
103
|
+
| `debug` | `False` | Log shipping details. |
|
|
104
|
+
| `app_git` | auto-detect | Application Git identity; `False` disables. |
|
|
105
|
+
| `client` | – | An existing `raindrop.Raindrop` client to ship through (multi-project setups). |
|
|
106
|
+
|
|
107
|
+
`call` passed to the callables is a `McpCallContext(tool_name, args, session_id, context)`, where `context` is the SDK's per-request `Context`.
|
|
108
|
+
|
|
109
|
+
## Event properties
|
|
110
|
+
|
|
111
|
+
`mcp.turn_id`, `mcp.tool` (the latest tool in the turn), `mcp.is_error`, `mcp.client_name` / `mcp.client_version` when the client identified itself, `mcp.intent` when the model filled `_intent`, `mcp.session_id` when the transport has one, plus anything from `properties`. Tool spans carry the arguments, the result text (or the error), `mcp.turn_id`, `mcp.session_id`, the client and the intent.
|
|
112
|
+
|
|
113
|
+
## Known limitations
|
|
114
|
+
|
|
115
|
+
- Servers built on the official SDK's `FastMCP` / `MCPServer` or on standalone `fastmcp` are supported; the low-level `mcp.server.Server` is not.
|
|
116
|
+
- On standalone `fastmcp` 2.x a tool that raises cannot echo the id (its `ToolResult` has no error form), so the model's next call starts a new event; 3.x+ echoes like the official SDK.
|
|
117
|
+
- `_turn_id` and `_intent` are added to the tool's JSON schema. A tool that declares either name itself keeps it: the field is neither advertised by this package nor stripped from the arguments for that tool, and a warning is emitted at registration since that tool then has no intent (or no turn grouping).
|
|
118
|
+
- Grouping depends on the model echoing `_turn_id`; clients that strip unknown result blocks start a new event per call.
|
|
119
|
+
- Delivery runs on the Raindrop SDK's background thread; `await_delivery` flushes before returning but cannot wait for a flush that thread already started.
|
|
120
|
+
|
|
121
|
+
## Testing
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pip install -e ".[dev]" && pytest
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The suite runs unchanged against `mcp<2` and `mcp>=2`.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# raindrop-mcp
|
|
2
|
+
|
|
3
|
+
Raindrop instrumentation for Python MCP servers. Works with the official SDK's `mcp` 1.x (`FastMCP`) and `mcp` 2.x (`MCPServer`), with the standalone [`fastmcp`](https://pypi.org/project/fastmcp/) package (2.x and 3.x+), and with any server built on them: wrap it once and every tool call lands in Raindrop as a tool span on an `mcp_activity` event. Python twin of [`@raindrop-ai/mcp`](https://github.com/raindrop-ai/raindrop-js/tree/main/packages/mcp).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install raindrop-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import os
|
|
15
|
+
from mcp.server.fastmcp import FastMCP # mcp 2.x: from mcp.server.mcpserver import MCPServer
|
|
16
|
+
from raindrop_mcp import RaindropMcp
|
|
17
|
+
|
|
18
|
+
raindrop = RaindropMcp(api_key=os.environ.get("RAINDROP_API_KEY"))
|
|
19
|
+
mcp = raindrop.wrap(FastMCP("my-server"))
|
|
20
|
+
|
|
21
|
+
@mcp.tool()
|
|
22
|
+
def search(query: str) -> str:
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
mcp.run()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Omitting `api_key` disables shipping (a warning is emitted) but never crashes the server.
|
|
29
|
+
|
|
30
|
+
Third-party servers usually build their own `FastMCP` at import time. Wrap the class before importing them, or wrap the instance afterwards (tools already registered are instrumented too):
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from mcp.server.fastmcp import FastMCP
|
|
34
|
+
from raindrop_mcp import RaindropMcp
|
|
35
|
+
|
|
36
|
+
RaindropMcp(api_key=...).wrap(FastMCP) # every FastMCP built from now on
|
|
37
|
+
import some_mcp_server # noqa: E402
|
|
38
|
+
some_mcp_server.mcp.run()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The standalone `fastmcp` package works the same way:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from fastmcp import FastMCP
|
|
45
|
+
from raindrop_mcp import RaindropMcp
|
|
46
|
+
|
|
47
|
+
mcp = RaindropMcp(api_key=...).wrap(FastMCP("Demo"))
|
|
48
|
+
|
|
49
|
+
@mcp.tool
|
|
50
|
+
def add(a: int, b: int) -> int:
|
|
51
|
+
return a + b
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Turn tracking
|
|
55
|
+
|
|
56
|
+
MCP has no turn boundary, so by default every tool advertises an optional `_turn_id` argument and every result ends with a `_turn_id: <id>` text block. The model copies it on its next call and omits it on a new prompt, so the calls of one prompt share one event (one trace, one tool span per call). The argument is removed before your tool runs. A tool that raises still echoes the id, so the model's next call stays on the same event.
|
|
57
|
+
|
|
58
|
+
If the client sends `_meta["io.modelcontextprotocol/aiInvocation"].turnId` (SEP-2817), that id is used and nothing is echoed.
|
|
59
|
+
|
|
60
|
+
`turn_tracking=False` leaves schemas and results untouched (this also disables `intent`); every call is then its own event.
|
|
61
|
+
|
|
62
|
+
## Intent and client
|
|
63
|
+
|
|
64
|
+
Every tool also advertises an optional `_intent` argument: one sentence on what the user is trying to accomplish, which the model fills on the first call of a prompt. It is stripped before your tool runs, recorded as the `mcp.intent` property, and appended to the event input under a `Session intent:` line after `MCP session started`. Set `intent=False` to leave it out. It is free text the model wrote, so the key-based secret redaction does not apply to it; list `_intent` in `redact_arguments` to keep the field advertised but out of telemetry.
|
|
65
|
+
|
|
66
|
+
The MCP client that made the call (`clientInfo`, e.g. `claude-code 2.1.0`, `Cursor`, `codex-mcp-client`) is recorded as `mcp.client_name` / `mcp.client_version` on every span and event. It comes from the per-request `_meta` of 2026-era clients, or from the `initialize` handshake on older ones.
|
|
67
|
+
|
|
68
|
+
## Options
|
|
69
|
+
|
|
70
|
+
| Option | Default | Description |
|
|
71
|
+
| ---------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `api_key` | – | Raindrop write key. Without one, nothing ships and a warning is emitted. |
|
|
73
|
+
| `endpoint` | `https://api.raindrop.ai/v1/` | Ingest endpoint. |
|
|
74
|
+
| `project_id` | – | Raindrop project slug. |
|
|
75
|
+
| `event_name` | `mcp_activity` | Event name. |
|
|
76
|
+
| `turn_tracking` | `True` | Advertise and echo `_turn_id` to group a prompt's calls into one event. |
|
|
77
|
+
| `intent` | `True` | Advertise `_intent` so the model states the user's goal on the first call of a prompt. |
|
|
78
|
+
| `user_id` | OAuth subject → hashed bearer token → `session:<id>` → `anonymous` | Fixed id or `callable(call) -> str \| None`. Returning `None` skips the call. |
|
|
79
|
+
| `convo_id` | transport session, else the caller's UTC day | Fixed id or `callable(call) -> str \| None`. |
|
|
80
|
+
| `properties` | – | Extra event properties, a dict or `callable(call) -> dict`. |
|
|
81
|
+
| `redact_arguments` | `[]` | Argument names never captured. Keys that look like secrets (`password`, `authorization`, `api_key`, …) are always redacted. |
|
|
82
|
+
| `redact_results` | `[]` | Tools whose results are never captured, e.g. ones that return credentials. |
|
|
83
|
+
| `await_delivery` | `True` | Wait (at most 5s, off the event loop) for delivery before returning each tool result. Needed on serverless. Set `False` on long-running servers to keep tool latency unchanged. |
|
|
84
|
+
| `max_text_field_chars` | `1,000,000` | Per-field character cap for captured arguments and results. |
|
|
85
|
+
| `debug` | `False` | Log shipping details. |
|
|
86
|
+
| `app_git` | auto-detect | Application Git identity; `False` disables. |
|
|
87
|
+
| `client` | – | An existing `raindrop.Raindrop` client to ship through (multi-project setups). |
|
|
88
|
+
|
|
89
|
+
`call` passed to the callables is a `McpCallContext(tool_name, args, session_id, context)`, where `context` is the SDK's per-request `Context`.
|
|
90
|
+
|
|
91
|
+
## Event properties
|
|
92
|
+
|
|
93
|
+
`mcp.turn_id`, `mcp.tool` (the latest tool in the turn), `mcp.is_error`, `mcp.client_name` / `mcp.client_version` when the client identified itself, `mcp.intent` when the model filled `_intent`, `mcp.session_id` when the transport has one, plus anything from `properties`. Tool spans carry the arguments, the result text (or the error), `mcp.turn_id`, `mcp.session_id`, the client and the intent.
|
|
94
|
+
|
|
95
|
+
## Known limitations
|
|
96
|
+
|
|
97
|
+
- Servers built on the official SDK's `FastMCP` / `MCPServer` or on standalone `fastmcp` are supported; the low-level `mcp.server.Server` is not.
|
|
98
|
+
- On standalone `fastmcp` 2.x a tool that raises cannot echo the id (its `ToolResult` has no error form), so the model's next call starts a new event; 3.x+ echoes like the official SDK.
|
|
99
|
+
- `_turn_id` and `_intent` are added to the tool's JSON schema. A tool that declares either name itself keeps it: the field is neither advertised by this package nor stripped from the arguments for that tool, and a warning is emitted at registration since that tool then has no intent (or no turn grouping).
|
|
100
|
+
- Grouping depends on the model echoing `_turn_id`; clients that strip unknown result blocks start a new event per call.
|
|
101
|
+
- Delivery runs on the Raindrop SDK's background thread; `await_delivery` flushes before returning but cannot wait for a flush that thread already started.
|
|
102
|
+
|
|
103
|
+
## Testing
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pip install -e ".[dev]" && pytest
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The suite runs unchanged against `mcp<2` and `mcp>=2`.
|