@strixgov/mcp-proxy 0.2.0 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.1]
11
+
12
+ ### Fixed
13
+ - `npm test` in the published package crashed with a missing
14
+ `scripts/preflight.mjs` (the tarball did not ship `scripts/`). `test` now runs
15
+ `scripts/run-tests.mjs`, which runs the suite in a source checkout and, in an
16
+ installed copy, exits non-zero with an explanation rather than crashing or
17
+ passing on zero tests. Reported by an external tester.
18
+
10
19
  ## [0.2.0]
11
20
 
12
21
  Minor, not a patch: this release carries the already-merged shadow-discovery
@@ -0,0 +1,58 @@
1
+ # Govern YouSpot with the Strix MCP proxy
2
+
3
+ This example uses YouSpot's official stdio bridge as the upstream server:
4
+
5
+ `MCP host -> @strixgov/mcp-proxy -> @youspot/mcp -> https://youspot.com/mcp/v1`
6
+
7
+ No YouSpot tool implementation is changed.
8
+
9
+ ## 1. Provide the YouSpot token to the host environment
10
+
11
+ ```bash
12
+ export YOUSPOT_TOKEN="..."
13
+ ```
14
+
15
+ `@youspot/mcp` requires the token for `tools/call`. The example config intentionally does not store it; the proxy passes the process environment through to the upstream when `upstream.env` is omitted.
16
+
17
+ ## 2. Point the MCP host at Strix
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "youspot-governed": {
23
+ "command": "npx",
24
+ "args": [
25
+ "-y",
26
+ "@strixgov/mcp-proxy",
27
+ "--config",
28
+ "/absolute/path/to/youspot-proxy-config.json"
29
+ ]
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ The same shape works in stdio-capable hosts that accept command/args MCP definitions. Use the host's normal secure environment mechanism for `YOUSPOT_TOKEN`.
36
+
37
+ ## 3. What the starter policy does
38
+
39
+ - reviewed read tools -> explicit ALLOW rules
40
+ - every other LOW/MEDIUM/HIGH tool -> APPROVAL_REQUIRED
41
+ - CRITICAL -> DENY
42
+ - policy default -> DENY
43
+
44
+ The explicit rules are intentional. `@strixgov/mcp-proxy` documents name heuristics as a discovery fallback, not a production security boundary. A YouSpot tool added after this example was reviewed therefore does not inherit an automatic LOW/ALLOW path.
45
+ - bundled approval channel -> disabled
46
+
47
+ With approval disabled, any call that evaluates to `APPROVAL_REQUIRED` is refused rather than auto-approved. Configure a separate approver only when the response channel is not writable by the acting agent.
48
+
49
+ ## 4. Verify
50
+
51
+ ```bash
52
+ npx @strixgov/verifier chain ~/.strix-mcp-proxy/youspot/receipts.jsonl \
53
+ --jwks ~/.strix-mcp-proxy/youspot/keys/public-jwk.json
54
+ ```
55
+
56
+ ## Coverage boundary
57
+
58
+ Only traffic routed through this local proxy is governed. Direct `https://youspot.com/mcp/v1` connections remain outside this example. Remote-HTTP-only clients require a hosted Strix gateway.
@@ -0,0 +1,236 @@
1
+ {
2
+ "serverId": "youspot",
3
+ "upstream": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "@youspot/mcp"
8
+ ]
9
+ },
10
+ "capabilities": [
11
+ {
12
+ "id": "mcp.youspot.get_graph_object",
13
+ "name": "get_graph_object",
14
+ "risk": "LOW",
15
+ "mode": "READ",
16
+ "description": "Read one object from the YouSpot graph."
17
+ },
18
+ {
19
+ "id": "mcp.youspot.list_graph_objects",
20
+ "name": "list_graph_objects",
21
+ "risk": "LOW",
22
+ "mode": "READ",
23
+ "description": "List objects from the YouSpot graph."
24
+ },
25
+ {
26
+ "id": "mcp.youspot.search_graph_objects",
27
+ "name": "search_graph_objects",
28
+ "risk": "LOW",
29
+ "mode": "READ",
30
+ "description": "Search the YouSpot graph."
31
+ },
32
+ {
33
+ "id": "mcp.youspot.get_gmail_message",
34
+ "name": "get_gmail_message",
35
+ "risk": "LOW",
36
+ "mode": "READ",
37
+ "description": "Read one Gmail message."
38
+ },
39
+ {
40
+ "id": "mcp.youspot.search_gmail_messages",
41
+ "name": "search_gmail_messages",
42
+ "risk": "LOW",
43
+ "mode": "READ",
44
+ "description": "Search connected Gmail mailboxes."
45
+ },
46
+ {
47
+ "id": "mcp.youspot.list_gmail_labels",
48
+ "name": "list_gmail_labels",
49
+ "risk": "LOW",
50
+ "mode": "READ",
51
+ "description": "List Gmail labels."
52
+ },
53
+ {
54
+ "id": "mcp.youspot.get_calendar_events",
55
+ "name": "get_calendar_events",
56
+ "risk": "LOW",
57
+ "mode": "READ",
58
+ "description": "Read calendar events."
59
+ },
60
+ {
61
+ "id": "mcp.youspot.list_google_calendars",
62
+ "name": "list_google_calendars",
63
+ "risk": "LOW",
64
+ "mode": "READ",
65
+ "description": "List Google calendars."
66
+ },
67
+ {
68
+ "id": "mcp.youspot.list_slack_channels",
69
+ "name": "list_slack_channels",
70
+ "risk": "LOW",
71
+ "mode": "READ",
72
+ "description": "List Slack channels known to YouSpot."
73
+ },
74
+ {
75
+ "id": "mcp.youspot.get_slack_thread",
76
+ "name": "get_slack_thread",
77
+ "risk": "LOW",
78
+ "mode": "READ",
79
+ "description": "Read a saved Slack thread."
80
+ },
81
+ {
82
+ "id": "mcp.youspot.search_slack_messages",
83
+ "name": "search_slack_messages",
84
+ "risk": "LOW",
85
+ "mode": "READ",
86
+ "description": "Search saved Slack messages."
87
+ },
88
+ {
89
+ "id": "mcp.youspot.list_integrations",
90
+ "name": "list_integrations",
91
+ "risk": "LOW",
92
+ "mode": "READ",
93
+ "description": "List connected integrations."
94
+ },
95
+ {
96
+ "id": "mcp.youspot.add_slack_reaction",
97
+ "name": "add_slack_reaction",
98
+ "risk": "MEDIUM",
99
+ "mode": "WRITE",
100
+ "description": "Add a reaction to a Slack message."
101
+ },
102
+ {
103
+ "id": "mcp.youspot.archive_gmail_message",
104
+ "name": "archive_gmail_message",
105
+ "risk": "MEDIUM",
106
+ "mode": "WRITE",
107
+ "description": "Archive a Gmail message."
108
+ },
109
+ {
110
+ "id": "mcp.youspot.connect_graph_objects",
111
+ "name": "connect_graph_objects",
112
+ "risk": "MEDIUM",
113
+ "mode": "WRITE",
114
+ "description": "Create a directed edge between graph objects."
115
+ },
116
+ {
117
+ "id": "mcp.youspot.create_gmail_draft",
118
+ "name": "create_gmail_draft",
119
+ "risk": "MEDIUM",
120
+ "mode": "WRITE",
121
+ "description": "Create a Gmail draft."
122
+ },
123
+ {
124
+ "id": "mcp.youspot.create_graph_object",
125
+ "name": "create_graph_object",
126
+ "risk": "MEDIUM",
127
+ "mode": "WRITE",
128
+ "description": "Create a YouSpot graph object."
129
+ },
130
+ {
131
+ "id": "mcp.youspot.disconnect_graph_objects",
132
+ "name": "disconnect_graph_objects",
133
+ "risk": "MEDIUM",
134
+ "mode": "WRITE",
135
+ "description": "Remove a graph-object edge."
136
+ },
137
+ {
138
+ "id": "mcp.youspot.set_follow_up",
139
+ "name": "set_follow_up",
140
+ "risk": "MEDIUM",
141
+ "mode": "WRITE",
142
+ "description": "Create a dated follow-up fact."
143
+ },
144
+ {
145
+ "id": "mcp.youspot.set_notification_emails",
146
+ "name": "set_notification_emails",
147
+ "risk": "MEDIUM",
148
+ "mode": "WRITE",
149
+ "description": "Change YouSpot notification-email settings."
150
+ },
151
+ {
152
+ "id": "mcp.youspot.update_graph_object",
153
+ "name": "update_graph_object",
154
+ "risk": "MEDIUM",
155
+ "mode": "WRITE",
156
+ "description": "Update fields on a graph object."
157
+ },
158
+ {
159
+ "id": "mcp.youspot.create_calendar_event",
160
+ "name": "create_calendar_event",
161
+ "risk": "HIGH",
162
+ "mode": "WRITE",
163
+ "description": "Create or queue a calendar event."
164
+ },
165
+ {
166
+ "id": "mcp.youspot.send_email",
167
+ "name": "send_email",
168
+ "risk": "HIGH",
169
+ "mode": "WRITE",
170
+ "description": "Send email to the signed-in user's own address."
171
+ },
172
+ {
173
+ "id": "mcp.youspot.send_slack_message",
174
+ "name": "send_slack_message",
175
+ "risk": "HIGH",
176
+ "mode": "WRITE",
177
+ "description": "Post a Slack message or DM."
178
+ },
179
+ {
180
+ "id": "mcp.youspot.send_text_to_user",
181
+ "name": "send_text_to_user",
182
+ "risk": "HIGH",
183
+ "mode": "WRITE",
184
+ "description": "Send an iMessage/SMS to the user's verified phone."
185
+ },
186
+ {
187
+ "id": "mcp.youspot.delete_graph_object",
188
+ "name": "delete_graph_object",
189
+ "risk": "CRITICAL",
190
+ "mode": "WRITE",
191
+ "description": "Delete one graph object."
192
+ },
193
+ {
194
+ "id": "mcp.youspot.delete_graph_objects",
195
+ "name": "delete_graph_objects",
196
+ "risk": "CRITICAL",
197
+ "mode": "WRITE",
198
+ "description": "Delete all graph objects of one type."
199
+ },
200
+ {
201
+ "id": "mcp.youspot.disconnect_integration",
202
+ "name": "disconnect_integration",
203
+ "risk": "CRITICAL",
204
+ "mode": "WRITE",
205
+ "description": "Disconnect an integration; may delete synced records."
206
+ }
207
+ ],
208
+ "policy": {
209
+ "rules": {
210
+ "mcp.youspot.get_graph_object": "ALLOW",
211
+ "mcp.youspot.list_graph_objects": "ALLOW",
212
+ "mcp.youspot.search_graph_objects": "ALLOW",
213
+ "mcp.youspot.get_gmail_message": "ALLOW",
214
+ "mcp.youspot.search_gmail_messages": "ALLOW",
215
+ "mcp.youspot.list_gmail_labels": "ALLOW",
216
+ "mcp.youspot.get_calendar_events": "ALLOW",
217
+ "mcp.youspot.list_google_calendars": "ALLOW",
218
+ "mcp.youspot.list_slack_channels": "ALLOW",
219
+ "mcp.youspot.get_slack_thread": "ALLOW",
220
+ "mcp.youspot.search_slack_messages": "ALLOW",
221
+ "mcp.youspot.list_integrations": "ALLOW"
222
+ },
223
+ "riskOverrides": {
224
+ "LOW": "APPROVAL_REQUIRED",
225
+ "MEDIUM": "APPROVAL_REQUIRED",
226
+ "HIGH": "APPROVAL_REQUIRED",
227
+ "CRITICAL": "DENY"
228
+ },
229
+ "default": "DENY"
230
+ },
231
+ "approval": {
232
+ "enabled": false
233
+ },
234
+ "storagePath": "~/.strix-mcp-proxy/youspot",
235
+ "keyPath": "~/.strix-mcp-proxy/youspot/keys"
236
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strixgov/mcp-proxy",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Strix MCP Proxy — the distribution wedge for governed agent tool execution. Point your MCP client at the proxy instead of the underlying server; every callTool is intercepted, evaluated against policy, and emits a signed Ed25519 receipt. Designed so Mode 3 (capability-enforced) is the v0.2.0 upgrade path, not a rewrite.",
5
5
  "license": "Elastic-2.0",
