@contextstream/mcp-server 0.3.69 → 0.3.71

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/dist/index.js +391 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7556,7 +7556,7 @@ var CONTEXTSTREAM_RULES_MINIMAL = `
7556
7556
 
7557
7557
  ### Tool Catalog
7558
7558
 
7559
- By default, the MCP server exposes the **standard** toolset (~50 tools). To expose fewer tools, set \`CONTEXTSTREAM_TOOLSET=light\`. To expose everything (~86 tools), set \`CONTEXTSTREAM_TOOLSET=complete\` in your MCP config:
7559
+ By default, the MCP server exposes the **standard** toolset (~58 tools). To expose fewer tools, set \`CONTEXTSTREAM_TOOLSET=light\`. To expose everything (~86 tools), set \`CONTEXTSTREAM_TOOLSET=complete\` in your MCP config:
7560
7560
 
7561
7561
  \`\`\`json
7562
7562
  {
@@ -8083,10 +8083,11 @@ var LIGHT_TOOLSET = /* @__PURE__ */ new Set([
8083
8083
  "mcp_server_version"
8084
8084
  ]);
8085
8085
  var STANDARD_TOOLSET = /* @__PURE__ */ new Set([
8086
- // Core session tools (13)
8086
+ // Core session tools (14)
8087
8087
  "session_init",
8088
8088
  "session_tools",
8089
8089
  "context_smart",
8090
+ "context_feedback",
8090
8091
  "session_summary",
8091
8092
  "session_capture",
8092
8093
  "session_capture_lesson",
@@ -8127,9 +8128,15 @@ var STANDARD_TOOLSET = /* @__PURE__ */ new Set([
8127
8128
  "memory_delete_event",
8128
8129
  "memory_timeline",
8129
8130
  "memory_summary",
8130
- // Memory nodes (2)
8131
+ // Memory nodes (6) - full CRUD for memory hygiene
8131
8132
  "memory_create_node",
8132
8133
  "memory_list_nodes",
8134
+ "memory_get_node",
8135
+ "memory_update_node",
8136
+ "memory_delete_node",
8137
+ "memory_supersede_node",
8138
+ // Memory distillation (1)
8139
+ "memory_distill_event",
8133
8140
  // Knowledge graph analysis (8)
8134
8141
  "graph_related",
8135
8142
  "graph_decisions",
@@ -8155,6 +8162,126 @@ var STANDARD_TOOLSET = /* @__PURE__ */ new Set([
8155
8162
  "auth_me",
8156
8163
  "mcp_server_version"
8157
8164
  ]);
8165
+ var SLACK_TOOLS = /* @__PURE__ */ new Set([
8166
+ "slack_stats",
8167
+ "slack_channels",
8168
+ "slack_search",
8169
+ "slack_discussions",
8170
+ "slack_activity",
8171
+ "slack_contributors",
8172
+ "slack_knowledge",
8173
+ "slack_summary",
8174
+ "slack_sync_users"
8175
+ ]);
8176
+ var GITHUB_TOOLS = /* @__PURE__ */ new Set([
8177
+ "github_stats",
8178
+ "github_repos",
8179
+ "github_search",
8180
+ "github_issues",
8181
+ "github_activity",
8182
+ "github_contributors",
8183
+ "github_knowledge",
8184
+ "github_summary"
8185
+ ]);
8186
+ var CROSS_INTEGRATION_TOOLS = /* @__PURE__ */ new Set([
8187
+ "integrations_status",
8188
+ "integrations_search",
8189
+ "integrations_summary",
8190
+ "integrations_knowledge"
8191
+ ]);
8192
+ var ALL_INTEGRATION_TOOLS = /* @__PURE__ */ new Set([
8193
+ ...SLACK_TOOLS,
8194
+ ...GITHUB_TOOLS,
8195
+ ...CROSS_INTEGRATION_TOOLS
8196
+ ]);
8197
+ var AUTO_HIDE_INTEGRATIONS = process.env.CONTEXTSTREAM_AUTO_HIDE_INTEGRATIONS !== "false";
8198
+ var TOKEN_SENSITIVE_CLIENTS = /* @__PURE__ */ new Set([
8199
+ "claude",
8200
+ "claude-code",
8201
+ "claude code",
8202
+ "claude desktop",
8203
+ "anthropic"
8204
+ ]);
8205
+ var AUTO_TOOLSET_ENABLED = process.env.CONTEXTSTREAM_AUTO_TOOLSET === "true";
8206
+ var SCHEMA_MODE = process.env.CONTEXTSTREAM_SCHEMA_MODE || "full";
8207
+ var COMPACT_SCHEMA_ENABLED = SCHEMA_MODE === "compact";
8208
+ function compactifyDescription(description) {
8209
+ if (!description) return "";
8210
+ let compact = description.replace(/```[\s\S]*?```/g, "");
8211
+ compact = compact.replace(/\n*Example:[\s\S]*$/i, "");
8212
+ compact = compact.replace(/\n*Access:.*$/gm, "");
8213
+ const firstLine = compact.split("\n")[0].trim();
8214
+ const firstSentence = firstLine.split(/\.(?:\s|$)/)[0];
8215
+ let result = firstSentence.length >= 20 ? firstSentence : firstLine;
8216
+ if (result.length > 120) {
8217
+ result = result.substring(0, 117) + "...";
8218
+ }
8219
+ return result;
8220
+ }
8221
+ function compactifyParamDescription(description) {
8222
+ if (!description) return void 0;
8223
+ const firstClause = description.split(/[.,;]/)[0].trim();
8224
+ if (firstClause.length > 40) {
8225
+ return firstClause.substring(0, 37) + "...";
8226
+ }
8227
+ return firstClause;
8228
+ }
8229
+ function applyCompactParamDescriptions(schema) {
8230
+ if (!(schema instanceof external_exports.ZodObject)) {
8231
+ return schema;
8232
+ }
8233
+ const shape = schema.shape;
8234
+ let changed = false;
8235
+ const nextShape = {};
8236
+ for (const [key, field] of Object.entries(shape)) {
8237
+ let nextField = field;
8238
+ const existingDescription = getDescription(field);
8239
+ if (field instanceof external_exports.ZodObject) {
8240
+ const nested = applyCompactParamDescriptions(field);
8241
+ if (nested !== field) {
8242
+ nextField = nested;
8243
+ changed = true;
8244
+ }
8245
+ }
8246
+ if (existingDescription) {
8247
+ const compact = compactifyParamDescription(existingDescription);
8248
+ if (compact && compact !== existingDescription) {
8249
+ nextField = nextField.describe(compact);
8250
+ changed = true;
8251
+ }
8252
+ }
8253
+ nextShape[key] = nextField;
8254
+ }
8255
+ if (!changed) return schema;
8256
+ let nextSchema = external_exports.object(nextShape);
8257
+ const def = schema._def;
8258
+ if (def?.catchall) nextSchema = nextSchema.catchall(def.catchall);
8259
+ if (def?.unknownKeys === "passthrough") nextSchema = nextSchema.passthrough();
8260
+ if (def?.unknownKeys === "strict") nextSchema = nextSchema.strict();
8261
+ return nextSchema;
8262
+ }
8263
+ function detectClaudeCodeFromEnv() {
8264
+ return process.env.CLAUDECODE === "1" || process.env.CLAUDE_CODE_ENTRYPOINT !== void 0 || process.env.CLAUDE_CODE === "1";
8265
+ }
8266
+ function isTokenSensitiveClient(clientName) {
8267
+ if (!clientName) return false;
8268
+ const normalized = clientName.toLowerCase().trim();
8269
+ for (const pattern of TOKEN_SENSITIVE_CLIENTS) {
8270
+ if (normalized.includes(pattern)) {
8271
+ return true;
8272
+ }
8273
+ }
8274
+ return false;
8275
+ }
8276
+ function getRecommendedToolset(clientName, fromEnv) {
8277
+ if (!AUTO_TOOLSET_ENABLED) return null;
8278
+ if (isTokenSensitiveClient(clientName) || fromEnv) {
8279
+ return LIGHT_TOOLSET;
8280
+ }
8281
+ return null;
8282
+ }
8283
+ var detectedClientInfo = null;
8284
+ var clientDetectedFromEnv = false;
8158
8285
  var TOOLSET_ALIASES = {
8159
8286
  // Light mode - minimal, fastest
8160
8287
  light: LIGHT_TOOLSET,
@@ -8167,6 +8294,8 @@ var TOOLSET_ALIASES = {
8167
8294
  complete: null,
8168
8295
  full: null,
8169
8296
  all: null
8297
+ // Auto mode - handled separately in resolveToolFilter, but listed here for reference
8298
+ // auto: STANDARD_TOOLSET (will be adjusted based on client detection)
8170
8299
  };
8171
8300
  function parseToolList(raw) {
8172
8301
  return new Set(
@@ -8179,24 +8308,41 @@ function resolveToolFilter() {
8179
8308
  const allowlist = parseToolList(allowlistRaw);
8180
8309
  if (allowlist.size === 0) {
8181
8310
  console.error("[ContextStream] CONTEXTSTREAM_TOOL_ALLOWLIST is empty; using standard toolset.");
8182
- return { allowlist: STANDARD_TOOLSET, source: "standard" };
8311
+ return { allowlist: STANDARD_TOOLSET, source: "standard", autoDetected: false };
8183
8312
  }
8184
- return { allowlist, source: "allowlist" };
8313
+ return { allowlist, source: "allowlist", autoDetected: false };
8185
8314
  }
8186
8315
  const toolsetRaw = process.env.CONTEXTSTREAM_TOOLSET;
8187
8316
  if (!toolsetRaw) {
8188
- return { allowlist: STANDARD_TOOLSET, source: "standard" };
8317
+ clientDetectedFromEnv = detectClaudeCodeFromEnv();
8318
+ if (clientDetectedFromEnv && AUTO_TOOLSET_ENABLED) {
8319
+ const recommended = getRecommendedToolset(void 0, true);
8320
+ if (recommended) {
8321
+ console.error("[ContextStream] Detected Claude Code via environment. Using light toolset for optimal token usage.");
8322
+ return { allowlist: recommended, source: "auto-claude", autoDetected: true };
8323
+ }
8324
+ }
8325
+ return { allowlist: STANDARD_TOOLSET, source: "standard", autoDetected: false };
8326
+ }
8327
+ if (toolsetRaw.trim().toLowerCase() === "auto") {
8328
+ clientDetectedFromEnv = detectClaudeCodeFromEnv();
8329
+ if (clientDetectedFromEnv) {
8330
+ console.error("[ContextStream] TOOLSET=auto: Detected Claude Code, using light toolset.");
8331
+ return { allowlist: LIGHT_TOOLSET, source: "auto-claude", autoDetected: true };
8332
+ }
8333
+ console.error("[ContextStream] TOOLSET=auto: Will adjust toolset based on MCP client (currently standard).");
8334
+ return { allowlist: STANDARD_TOOLSET, source: "auto-pending", autoDetected: true };
8189
8335
  }
8190
8336
  const key = toolsetRaw.trim().toLowerCase();
8191
8337
  if (key in TOOLSET_ALIASES) {
8192
8338
  const resolved = TOOLSET_ALIASES[key];
8193
8339
  if (resolved === null) {
8194
- return { allowlist: null, source: "complete" };
8340
+ return { allowlist: null, source: "complete", autoDetected: false };
8195
8341
  }
8196
- return { allowlist: resolved, source: key };
8342
+ return { allowlist: resolved, source: key, autoDetected: false };
8197
8343
  }
8198
8344
  console.error(`[ContextStream] Unknown CONTEXTSTREAM_TOOLSET "${toolsetRaw}". Using standard toolset.`);
8199
- return { allowlist: STANDARD_TOOLSET, source: "standard" };
8345
+ return { allowlist: STANDARD_TOOLSET, source: "standard", autoDetected: false };
8200
8346
  }
8201
8347
  function formatContent(data) {
8202
8348
  return JSON.stringify(data, null, 2);
@@ -8265,17 +8411,73 @@ function isDuplicateLessonCapture(signature) {
8265
8411
  recentLessonCaptures.set(signature, now);
8266
8412
  return false;
8267
8413
  }
8414
+ function setupClientDetection(server) {
8415
+ if (!AUTO_TOOLSET_ENABLED) {
8416
+ console.error("[ContextStream] Auto-toolset: DISABLED (set CONTEXTSTREAM_AUTO_TOOLSET=true to enable)");
8417
+ return;
8418
+ }
8419
+ if (clientDetectedFromEnv) {
8420
+ console.error("[ContextStream] Client detection: Already detected Claude Code from environment");
8421
+ return;
8422
+ }
8423
+ const lowLevelServer = server.server;
8424
+ if (!lowLevelServer) {
8425
+ console.error("[ContextStream] Warning: Could not access low-level MCP server for client detection");
8426
+ return;
8427
+ }
8428
+ lowLevelServer.oninitialized = () => {
8429
+ try {
8430
+ const clientVersion = lowLevelServer.getClientVersion?.();
8431
+ if (clientVersion) {
8432
+ detectedClientInfo = clientVersion;
8433
+ const clientName = clientVersion.name || "unknown";
8434
+ const clientVer = clientVersion.version || "unknown";
8435
+ console.error(`[ContextStream] MCP Client detected: ${clientName} v${clientVer}`);
8436
+ if (isTokenSensitiveClient(clientName)) {
8437
+ console.error("[ContextStream] Token-sensitive client detected. Consider using CONTEXTSTREAM_TOOLSET=light for optimal performance.");
8438
+ try {
8439
+ lowLevelServer.sendToolsListChanged?.();
8440
+ console.error("[ContextStream] Emitted tools/list_changed notification");
8441
+ } catch (error) {
8442
+ }
8443
+ }
8444
+ }
8445
+ } catch (error) {
8446
+ console.error("[ContextStream] Error in client detection callback:", error);
8447
+ }
8448
+ };
8449
+ console.error("[ContextStream] Client detection: Callback registered for MCP initialize");
8450
+ }
8268
8451
  function registerTools(server, client, sessionManager) {
8269
8452
  const upgradeUrl2 = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
8270
8453
  const toolFilter = resolveToolFilter();
8271
8454
  const toolAllowlist = toolFilter.allowlist;
8272
8455
  if (toolAllowlist) {
8273
8456
  const source = toolFilter.source;
8274
- const hint = source === "light" ? " Set CONTEXTSTREAM_TOOLSET=standard or complete for more tools." : source === "standard" ? " Set CONTEXTSTREAM_TOOLSET=complete for all tools." : "";
8275
- console.error(`[ContextStream] Toolset: ${source} (${toolAllowlist.size} tools).${hint}`);
8457
+ const autoNote = toolFilter.autoDetected ? " (auto-detected)" : "";
8458
+ const hint = source === "light" || source === "auto-claude" ? " Set CONTEXTSTREAM_TOOLSET=standard or complete for more tools." : source === "standard" ? " Set CONTEXTSTREAM_TOOLSET=complete for all tools." : source === "auto-pending" ? " Toolset may be adjusted when MCP client is detected." : "";
8459
+ console.error(`[ContextStream] Toolset: ${source} (${toolAllowlist.size} tools)${autoNote}.${hint}`);
8276
8460
  } else {
8277
8461
  console.error(`[ContextStream] Toolset: complete (all tools).`);
8278
8462
  }
8463
+ if (AUTO_TOOLSET_ENABLED) {
8464
+ if (clientDetectedFromEnv) {
8465
+ console.error("[ContextStream] Auto-toolset: ACTIVE (Claude Code detected from environment)");
8466
+ } else {
8467
+ console.error("[ContextStream] Auto-toolset: ENABLED (will detect MCP client on initialize)");
8468
+ }
8469
+ }
8470
+ if (AUTO_HIDE_INTEGRATIONS) {
8471
+ console.error(`[ContextStream] Integration auto-hide: ENABLED (${ALL_INTEGRATION_TOOLS.size} tools hidden until integrations connected)`);
8472
+ console.error("[ContextStream] Set CONTEXTSTREAM_AUTO_HIDE_INTEGRATIONS=false to disable.");
8473
+ } else {
8474
+ console.error("[ContextStream] Integration auto-hide: disabled");
8475
+ }
8476
+ if (COMPACT_SCHEMA_ENABLED) {
8477
+ console.error("[ContextStream] Schema mode: COMPACT (shorter descriptions, minimal params)");
8478
+ } else {
8479
+ console.error("[ContextStream] Schema mode: full (set CONTEXTSTREAM_SCHEMA_MODE=compact to reduce token overhead)");
8480
+ }
8279
8481
  const defaultProTools = /* @__PURE__ */ new Set([
8280
8482
  // AI endpoints (typically paid/credit-metered)
8281
8483
  "ai_context",
@@ -8354,6 +8556,128 @@ function registerTools(server, client, sessionManager) {
8354
8556
  ].join("\n")
8355
8557
  );
8356
8558
  }
8559
+ let integrationStatus = { checked: false, slack: false, github: false };
8560
+ let toolsListChangedNotified = false;
8561
+ async function checkIntegrationStatus(workspaceId) {
8562
+ if (integrationStatus.checked && integrationStatus.workspaceId === workspaceId) {
8563
+ return { slack: integrationStatus.slack, github: integrationStatus.github };
8564
+ }
8565
+ if (!workspaceId) {
8566
+ return { slack: false, github: false };
8567
+ }
8568
+ try {
8569
+ const status = await client.integrationsStatus({ workspace_id: workspaceId });
8570
+ const slackConnected = status?.some(
8571
+ (s) => s.provider === "slack" && s.status === "connected"
8572
+ ) ?? false;
8573
+ const githubConnected = status?.some(
8574
+ (s) => s.provider === "github" && s.status === "connected"
8575
+ ) ?? false;
8576
+ integrationStatus = {
8577
+ checked: true,
8578
+ slack: slackConnected,
8579
+ github: githubConnected,
8580
+ workspaceId
8581
+ };
8582
+ console.error(`[ContextStream] Integration status: Slack=${slackConnected}, GitHub=${githubConnected}`);
8583
+ return { slack: slackConnected, github: githubConnected };
8584
+ } catch (error) {
8585
+ console.error("[ContextStream] Failed to check integration status:", error);
8586
+ return { slack: false, github: false };
8587
+ }
8588
+ }
8589
+ function updateIntegrationStatus(status, workspaceId) {
8590
+ const hadSlack = integrationStatus.slack;
8591
+ const hadGithub = integrationStatus.github;
8592
+ integrationStatus = {
8593
+ checked: true,
8594
+ slack: status.slack,
8595
+ github: status.github,
8596
+ workspaceId
8597
+ };
8598
+ if (AUTO_HIDE_INTEGRATIONS && !toolsListChangedNotified) {
8599
+ const newlyConnected = !hadSlack && status.slack || !hadGithub && status.github;
8600
+ if (newlyConnected) {
8601
+ try {
8602
+ server.server?.sendToolsListChanged?.();
8603
+ toolsListChangedNotified = true;
8604
+ console.error("[ContextStream] Emitted tools/list_changed notification (integrations detected)");
8605
+ } catch (error) {
8606
+ console.error("[ContextStream] Failed to emit tools/list_changed:", error);
8607
+ }
8608
+ }
8609
+ }
8610
+ }
8611
+ async function gateIfIntegrationTool(toolName) {
8612
+ if (!AUTO_HIDE_INTEGRATIONS) return null;
8613
+ const requiresSlack = SLACK_TOOLS.has(toolName);
8614
+ const requiresGithub = GITHUB_TOOLS.has(toolName);
8615
+ const requiresCrossIntegration = CROSS_INTEGRATION_TOOLS.has(toolName);
8616
+ if (!requiresSlack && !requiresGithub && !requiresCrossIntegration) {
8617
+ return null;
8618
+ }
8619
+ const workspaceId = sessionManager?.getContext()?.workspace_id;
8620
+ const status = await checkIntegrationStatus(workspaceId);
8621
+ if (requiresSlack && !status.slack) {
8622
+ return errorResult(
8623
+ [
8624
+ `Integration not connected: \`${toolName}\` requires Slack integration.`,
8625
+ "",
8626
+ "To use Slack tools:",
8627
+ "1. Go to https://contextstream.io/settings/integrations",
8628
+ "2. Connect your Slack workspace",
8629
+ "3. Try this command again",
8630
+ "",
8631
+ "Note: Even without explicit Slack tools, context_smart and session_smart_search",
8632
+ "will automatically include relevant Slack context when the integration is connected."
8633
+ ].join("\n")
8634
+ );
8635
+ }
8636
+ if (requiresGithub && !status.github) {
8637
+ return errorResult(
8638
+ [
8639
+ `Integration not connected: \`${toolName}\` requires GitHub integration.`,
8640
+ "",
8641
+ "To use GitHub tools:",
8642
+ "1. Go to https://contextstream.io/settings/integrations",
8643
+ "2. Connect your GitHub repositories",
8644
+ "3. Try this command again",
8645
+ "",
8646
+ "Note: Even without explicit GitHub tools, context_smart and session_smart_search",
8647
+ "will automatically include relevant GitHub context when the integration is connected."
8648
+ ].join("\n")
8649
+ );
8650
+ }
8651
+ if (requiresCrossIntegration && !status.slack && !status.github) {
8652
+ return errorResult(
8653
+ [
8654
+ `Integration not connected: \`${toolName}\` requires at least one integration (Slack or GitHub).`,
8655
+ "",
8656
+ "To use cross-integration tools:",
8657
+ "1. Go to https://contextstream.io/settings/integrations",
8658
+ "2. Connect Slack and/or GitHub",
8659
+ "3. Try this command again"
8660
+ ].join("\n")
8661
+ );
8662
+ }
8663
+ return null;
8664
+ }
8665
+ function shouldRegisterIntegrationTool(toolName) {
8666
+ if (!AUTO_HIDE_INTEGRATIONS) return true;
8667
+ if (!integrationStatus.checked) {
8668
+ return !ALL_INTEGRATION_TOOLS.has(toolName);
8669
+ }
8670
+ if (SLACK_TOOLS.has(toolName)) {
8671
+ return integrationStatus.slack;
8672
+ }
8673
+ if (GITHUB_TOOLS.has(toolName)) {
8674
+ return integrationStatus.github;
8675
+ }
8676
+ if (CROSS_INTEGRATION_TOOLS.has(toolName)) {
8677
+ return integrationStatus.slack || integrationStatus.github;
8678
+ }
8679
+ return true;
8680
+ }
8357
8681
  async function gateIfGraphTool(toolName, input) {
8358
8682
  const requiredTier = graphToolTiers.get(toolName);
8359
8683
  if (!requiredTier) return null;
@@ -8451,18 +8775,30 @@ function registerTools(server, client, sessionManager) {
8451
8775
  if (toolAllowlist && !toolAllowlist.has(name)) {
8452
8776
  return;
8453
8777
  }
8778
+ if (!shouldRegisterIntegrationTool(name)) {
8779
+ return;
8780
+ }
8454
8781
  const accessLabel = getToolAccessLabel(name);
8455
8782
  const showUpgrade = accessLabel !== "Free";
8783
+ let finalDescription;
8784
+ let finalSchema;
8785
+ if (COMPACT_SCHEMA_ENABLED) {
8786
+ finalDescription = compactifyDescription(config.description);
8787
+ finalSchema = config.inputSchema ? applyCompactParamDescriptions(config.inputSchema) : void 0;
8788
+ } else {
8789
+ finalDescription = `${config.description}
8790
+
8791
+ Access: ${accessLabel}${showUpgrade ? ` (upgrade: ${upgradeUrl2})` : ""}`;
8792
+ finalSchema = config.inputSchema ? applyParamDescriptions(config.inputSchema) : void 0;
8793
+ }
8456
8794
  const labeledConfig = {
8457
8795
  ...config,
8458
- title: `${config.title} (${accessLabel})`,
8459
- description: `${config.description}
8460
-
8461
- Access: ${accessLabel}${showUpgrade ? ` (upgrade: ${upgradeUrl2})` : ""}`
8796
+ title: COMPACT_SCHEMA_ENABLED ? config.title : `${config.title} (${accessLabel})`,
8797
+ description: finalDescription
8462
8798
  };
8463
8799
  const annotatedConfig = {
8464
8800
  ...labeledConfig,
8465
- inputSchema: labeledConfig.inputSchema ? applyParamDescriptions(labeledConfig.inputSchema) : void 0,
8801
+ inputSchema: finalSchema,
8466
8802
  annotations: {
8467
8803
  ...inferToolAnnotations(name),
8468
8804
  ...labeledConfig.annotations
@@ -8470,8 +8806,10 @@ Access: ${accessLabel}${showUpgrade ? ` (upgrade: ${upgradeUrl2})` : ""}`
8470
8806
  };
8471
8807
  const safeHandler = async (input, extra) => {
8472
8808
  try {
8473
- const gated = await gateIfProTool(name);
8474
- if (gated) return gated;
8809
+ const proGated = await gateIfProTool(name);
8810
+ if (proGated) return proGated;
8811
+ const integrationGated = await gateIfIntegrationTool(name);
8812
+ if (integrationGated) return integrationGated;
8475
8813
  return await handler(input, extra);
8476
8814
  } catch (error) {
8477
8815
  const errorMessage = error?.message || String(error);
@@ -9679,6 +10017,21 @@ This does semantic search on the first message. You only need context_smart on s
9679
10017
  if (sessionManager) {
9680
10018
  sessionManager.markInitialized(result);
9681
10019
  }
10020
+ const workspaceId = typeof result.workspace_id === "string" ? result.workspace_id : void 0;
10021
+ if (workspaceId && AUTO_HIDE_INTEGRATIONS) {
10022
+ try {
10023
+ const intStatus = await checkIntegrationStatus(workspaceId);
10024
+ updateIntegrationStatus(intStatus, workspaceId);
10025
+ result.integrations = {
10026
+ slack_connected: intStatus.slack,
10027
+ github_connected: intStatus.github,
10028
+ auto_hide_enabled: true,
10029
+ hint: intStatus.slack || intStatus.github ? "Integration tools are now available in the tool list." : "Connect integrations at https://contextstream.io/settings/integrations to enable Slack/GitHub tools."
10030
+ };
10031
+ } catch (error) {
10032
+ console.error("[ContextStream] Failed to check integration status in session_init:", error);
10033
+ }
10034
+ }
9682
10035
  const status = typeof result.status === "string" ? result.status : "";
9683
10036
  const workspaceWarning = typeof result.workspace_warning === "string" ? result.workspace_warning : "";
9684
10037
  let text = formatContent(result);
@@ -11242,6 +11595,15 @@ Use this to verify integrations are healthy and syncing properly.`,
11242
11595
  return errorResult("Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly.");
11243
11596
  }
11244
11597
  const result = await client.integrationsStatus({ workspace_id: workspaceId });
11598
+ if (AUTO_HIDE_INTEGRATIONS) {
11599
+ const slackConnected = result?.some(
11600
+ (s) => s.provider === "slack" && s.status === "connected"
11601
+ ) ?? false;
11602
+ const githubConnected = result?.some(
11603
+ (s) => s.provider === "github" && s.status === "connected"
11604
+ ) ?? false;
11605
+ updateIntegrationStatus({ slack: slackConnected, github: githubConnected }, workspaceId);
11606
+ }
11245
11607
  if (result.length === 0) {
11246
11608
  return { content: [{ type: "text", text: "No integrations configured for this workspace." }] };
11247
11609
  }
@@ -13524,14 +13886,15 @@ Created API key: ${maskedNewKey}
13524
13886
  console.log(`
13525
13887
  Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
13526
13888
  console.log("\nMCP toolset (which tools to expose to the AI):");
13527
- console.log(" 1) Light \u2014 core session, project, and basic memory/graph tools (~30 tools)");
13528
- console.log(" Best for: faster responses, simpler workflows, resource-constrained environments");
13529
- console.log(" 2) Standard (recommended) \u2014 adds workspace, memory CRUD, graph analysis, search (~50 tools)");
13889
+ console.log(" 1) Light \u2014 core session, project, and basic memory/graph tools (~31 tools)");
13890
+ console.log(" Best for: Claude Code, faster responses, token-constrained environments");
13891
+ console.log(" 2) Standard (recommended) \u2014 adds workspace, memory CRUD, graph analysis, search (~58 tools)");
13530
13892
  console.log(" Best for: most users, full development workflow with memory + code analysis");
13531
13893
  console.log(" 3) Complete \u2014 all tools including full graph + AI, GitHub, Slack integrations (~86 tools)");
13532
13894
  console.log(" Best for: Elite users or power users needing full graph + integrations");
13533
13895
  console.log("");
13534
- console.log(" Tip: Elite users should choose Complete to unlock full graph tools (call path, path, circular, unused).");
13896
+ console.log(" Note: Slack/GitHub tools are auto-hidden until you connect those integrations.");
13897
+ console.log(" Tip: Elite users should choose Complete to unlock full graph tools.");
13535
13898
  console.log(" Tip: Change later by setting CONTEXTSTREAM_TOOLSET=light|standard|complete");
13536
13899
  const toolsetDefault = detectedGraphTier === "full" ? "3" : "2";
13537
13900
  const toolsetChoice = normalizeInput(await rl.question(`Choose [1/2/3] (default ${toolsetDefault}): `)) || toolsetDefault;
@@ -13846,8 +14209,9 @@ Applying to ${projects.length} project(s)...`);
13846
14209
  const skipped = writeActions.filter((a) => a.status === "skipped").length;
13847
14210
  const dry = writeActions.filter((a) => a.status === "dry-run").length;
13848
14211
  console.log(`Summary: ${created} created, ${updated} updated, ${appended} appended, ${skipped} skipped, ${dry} dry-run.`);
13849
- const toolsetDesc = toolset === "light" ? "~30 tools" : toolset === "complete" ? "~86 tools" : "~50 tools";
14212
+ const toolsetDesc = toolset === "light" ? "~31 tools" : toolset === "complete" ? "~86 tools" : "~58 tools";
13850
14213
  console.log(`Toolset: ${toolset} (${toolsetDesc})`);
14214
+ console.log(`Auto-hide: Slack/GitHub tools hidden until integrations connected.`);
13851
14215
  }
13852
14216
  console.log("\nNext steps:");
13853
14217
  console.log("- Restart your editor/CLI after changing MCP config or rules.");
@@ -13911,6 +14275,9 @@ Environment variables:
13911
14275
  CONTEXTSTREAM_PROJECT_ID Optional default project ID
13912
14276
  CONTEXTSTREAM_TOOLSET Tool mode: light|standard|complete (default: standard)
13913
14277
  CONTEXTSTREAM_TOOL_ALLOWLIST Optional comma-separated tool names to expose (overrides toolset)
14278
+ CONTEXTSTREAM_AUTO_TOOLSET Auto-detect client and adjust toolset (default: false)
14279
+ CONTEXTSTREAM_AUTO_HIDE_INTEGRATIONS Auto-hide Slack/GitHub tools when not connected (default: true)
14280
+ CONTEXTSTREAM_SCHEMA_MODE Schema verbosity: compact|full (default: full, compact reduces tokens)
13914
14281
  CONTEXTSTREAM_PRO_TOOLS Optional comma-separated PRO tool names (default: AI tools)
13915
14282
  CONTEXTSTREAM_UPGRADE_URL Optional upgrade URL shown for PRO tools on Free plan
13916
14283
  CONTEXTSTREAM_ENABLE_PROMPTS Enable MCP prompts list (default: true)
@@ -13960,6 +14327,7 @@ async function main() {
13960
14327
  name: "contextstream-mcp",
13961
14328
  version: VERSION
13962
14329
  });
14330
+ setupClientDetection(server);
13963
14331
  const sessionManager = new SessionManager(server, client);
13964
14332
  registerTools(server, client, sessionManager);
13965
14333
  registerResources(server, client, config.apiUrl);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contextstream/mcp-server",
3
3
  "mcpName": "io.github.contextstreamio/mcp-server",
4
- "version": "0.3.69",
4
+ "version": "0.3.71",
5
5
  "description": "MCP server exposing ContextStream public API - code context, memory, search, and AI tools for developers",
6
6
  "type": "module",
7
7
  "license": "MIT",