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.
@@ -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`.