6
6
  "type": "module",
@@ -20,6 +20,9 @@
20
20
  "@strixgov/mcp-adapter": "^0.1.0",
21
21
  "@strixgov/tool-gateway": "^0.5.0"
22
22
  },
23
+ "devDependencies": {
24
+ "zod": "^3.25.76"
25
+ },
23
26
  "keywords": [
24
27
  "strix",
25
28
  "mcp",
@@ -40,6 +43,7 @@
40
43
  "files": [
41
44
  "src/",
42
45
  "bin/",
46
+ "scripts/run-tests.mjs",
43
47
  "examples/",
44
48
  "README.md",
45
49
  "CHANGELOG.md",
@@ -54,6 +58,6 @@
54
58
  "node": ">=18.0.0"
55
59
  },
56
60
  "scripts": {
57
- "test": "node scripts/preflight.mjs && node --test"
61
+ "test": "node scripts/run-tests.mjs"
58
62
  }
59
63
  }
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `npm test` entry point for @strixgov/mcp-proxy.
4
+ *
5
+ * The suite needs a source checkout (devDependencies and pnpm workspace links),
6
+ * so the npm tarball does not ship test/ or scripts/preflight.mjs. Previously
7
+ * `test` called preflight.mjs directly, so `npm test` in an installed copy died
8
+ * with "Cannot find module scripts/preflight.mjs". This wrapper fails closed
9
+ * with an explanation instead: it never exits 0 having run zero tests.
10
+ */
11
+ import { existsSync } from "node:fs";
12
+ import { spawnSync } from "node:child_process";
13
+ import { fileURLToPath } from "node:url";
14
+
15
+ const root = fileURLToPath(new URL("..", import.meta.url));
16
+ const testDir = fileURLToPath(new URL("../test", import.meta.url));
17
+ const preflight = fileURLToPath(new URL("./preflight.mjs", import.meta.url));
18
+
19
+ if (!existsSync(testDir) || !existsSync(preflight)) {
20
+ process.stderr.write(
21
+ [
22
+ "",
23
+ " @strixgov/mcp-proxy: no tests to run here.",
24
+ "",
25
+ " The test suite is not included in the published npm package.",
26
+ " Run it from a source checkout of https://github.com/Strixgov/strix:",
27
+ "",
28
+ " pnpm install",
29
+ " pnpm --dir packages/strixgov-mcp-proxy test",
30
+ "",
31
+ " Exiting non-zero on purpose: zero tests run must not read as a pass.",
32
+ "",
33
+ ].join("\n"),
34
+ );
35
+ process.exit(1);
36
+ }
37
+
38
+ for (const args of [[preflight], ["--test"]]) {
39
+ const r = spawnSync(process.execPath, args, { cwd: root, stdio: "inherit" });
40
+ if (r.status !== 0) process.exit(r.status ?? 1);
41
+ }