grove-mcp 1.0.3 → 1.0.6

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 (2) hide show
  1. package/index.js +67 -3
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -17,11 +17,15 @@
17
17
 
18
18
  const https = require('https');
19
19
  const readline = require('readline');
20
+ const crypto = require('crypto');
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+ const os = require('os');
20
24
 
21
25
  const HOSTNAME = 'mcp.lyra.tg';
22
26
  const SSE_PATH = '/sse';
23
27
 
24
- // Per-user downstream service tokens from the MCP config env block.
28
+ // Per-user downstream service tokens and session key from the MCP config env block.
25
29
  // Forwarded as custom headers on every POST so the K8s pod can use them
26
30
  // without storing tokens in the cluster environment.
27
31
  const TOKEN_HEADERS = {};
@@ -30,6 +34,64 @@ if (process.env.GROVE_OUTLINE_TOKEN)
30
34
  if (process.env.GROVE_MATTERMOST_TOKEN)
31
35
  TOKEN_HEADERS['Grove-Mattermost-Token'] = process.env.GROVE_MATTERMOST_TOKEN;
32
36
 
37
+ // Per-user session isolation: scopes Redis session keys so multiple users
38
+ // on the shared 3-pod cluster never overwrite each other's auth tokens.
39
+ // If GROVE_SESSION_KEY is set in the environment and is not the placeholder
40
+ // value, use it directly. Otherwise auto-generate a stable random key the
41
+ // first time and persist it to ~/.grove-mcp/session-key so that it survives
42
+ // restarts without any manual configuration.
43
+ (function resolveSessionKey() {
44
+ const PLACEHOLDER = '<your-session-key-here>';
45
+ const envKey = process.env.GROVE_SESSION_KEY;
46
+
47
+ if (envKey && envKey !== PLACEHOLDER) {
48
+ TOKEN_HEADERS['X-Grove-Session-Key'] = envKey;
49
+ return;
50
+ }
51
+
52
+ const keyFile = path.join(os.homedir(), '.grove-mcp', 'session-key');
53
+ try {
54
+ const stored = fs.readFileSync(keyFile, 'utf8').trim();
55
+ if (stored) {
56
+ TOKEN_HEADERS['X-Grove-Session-Key'] = stored;
57
+ return;
58
+ }
59
+ } catch (_) {
60
+ // File doesn't exist yet — generate below.
61
+ }
62
+
63
+ const generated = crypto.randomBytes(16).toString('hex');
64
+ try {
65
+ fs.mkdirSync(path.dirname(keyFile), { recursive: true });
66
+ fs.writeFileSync(keyFile, generated, { mode: 0o600 });
67
+ } catch (err) {
68
+ process.stderr.write(
69
+ `grove-mcp-bridge: warning: could not persist session key to ${keyFile}: ${err.message}\n`
70
+ );
71
+ }
72
+ TOKEN_HEADERS['X-Grove-Session-Key'] = generated;
73
+ })();
74
+
75
+ // Strip MCP spec fields that older Claude Desktop clients don't handle.
76
+ // FastMCP 3.x auto-generates outputSchema from Python return type annotations;
77
+ // Claude Desktop silently drops ALL tools when it sees this field (claude-code#25081).
78
+ function stripMcpCompat(raw) {
79
+ try {
80
+ const msg = JSON.parse(raw);
81
+ if (msg.result && Array.isArray(msg.result.tools)) {
82
+ msg.result.tools = msg.result.tools.map(function (t) {
83
+ // eslint-disable-next-line no-unused-vars
84
+ var outputSchema = t.outputSchema, rest = Object.assign({}, t);
85
+ delete rest.outputSchema;
86
+ return rest;
87
+ });
88
+ }
89
+ return JSON.stringify(msg);
90
+ } catch (_) {
91
+ return raw;
92
+ }
93
+ }
94
+
33
95
  let sessionPath = null;
34
96
  let affinityCookie = null; // sticky-session cookie from SSE response headers
35
97
  const pending = [];
@@ -86,8 +148,10 @@ const sseReq = https.request(
86
148
  for (const msg of pending) sendToServer(msg);
87
149
  pending.length = 0;
88
150
  } else if (eventType === 'message' && raw) {
89
- // raw is already a serialised JSON-RPC object write directly
90
- process.stdout.write(raw + '\n');
151
+ // Strip modern MCP spec fields that cause Claude Desktop to silently
152
+ // drop all tools (anthropics/claude-code#25081): FastMCP 3.x emits
153
+ // outputSchema in tools/list which Claude Desktop doesn't understand.
154
+ process.stdout.write(stripMcpCompat(raw) + '\n');
91
155
  }
92
156
 
93
157
  eventType = '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grove-mcp",
3
- "version": "1.0.3",
3
+ "version": "1.0.6",
4
4
  "description": "Claude Desktop bridge for the Grove MCP Server (Mattermost + Outline)",
5
5
  "main": "index.js",
6
6
  "bin": {