@contextstream/mcp-server 0.3.72 → 0.4.0

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 +1468 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7662,6 +7662,13 @@ ${options.workspaceId ? `# Workspace ID: ${options.workspaceId}` : ""}
7662
7662
  content: content.trim() + "\n"
7663
7663
  };
7664
7664
  }
7665
+ function generateAllRuleFiles(options) {
7666
+ return getAvailableEditors().map((editor) => {
7667
+ const result = generateRuleContent(editor, options);
7668
+ if (!result) return null;
7669
+ return { editor, ...result };
7670
+ }).filter((r) => r !== null);
7671
+ }
7665
7672
 
7666
7673
  // src/tool-catalog.ts
7667
7674
  var TOOL_CATALOG = [
@@ -8431,6 +8438,111 @@ function getBundleInfo() {
8431
8438
  }));
8432
8439
  }
8433
8440
  var deferredTools = /* @__PURE__ */ new Map();
8441
+ var ROUTER_MODE = process.env.CONTEXTSTREAM_ROUTER_MODE === "true";
8442
+ var operationsRegistry = /* @__PURE__ */ new Map();
8443
+ function inferOperationCategory(name) {
8444
+ if (name.startsWith("session_") || name.startsWith("context_")) return "Session";
8445
+ if (name.startsWith("memory_")) return "Memory";
8446
+ if (name.startsWith("search_")) return "Search";
8447
+ if (name.startsWith("graph_")) return "Graph";
8448
+ if (name.startsWith("workspace")) return "Workspace";
8449
+ if (name.startsWith("project")) return "Project";
8450
+ if (name.startsWith("reminder")) return "Reminders";
8451
+ if (name.startsWith("slack_") || name.startsWith("github_") || name.startsWith("integration")) return "Integrations";
8452
+ if (name.startsWith("ai_")) return "AI";
8453
+ if (name === "auth_me" || name === "mcp_server_version" || name === "generate_editor_rules") return "Utility";
8454
+ if (name === "tools_enable_bundle" || name === "contextstream" || name === "contextstream_help") return "Meta";
8455
+ return "Other";
8456
+ }
8457
+ function getOperationCatalog(category) {
8458
+ const ops = {};
8459
+ for (const [name, config] of operationsRegistry) {
8460
+ const cat = config.category;
8461
+ if (category && cat.toLowerCase() !== category.toLowerCase()) continue;
8462
+ if (!ops[cat]) ops[cat] = [];
8463
+ ops[cat].push(name);
8464
+ }
8465
+ const lines = [];
8466
+ for (const [cat, names] of Object.entries(ops).sort()) {
8467
+ lines.push(`${cat}: ${names.join(", ")}`);
8468
+ }
8469
+ return lines.join("\n");
8470
+ }
8471
+ function getOperationSchema(name) {
8472
+ const op = operationsRegistry.get(name);
8473
+ if (!op) return null;
8474
+ const zodSchema = op.inputSchema;
8475
+ try {
8476
+ const shape = zodSchema?._def?.shape?.() || zodSchema?.shape || {};
8477
+ const properties = {};
8478
+ const required = [];
8479
+ for (const [key, field] of Object.entries(shape)) {
8480
+ const f = field;
8481
+ const isOptional = f?._def?.typeName === "ZodOptional" || f?.isOptional?.();
8482
+ const innerType = isOptional ? f?._def?.innerType : f;
8483
+ const typeName = innerType?._def?.typeName || "unknown";
8484
+ const description = f?._def?.description || innerType?._def?.description;
8485
+ let type = "string";
8486
+ if (typeName === "ZodNumber") type = "number";
8487
+ else if (typeName === "ZodBoolean") type = "boolean";
8488
+ else if (typeName === "ZodArray") type = "array";
8489
+ else if (typeName === "ZodObject") type = "object";
8490
+ else if (typeName === "ZodEnum") type = "enum";
8491
+ properties[key] = { type };
8492
+ if (description) properties[key].description = description;
8493
+ if (typeName === "ZodEnum") {
8494
+ properties[key].enum = innerType?._def?.values;
8495
+ }
8496
+ if (!isOptional) required.push(key);
8497
+ }
8498
+ return {
8499
+ name: op.name,
8500
+ title: op.title,
8501
+ description: op.description,
8502
+ category: op.category,
8503
+ schema: {
8504
+ type: "object",
8505
+ properties,
8506
+ required: required.length > 0 ? required : void 0
8507
+ }
8508
+ };
8509
+ } catch {
8510
+ return {
8511
+ name: op.name,
8512
+ title: op.title,
8513
+ description: op.description,
8514
+ category: op.category,
8515
+ schema: { type: "object" }
8516
+ };
8517
+ }
8518
+ }
8519
+ var OUTPUT_FORMAT = process.env.CONTEXTSTREAM_OUTPUT_FORMAT || "compact";
8520
+ var COMPACT_OUTPUT = OUTPUT_FORMAT === "compact";
8521
+ var CONSOLIDATED_MODE = process.env.CONTEXTSTREAM_CONSOLIDATED !== "false";
8522
+ var CONSOLIDATED_TOOLS = /* @__PURE__ */ new Set([
8523
+ "session_init",
8524
+ // Standalone - complex initialization
8525
+ "context_smart",
8526
+ // Standalone - called every message
8527
+ "search",
8528
+ // Consolidates search_semantic, search_hybrid, search_keyword, search_pattern
8529
+ "session",
8530
+ // Consolidates session_capture, session_recall, etc.
8531
+ "memory",
8532
+ // Consolidates memory_create_event, memory_get_event, etc.
8533
+ "graph",
8534
+ // Consolidates graph_dependencies, graph_impact, etc.
8535
+ "project",
8536
+ // Consolidates projects_list, projects_create, etc.
8537
+ "workspace",
8538
+ // Consolidates workspaces_list, workspace_associate, etc.
8539
+ "reminder",
8540
+ // Consolidates reminders_list, reminders_create, etc.
8541
+ "integration",
8542
+ // Consolidates slack_*, github_*, integrations_*
8543
+ "help"
8544
+ // Consolidates session_tools, auth_me, mcp_server_version, etc.
8545
+ ]);
8434
8546
  var TOOLSET_ALIASES = {
8435
8547
  // Light mode - minimal, fastest
8436
8548
  light: LIGHT_TOOLSET,
@@ -8493,8 +8605,9 @@ function resolveToolFilter() {
8493
8605
  console.error(`[ContextStream] Unknown CONTEXTSTREAM_TOOLSET "${toolsetRaw}". Using standard toolset.`);
8494
8606
  return { allowlist: STANDARD_TOOLSET, source: "standard", autoDetected: false };
8495
8607
  }
8496
- function formatContent(data) {
8497
- return JSON.stringify(data, null, 2);
8608
+ function formatContent(data, forceFormat) {
8609
+ const usePretty = forceFormat === "pretty" || !forceFormat && !COMPACT_OUTPUT;
8610
+ return usePretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
8498
8611
  }
8499
8612
  function toStructured(data) {
8500
8613
  if (data && typeof data === "object" && !Array.isArray(data)) {
@@ -8632,6 +8745,21 @@ function registerTools(server, client, sessionManager) {
8632
8745
  console.error(`[ContextStream] Progressive mode: ENABLED (starting with ${coreBundle.size} core tools)`);
8633
8746
  console.error("[ContextStream] Use tools_enable_bundle to unlock additional tool bundles dynamically.");
8634
8747
  }
8748
+ if (ROUTER_MODE) {
8749
+ console.error("[ContextStream] Router mode: ENABLED (all operations accessed via contextstream/contextstream_help)");
8750
+ console.error("[ContextStream] Only 2 tools registered. Use contextstream_help to see available operations.");
8751
+ }
8752
+ if (COMPACT_OUTPUT) {
8753
+ console.error("[ContextStream] Output format: COMPACT (minified JSON, ~30% fewer tokens per response)");
8754
+ } else {
8755
+ console.error("[ContextStream] Output format: pretty (set CONTEXTSTREAM_OUTPUT_FORMAT=compact for fewer tokens)");
8756
+ }
8757
+ if (CONSOLIDATED_MODE) {
8758
+ console.error(`[ContextStream] Consolidated mode: ENABLED (~${CONSOLIDATED_TOOLS.size} domain tools, ~75% token reduction)`);
8759
+ console.error("[ContextStream] Set CONTEXTSTREAM_CONSOLIDATED=false to use individual tools.");
8760
+ } else {
8761
+ console.error("[ContextStream] Consolidated mode: disabled (using individual tools)");
8762
+ }
8635
8763
  let serverRef = server;
8636
8764
  const defaultProTools = /* @__PURE__ */ new Set([
8637
8765
  // AI endpoints (typically paid/credit-metered)
@@ -9015,11 +9143,44 @@ Upgrade: ${upgradeUrl2}` : "";
9015
9143
  console.error(`[ContextStream] Bundle '${bundleName}' enabled with ${toolsEnabled} tools.`);
9016
9144
  return { success: true, message: `Enabled bundle '${bundleName}' with ${toolsEnabled} tools.`, toolsEnabled };
9017
9145
  }
9146
+ const ROUTER_DIRECT_TOOLS = /* @__PURE__ */ new Set(["contextstream", "contextstream_help"]);
9018
9147
  function registerTool(name, config, handler) {
9019
- if (toolAllowlist && !toolAllowlist.has(name)) {
9148
+ if (CONSOLIDATED_MODE && !CONSOLIDATED_TOOLS.has(name)) {
9149
+ operationsRegistry.set(name, {
9150
+ name,
9151
+ title: config.title,
9152
+ description: config.description,
9153
+ inputSchema: config.inputSchema,
9154
+ handler,
9155
+ category: inferOperationCategory(name)
9156
+ });
9157
+ return;
9158
+ }
9159
+ if (!CONSOLIDATED_MODE && toolAllowlist && !toolAllowlist.has(name)) {
9160
+ if (ROUTER_MODE && !ROUTER_DIRECT_TOOLS.has(name)) {
9161
+ operationsRegistry.set(name, {
9162
+ name,
9163
+ title: config.title,
9164
+ description: config.description,
9165
+ inputSchema: config.inputSchema,
9166
+ handler,
9167
+ category: inferOperationCategory(name)
9168
+ });
9169
+ }
9170
+ return;
9171
+ }
9172
+ if (!CONSOLIDATED_MODE && !shouldRegisterIntegrationTool(name)) {
9020
9173
  return;
9021
9174
  }
9022
- if (!shouldRegisterIntegrationTool(name)) {
9175
+ if (ROUTER_MODE && !ROUTER_DIRECT_TOOLS.has(name)) {
9176
+ operationsRegistry.set(name, {
9177
+ name,
9178
+ title: config.title,
9179
+ description: config.description,
9180
+ inputSchema: config.inputSchema,
9181
+ handler,
9182
+ category: inferOperationCategory(name)
9183
+ });
9023
9184
  return;
9024
9185
  }
9025
9186
  if (PROGRESSIVE_MODE && !isToolInEnabledBundles(name)) {
@@ -9147,6 +9308,137 @@ Example: Enable memory tools before using memory_create_event.`,
9147
9308
  return { content: [{ type: "text", text: formatContent(response) }], structuredContent: toStructured(response) };
9148
9309
  }
9149
9310
  );
9311
+ if (ROUTER_MODE) {
9312
+ serverRef.registerTool(
9313
+ "contextstream",
9314
+ {
9315
+ title: "ContextStream Operation",
9316
+ description: `Execute any ContextStream operation. Use contextstream_help to see available operations.
9317
+
9318
+ Example: contextstream({ op: "session_init", args: { folder_path: "/path/to/project" } })
9319
+
9320
+ This single tool replaces 50+ individual tools, dramatically reducing token overhead.
9321
+ All ContextStream functionality is accessible through this dispatcher.`,
9322
+ inputSchema: {
9323
+ type: "object",
9324
+ properties: {
9325
+ op: { type: "string", description: "Operation name (e.g., session_init, memory_create_event)" },
9326
+ args: { type: "object", description: "Operation arguments (varies by operation)" }
9327
+ },
9328
+ required: ["op"]
9329
+ },
9330
+ annotations: {
9331
+ readOnlyHint: false,
9332
+ destructiveHint: false,
9333
+ idempotentHint: false,
9334
+ openWorldHint: false
9335
+ }
9336
+ },
9337
+ async (input) => {
9338
+ const opName = input.op;
9339
+ const operation = operationsRegistry.get(opName);
9340
+ if (!operation) {
9341
+ const available = getOperationCatalog();
9342
+ return {
9343
+ content: [{
9344
+ type: "text",
9345
+ text: `Unknown operation: ${opName}
9346
+
9347
+ Available operations:
9348
+ ${available}
9349
+
9350
+ Use contextstream_help({ op: "operation_name" }) for details.`
9351
+ }],
9352
+ isError: true
9353
+ };
9354
+ }
9355
+ const args = input.args || {};
9356
+ const parsed = operation.inputSchema.safeParse(args);
9357
+ if (!parsed.success) {
9358
+ const schema = getOperationSchema(opName);
9359
+ return {
9360
+ content: [{
9361
+ type: "text",
9362
+ text: `Invalid arguments for ${opName}: ${parsed.error.message}
9363
+
9364
+ Expected schema:
9365
+ ${JSON.stringify(schema?.schema || {}, null, 2)}`
9366
+ }],
9367
+ isError: true
9368
+ };
9369
+ }
9370
+ try {
9371
+ return await operation.handler(parsed.data);
9372
+ } catch (error) {
9373
+ return {
9374
+ content: [{
9375
+ type: "text",
9376
+ text: `Error executing ${opName}: ${error?.message || String(error)}`
9377
+ }],
9378
+ isError: true
9379
+ };
9380
+ }
9381
+ }
9382
+ );
9383
+ serverRef.registerTool(
9384
+ "contextstream_help",
9385
+ {
9386
+ title: "ContextStream Help",
9387
+ description: `Get help on available ContextStream operations or schema for a specific operation.
9388
+
9389
+ Examples:
9390
+ - contextstream_help({}) - List all operations by category
9391
+ - contextstream_help({ op: "session_init" }) - Get schema for session_init
9392
+ - contextstream_help({ category: "Memory" }) - List memory operations only`,
9393
+ inputSchema: {
9394
+ type: "object",
9395
+ properties: {
9396
+ op: { type: "string", description: "Operation name to get schema for" },
9397
+ category: { type: "string", description: "Category to filter (Session, Memory, Search, Graph, etc.)" }
9398
+ }
9399
+ },
9400
+ annotations: {
9401
+ readOnlyHint: true,
9402
+ destructiveHint: false,
9403
+ idempotentHint: true,
9404
+ openWorldHint: false
9405
+ }
9406
+ },
9407
+ async (input) => {
9408
+ if (input.op) {
9409
+ const schema = getOperationSchema(input.op);
9410
+ if (!schema) {
9411
+ return {
9412
+ content: [{
9413
+ type: "text",
9414
+ text: `Unknown operation: ${input.op}
9415
+
9416
+ Use contextstream_help({}) to see available operations.`
9417
+ }],
9418
+ isError: true
9419
+ };
9420
+ }
9421
+ return {
9422
+ content: [{ type: "text", text: JSON.stringify(schema, null, 2) }],
9423
+ structuredContent: schema
9424
+ };
9425
+ }
9426
+ const catalog = getOperationCatalog(input.category);
9427
+ const result = {
9428
+ router_mode: true,
9429
+ total_operations: operationsRegistry.size,
9430
+ categories: catalog,
9431
+ usage: 'Call contextstream({ op: "operation_name", args: {...} }) to execute an operation.',
9432
+ hint: 'Use contextstream_help({ op: "operation_name" }) to see the schema for a specific operation.'
9433
+ };
9434
+ return {
9435
+ content: [{ type: "text", text: formatContent(result) }],
9436
+ structuredContent: toStructured(result)
9437
+ };
9438
+ }
9439
+ );
9440
+ console.error(`[ContextStream] Router mode: Registered 2 meta-tools, ${operationsRegistry.size} operations available via dispatcher.`);
9441
+ }
9150
9442
  registerTool(
9151
9443
  "workspaces_list",
9152
9444
  {
@@ -12053,6 +12345,1175 @@ Use this to remove a reminder that is no longer relevant.`,
12053
12345
  };
12054
12346
  }
12055
12347
  );
12348
+ if (CONSOLIDATED_MODE) {
12349
+ registerTool(
12350
+ "search",
12351
+ {
12352
+ title: "Search",
12353
+ description: `Search workspace memory and knowledge. Modes: semantic (meaning-based), hybrid (semantic + keyword), keyword (exact match), pattern (regex).`,
12354
+ inputSchema: external_exports.object({
12355
+ mode: external_exports.enum(["semantic", "hybrid", "keyword", "pattern"]).describe("Search mode"),
12356
+ query: external_exports.string().describe("Search query"),
12357
+ workspace_id: external_exports.string().uuid().optional(),
12358
+ project_id: external_exports.string().uuid().optional(),
12359
+ limit: external_exports.number().optional()
12360
+ })
12361
+ },
12362
+ async (input) => {
12363
+ const params = {
12364
+ query: input.query,
12365
+ workspace_id: resolveWorkspaceId(input.workspace_id),
12366
+ project_id: resolveProjectId(input.project_id),
12367
+ limit: input.limit
12368
+ };
12369
+ let result;
12370
+ switch (input.mode) {
12371
+ case "semantic":
12372
+ result = await client.searchSemantic(params);
12373
+ break;
12374
+ case "hybrid":
12375
+ result = await client.searchHybrid(params);
12376
+ break;
12377
+ case "keyword":
12378
+ result = await client.searchKeyword(params);
12379
+ break;
12380
+ case "pattern":
12381
+ result = await client.searchPattern(params);
12382
+ break;
12383
+ }
12384
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12385
+ }
12386
+ );
12387
+ registerTool(
12388
+ "session",
12389
+ {
12390
+ title: "Session",
12391
+ description: `Session management operations. Actions: capture (save decision/insight), capture_lesson (save lesson from mistake), get_lessons (retrieve lessons), recall (natural language recall), remember (quick save), user_context (get preferences), summary (workspace summary), compress (compress chat), delta (changes since timestamp), smart_search (context-enriched search), decision_trace (trace decision provenance).`,
12392
+ inputSchema: external_exports.object({
12393
+ action: external_exports.enum([
12394
+ "capture",
12395
+ "capture_lesson",
12396
+ "get_lessons",
12397
+ "recall",
12398
+ "remember",
12399
+ "user_context",
12400
+ "summary",
12401
+ "compress",
12402
+ "delta",
12403
+ "smart_search",
12404
+ "decision_trace"
12405
+ ]).describe("Action to perform"),
12406
+ workspace_id: external_exports.string().uuid().optional(),
12407
+ project_id: external_exports.string().uuid().optional(),
12408
+ // Content params
12409
+ query: external_exports.string().optional().describe("Query for recall/search/lessons/decision_trace"),
12410
+ content: external_exports.string().optional().describe("Content for capture/remember/compress"),
12411
+ title: external_exports.string().optional().describe("Title for capture/capture_lesson"),
12412
+ event_type: external_exports.enum(["decision", "preference", "insight", "task", "bug", "feature", "correction", "lesson", "warning", "frustration", "conversation"]).optional().describe("Event type for capture"),
12413
+ importance: external_exports.enum(["low", "medium", "high", "critical"]).optional(),
12414
+ tags: external_exports.array(external_exports.string()).optional(),
12415
+ // Lesson-specific
12416
+ category: external_exports.enum(["workflow", "code_quality", "verification", "communication", "project_specific"]).optional(),
12417
+ trigger: external_exports.string().optional().describe("What caused the problem"),
12418
+ impact: external_exports.string().optional().describe("What went wrong"),
12419
+ prevention: external_exports.string().optional().describe("How to prevent in future"),
12420
+ severity: external_exports.enum(["low", "medium", "high", "critical"]).optional(),
12421
+ keywords: external_exports.array(external_exports.string()).optional(),
12422
+ // Other params
12423
+ since: external_exports.string().optional().describe("ISO timestamp for delta"),
12424
+ limit: external_exports.number().optional(),
12425
+ max_tokens: external_exports.number().optional().describe("Max tokens for summary"),
12426
+ include_decisions: external_exports.boolean().optional(),
12427
+ include_related: external_exports.boolean().optional(),
12428
+ include_impact: external_exports.boolean().optional(),
12429
+ session_id: external_exports.string().optional(),
12430
+ code_refs: external_exports.array(external_exports.object({
12431
+ file_path: external_exports.string(),
12432
+ symbol_id: external_exports.string().optional(),
12433
+ symbol_name: external_exports.string().optional()
12434
+ })).optional(),
12435
+ provenance: external_exports.object({
12436
+ repo: external_exports.string().optional(),
12437
+ branch: external_exports.string().optional(),
12438
+ commit_sha: external_exports.string().optional(),
12439
+ pr_url: external_exports.string().url().optional(),
12440
+ issue_url: external_exports.string().url().optional(),
12441
+ slack_thread_url: external_exports.string().url().optional()
12442
+ }).optional()
12443
+ })
12444
+ },
12445
+ async (input) => {
12446
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
12447
+ const projectId = resolveProjectId(input.project_id);
12448
+ switch (input.action) {
12449
+ case "capture": {
12450
+ if (!input.event_type || !input.title || !input.content) {
12451
+ return errorResult("capture requires: event_type, title, content");
12452
+ }
12453
+ const result = await client.captureContext({
12454
+ workspace_id: workspaceId,
12455
+ project_id: projectId,
12456
+ event_type: input.event_type,
12457
+ title: input.title,
12458
+ content: input.content,
12459
+ importance: input.importance,
12460
+ tags: input.tags,
12461
+ session_id: input.session_id,
12462
+ code_refs: input.code_refs,
12463
+ provenance: input.provenance
12464
+ });
12465
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12466
+ }
12467
+ case "capture_lesson": {
12468
+ if (!input.title || !input.category || !input.trigger || !input.impact || !input.prevention) {
12469
+ return errorResult("capture_lesson requires: title, category, trigger, impact, prevention");
12470
+ }
12471
+ const lessonInput = {
12472
+ title: input.title,
12473
+ category: input.category,
12474
+ trigger: input.trigger,
12475
+ impact: input.impact,
12476
+ prevention: input.prevention,
12477
+ severity: input.severity || "medium",
12478
+ keywords: input.keywords,
12479
+ workspace_id: workspaceId,
12480
+ project_id: projectId
12481
+ };
12482
+ const signature = buildLessonSignature(lessonInput, workspaceId || "global", projectId);
12483
+ if (isDuplicateLessonCapture(signature)) {
12484
+ return { content: [{ type: "text", text: formatContent({ deduplicated: true, message: "Lesson already captured recently" }) }] };
12485
+ }
12486
+ const result = await client.captureLesson(lessonInput);
12487
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12488
+ }
12489
+ case "get_lessons": {
12490
+ const result = await client.getLessons({
12491
+ workspace_id: workspaceId,
12492
+ project_id: projectId,
12493
+ query: input.query,
12494
+ category: input.category,
12495
+ severity: input.severity,
12496
+ limit: input.limit
12497
+ });
12498
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12499
+ }
12500
+ case "recall": {
12501
+ if (!input.query) {
12502
+ return errorResult("recall requires: query");
12503
+ }
12504
+ const result = await client.recallContext({
12505
+ workspace_id: workspaceId,
12506
+ project_id: projectId,
12507
+ query: input.query
12508
+ });
12509
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12510
+ }
12511
+ case "remember": {
12512
+ if (!input.content) {
12513
+ return errorResult("remember requires: content");
12514
+ }
12515
+ const result = await client.rememberContext({
12516
+ workspace_id: workspaceId,
12517
+ project_id: projectId,
12518
+ content: input.content,
12519
+ importance: input.importance
12520
+ });
12521
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12522
+ }
12523
+ case "user_context": {
12524
+ const result = await client.getUserContext({ workspace_id: workspaceId });
12525
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12526
+ }
12527
+ case "summary": {
12528
+ const result = await client.getSessionSummary({
12529
+ workspace_id: workspaceId,
12530
+ project_id: projectId,
12531
+ max_tokens: input.max_tokens
12532
+ });
12533
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12534
+ }
12535
+ case "compress": {
12536
+ if (!input.content) {
12537
+ return errorResult("compress requires: content (the chat history to compress)");
12538
+ }
12539
+ const result = await client.compressSession({
12540
+ workspace_id: workspaceId,
12541
+ project_id: projectId,
12542
+ chat_history: input.content
12543
+ });
12544
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12545
+ }
12546
+ case "delta": {
12547
+ if (!input.since) {
12548
+ return errorResult("delta requires: since (ISO timestamp)");
12549
+ }
12550
+ const result = await client.getSessionDelta({
12551
+ workspace_id: workspaceId,
12552
+ project_id: projectId,
12553
+ since: input.since,
12554
+ limit: input.limit
12555
+ });
12556
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12557
+ }
12558
+ case "smart_search": {
12559
+ if (!input.query) {
12560
+ return errorResult("smart_search requires: query");
12561
+ }
12562
+ const result = await client.smartSearch({
12563
+ workspace_id: workspaceId,
12564
+ project_id: projectId,
12565
+ query: input.query,
12566
+ include_decisions: input.include_decisions,
12567
+ include_related: input.include_related
12568
+ });
12569
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12570
+ }
12571
+ case "decision_trace": {
12572
+ if (!input.query) {
12573
+ return errorResult("decision_trace requires: query");
12574
+ }
12575
+ const result = await client.decisionTrace({
12576
+ workspace_id: workspaceId,
12577
+ project_id: projectId,
12578
+ query: input.query,
12579
+ include_impact: input.include_impact,
12580
+ limit: input.limit
12581
+ });
12582
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12583
+ }
12584
+ default:
12585
+ return errorResult(`Unknown action: ${input.action}`);
12586
+ }
12587
+ }
12588
+ );
12589
+ registerTool(
12590
+ "memory",
12591
+ {
12592
+ title: "Memory",
12593
+ description: `Memory operations for events and nodes. Event actions: create_event, get_event, update_event, delete_event, list_events, distill_event. Node actions: create_node, get_node, update_node, delete_node, list_nodes, supersede_node. Query actions: search, decisions, timeline, summary.`,
12594
+ inputSchema: external_exports.object({
12595
+ action: external_exports.enum([
12596
+ "create_event",
12597
+ "get_event",
12598
+ "update_event",
12599
+ "delete_event",
12600
+ "list_events",
12601
+ "distill_event",
12602
+ "create_node",
12603
+ "get_node",
12604
+ "update_node",
12605
+ "delete_node",
12606
+ "list_nodes",
12607
+ "supersede_node",
12608
+ "search",
12609
+ "decisions",
12610
+ "timeline",
12611
+ "summary"
12612
+ ]).describe("Action to perform"),
12613
+ workspace_id: external_exports.string().uuid().optional(),
12614
+ project_id: external_exports.string().uuid().optional(),
12615
+ // ID params
12616
+ event_id: external_exports.string().uuid().optional(),
12617
+ node_id: external_exports.string().uuid().optional(),
12618
+ // Content params
12619
+ title: external_exports.string().optional(),
12620
+ content: external_exports.string().optional(),
12621
+ event_type: external_exports.string().optional(),
12622
+ node_type: external_exports.string().optional(),
12623
+ metadata: external_exports.record(external_exports.any()).optional(),
12624
+ // Query params
12625
+ query: external_exports.string().optional(),
12626
+ category: external_exports.string().optional(),
12627
+ limit: external_exports.number().optional(),
12628
+ // Node relations
12629
+ relations: external_exports.array(external_exports.object({
12630
+ type: external_exports.string(),
12631
+ target_id: external_exports.string().uuid()
12632
+ })).optional(),
12633
+ new_node_id: external_exports.string().uuid().optional().describe("For supersede: the new node ID"),
12634
+ // Provenance
12635
+ provenance: external_exports.object({
12636
+ repo: external_exports.string().optional(),
12637
+ branch: external_exports.string().optional(),
12638
+ commit_sha: external_exports.string().optional(),
12639
+ pr_url: external_exports.string().url().optional(),
12640
+ issue_url: external_exports.string().url().optional(),
12641
+ slack_thread_url: external_exports.string().url().optional()
12642
+ }).optional(),
12643
+ code_refs: external_exports.array(external_exports.object({
12644
+ file_path: external_exports.string(),
12645
+ symbol_id: external_exports.string().optional(),
12646
+ symbol_name: external_exports.string().optional()
12647
+ })).optional()
12648
+ })
12649
+ },
12650
+ async (input) => {
12651
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
12652
+ const projectId = resolveProjectId(input.project_id);
12653
+ switch (input.action) {
12654
+ case "create_event": {
12655
+ if (!input.event_type || !input.title || !input.content) {
12656
+ return errorResult("create_event requires: event_type, title, content");
12657
+ }
12658
+ const result = await client.createMemoryEvent({
12659
+ workspace_id: workspaceId,
12660
+ project_id: projectId,
12661
+ event_type: input.event_type,
12662
+ title: input.title,
12663
+ content: input.content,
12664
+ metadata: input.metadata,
12665
+ provenance: input.provenance,
12666
+ code_refs: input.code_refs
12667
+ });
12668
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12669
+ }
12670
+ case "get_event": {
12671
+ if (!input.event_id) {
12672
+ return errorResult("get_event requires: event_id");
12673
+ }
12674
+ const result = await client.getMemoryEvent(input.event_id);
12675
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12676
+ }
12677
+ case "update_event": {
12678
+ if (!input.event_id) {
12679
+ return errorResult("update_event requires: event_id");
12680
+ }
12681
+ const result = await client.updateMemoryEvent({
12682
+ event_id: input.event_id,
12683
+ title: input.title,
12684
+ content: input.content,
12685
+ metadata: input.metadata
12686
+ });
12687
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12688
+ }
12689
+ case "delete_event": {
12690
+ if (!input.event_id) {
12691
+ return errorResult("delete_event requires: event_id");
12692
+ }
12693
+ const result = await client.deleteMemoryEvent(input.event_id);
12694
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12695
+ }
12696
+ case "list_events": {
12697
+ const result = await client.listMemoryEvents({
12698
+ workspace_id: workspaceId,
12699
+ project_id: projectId,
12700
+ limit: input.limit
12701
+ });
12702
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12703
+ }
12704
+ case "distill_event": {
12705
+ if (!input.event_id) {
12706
+ return errorResult("distill_event requires: event_id");
12707
+ }
12708
+ const result = await client.distillEvent(input.event_id);
12709
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12710
+ }
12711
+ case "create_node": {
12712
+ if (!input.node_type || !input.title || !input.content) {
12713
+ return errorResult("create_node requires: node_type, title, content");
12714
+ }
12715
+ const result = await client.createKnowledgeNode({
12716
+ workspace_id: workspaceId,
12717
+ project_id: projectId,
12718
+ node_type: input.node_type,
12719
+ title: input.title,
12720
+ content: input.content,
12721
+ relations: input.relations
12722
+ });
12723
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12724
+ }
12725
+ case "get_node": {
12726
+ if (!input.node_id) {
12727
+ return errorResult("get_node requires: node_id");
12728
+ }
12729
+ const result = await client.getKnowledgeNode(input.node_id);
12730
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12731
+ }
12732
+ case "update_node": {
12733
+ if (!input.node_id) {
12734
+ return errorResult("update_node requires: node_id");
12735
+ }
12736
+ const result = await client.updateKnowledgeNode({
12737
+ node_id: input.node_id,
12738
+ title: input.title,
12739
+ content: input.content
12740
+ });
12741
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12742
+ }
12743
+ case "delete_node": {
12744
+ if (!input.node_id) {
12745
+ return errorResult("delete_node requires: node_id");
12746
+ }
12747
+ const result = await client.deleteKnowledgeNode(input.node_id);
12748
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12749
+ }
12750
+ case "list_nodes": {
12751
+ const result = await client.listKnowledgeNodes({
12752
+ workspace_id: workspaceId,
12753
+ project_id: projectId,
12754
+ limit: input.limit
12755
+ });
12756
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12757
+ }
12758
+ case "supersede_node": {
12759
+ if (!input.node_id || !input.new_node_id) {
12760
+ return errorResult("supersede_node requires: node_id, new_node_id");
12761
+ }
12762
+ const result = await client.supersedeKnowledgeNode({
12763
+ node_id: input.node_id,
12764
+ new_node_id: input.new_node_id
12765
+ });
12766
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12767
+ }
12768
+ case "search": {
12769
+ if (!input.query) {
12770
+ return errorResult("search requires: query");
12771
+ }
12772
+ const result = await client.searchMemory({
12773
+ workspace_id: workspaceId,
12774
+ project_id: projectId,
12775
+ query: input.query,
12776
+ limit: input.limit
12777
+ });
12778
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12779
+ }
12780
+ case "decisions": {
12781
+ const result = await client.memoryDecisions({
12782
+ workspace_id: workspaceId,
12783
+ project_id: projectId,
12784
+ category: input.category,
12785
+ limit: input.limit
12786
+ });
12787
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12788
+ }
12789
+ case "timeline": {
12790
+ const result = await client.memoryTimeline({
12791
+ workspace_id: workspaceId
12792
+ });
12793
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12794
+ }
12795
+ case "summary": {
12796
+ const result = await client.memorySummary({
12797
+ workspace_id: workspaceId
12798
+ });
12799
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12800
+ }
12801
+ default:
12802
+ return errorResult(`Unknown action: ${input.action}`);
12803
+ }
12804
+ }
12805
+ );
12806
+ registerTool(
12807
+ "graph",
12808
+ {
12809
+ title: "Graph",
12810
+ description: `Code graph analysis. Actions: dependencies (module deps), impact (change impact), call_path (function call path), related (related nodes), path (path between nodes), decisions (decision history), ingest (build graph), circular_dependencies, unused_code, contradictions.`,
12811
+ inputSchema: external_exports.object({
12812
+ action: external_exports.enum([
12813
+ "dependencies",
12814
+ "impact",
12815
+ "call_path",
12816
+ "related",
12817
+ "path",
12818
+ "decisions",
12819
+ "ingest",
12820
+ "circular_dependencies",
12821
+ "unused_code",
12822
+ "contradictions"
12823
+ ]).describe("Action to perform"),
12824
+ workspace_id: external_exports.string().uuid().optional(),
12825
+ project_id: external_exports.string().uuid().optional(),
12826
+ // ID params
12827
+ node_id: external_exports.string().uuid().optional().describe("For related/contradictions"),
12828
+ source_id: external_exports.string().uuid().optional().describe("For path"),
12829
+ target_id: external_exports.string().uuid().optional().describe("For path"),
12830
+ // Target specification
12831
+ target: external_exports.object({
12832
+ type: external_exports.string().describe("module|function|type|variable"),
12833
+ id: external_exports.string().describe("Element identifier")
12834
+ }).optional().describe("For dependencies/impact"),
12835
+ source: external_exports.object({
12836
+ type: external_exports.string().describe("function"),
12837
+ id: external_exports.string().describe("Function identifier")
12838
+ }).optional().describe("For call_path"),
12839
+ // Options
12840
+ max_depth: external_exports.number().optional(),
12841
+ include_transitive: external_exports.boolean().optional(),
12842
+ limit: external_exports.number().optional(),
12843
+ wait: external_exports.boolean().optional().describe("For ingest: wait for completion")
12844
+ })
12845
+ },
12846
+ async (input) => {
12847
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
12848
+ const projectId = resolveProjectId(input.project_id);
12849
+ const gatedActions = ["related", "path", "decisions", "call_path", "circular_dependencies", "unused_code", "ingest", "contradictions"];
12850
+ if (gatedActions.includes(input.action)) {
12851
+ const gate = await gateIfGraphTool(`graph_${input.action}`, input);
12852
+ if (gate) return gate;
12853
+ }
12854
+ switch (input.action) {
12855
+ case "dependencies": {
12856
+ if (!input.target) {
12857
+ return errorResult("dependencies requires: target { type, id }");
12858
+ }
12859
+ const result = await client.graphDependencies({
12860
+ target: input.target,
12861
+ max_depth: input.max_depth,
12862
+ include_transitive: input.include_transitive
12863
+ });
12864
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12865
+ }
12866
+ case "impact": {
12867
+ if (!input.target) {
12868
+ return errorResult("impact requires: target { type, id }");
12869
+ }
12870
+ const result = await client.graphImpact({
12871
+ target: input.target,
12872
+ max_depth: input.max_depth
12873
+ });
12874
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12875
+ }
12876
+ case "call_path": {
12877
+ if (!input.source || !input.target) {
12878
+ return errorResult("call_path requires: source { type, id }, target { type, id }");
12879
+ }
12880
+ const result = await client.graphCallPath({
12881
+ source: input.source,
12882
+ target: input.target,
12883
+ max_depth: input.max_depth
12884
+ });
12885
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12886
+ }
12887
+ case "related": {
12888
+ if (!input.node_id) {
12889
+ return errorResult("related requires: node_id");
12890
+ }
12891
+ const result = await client.graphRelated({
12892
+ node_id: input.node_id,
12893
+ workspace_id: workspaceId,
12894
+ project_id: projectId,
12895
+ limit: input.limit
12896
+ });
12897
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12898
+ }
12899
+ case "path": {
12900
+ if (!input.source_id || !input.target_id) {
12901
+ return errorResult("path requires: source_id, target_id");
12902
+ }
12903
+ const result = await client.graphPath({
12904
+ source_id: input.source_id,
12905
+ target_id: input.target_id,
12906
+ workspace_id: workspaceId,
12907
+ project_id: projectId
12908
+ });
12909
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12910
+ }
12911
+ case "decisions": {
12912
+ const result = await client.graphDecisions({
12913
+ workspace_id: workspaceId,
12914
+ project_id: projectId,
12915
+ limit: input.limit
12916
+ });
12917
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12918
+ }
12919
+ case "ingest": {
12920
+ if (!projectId) {
12921
+ return errorResult("ingest requires: project_id");
12922
+ }
12923
+ const result = await client.graphIngest({
12924
+ project_id: projectId,
12925
+ wait: input.wait
12926
+ });
12927
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12928
+ }
12929
+ case "circular_dependencies": {
12930
+ if (!projectId) {
12931
+ return errorResult("circular_dependencies requires: project_id");
12932
+ }
12933
+ const result = await client.findCircularDependencies(projectId);
12934
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12935
+ }
12936
+ case "unused_code": {
12937
+ if (!projectId) {
12938
+ return errorResult("unused_code requires: project_id");
12939
+ }
12940
+ const result = await client.findUnusedCode(projectId);
12941
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12942
+ }
12943
+ case "contradictions": {
12944
+ if (!input.node_id) {
12945
+ return errorResult("contradictions requires: node_id");
12946
+ }
12947
+ const result = await client.findContradictions(input.node_id);
12948
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
12949
+ }
12950
+ default:
12951
+ return errorResult(`Unknown action: ${input.action}`);
12952
+ }
12953
+ }
12954
+ );
12955
+ registerTool(
12956
+ "project",
12957
+ {
12958
+ title: "Project",
12959
+ description: `Project management. Actions: list, get, create, update, index (trigger indexing), overview, statistics, files, index_status, ingest_local (index local folder).`,
12960
+ inputSchema: external_exports.object({
12961
+ action: external_exports.enum([
12962
+ "list",
12963
+ "get",
12964
+ "create",
12965
+ "update",
12966
+ "index",
12967
+ "overview",
12968
+ "statistics",
12969
+ "files",
12970
+ "index_status",
12971
+ "ingest_local"
12972
+ ]).describe("Action to perform"),
12973
+ workspace_id: external_exports.string().uuid().optional(),
12974
+ project_id: external_exports.string().uuid().optional(),
12975
+ // Create/update params
12976
+ name: external_exports.string().optional(),
12977
+ description: external_exports.string().optional(),
12978
+ folder_path: external_exports.string().optional(),
12979
+ generate_editor_rules: external_exports.boolean().optional(),
12980
+ // Ingest params
12981
+ path: external_exports.string().optional().describe("Local path to ingest"),
12982
+ overwrite: external_exports.boolean().optional(),
12983
+ write_to_disk: external_exports.boolean().optional(),
12984
+ // Pagination
12985
+ page: external_exports.number().optional(),
12986
+ page_size: external_exports.number().optional()
12987
+ })
12988
+ },
12989
+ async (input) => {
12990
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
12991
+ const projectId = resolveProjectId(input.project_id);
12992
+ switch (input.action) {
12993
+ case "list": {
12994
+ const result = await client.listProjects({
12995
+ workspace_id: workspaceId,
12996
+ page: input.page,
12997
+ page_size: input.page_size
12998
+ });
12999
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13000
+ }
13001
+ case "get": {
13002
+ if (!projectId) {
13003
+ return errorResult("get requires: project_id");
13004
+ }
13005
+ const result = await client.getProject(projectId);
13006
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13007
+ }
13008
+ case "create": {
13009
+ if (!input.name) {
13010
+ return errorResult("create requires: name");
13011
+ }
13012
+ const result = await client.createProject({
13013
+ workspace_id: workspaceId,
13014
+ name: input.name,
13015
+ description: input.description,
13016
+ folder_path: input.folder_path,
13017
+ generate_editor_rules: input.generate_editor_rules
13018
+ });
13019
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13020
+ }
13021
+ case "update": {
13022
+ if (!projectId) {
13023
+ return errorResult("update requires: project_id");
13024
+ }
13025
+ const result = await client.updateProject({
13026
+ project_id: projectId,
13027
+ name: input.name,
13028
+ description: input.description
13029
+ });
13030
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13031
+ }
13032
+ case "index": {
13033
+ if (!projectId) {
13034
+ return errorResult("index requires: project_id");
13035
+ }
13036
+ const result = await client.indexProject(projectId);
13037
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13038
+ }
13039
+ case "overview": {
13040
+ if (!projectId) {
13041
+ return errorResult("overview requires: project_id");
13042
+ }
13043
+ const result = await client.projectOverview(projectId);
13044
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13045
+ }
13046
+ case "statistics": {
13047
+ if (!projectId) {
13048
+ return errorResult("statistics requires: project_id");
13049
+ }
13050
+ const result = await client.projectStatistics(projectId);
13051
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13052
+ }
13053
+ case "files": {
13054
+ if (!projectId) {
13055
+ return errorResult("files requires: project_id");
13056
+ }
13057
+ const result = await client.projectFiles(projectId);
13058
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13059
+ }
13060
+ case "index_status": {
13061
+ if (!projectId) {
13062
+ return errorResult("index_status requires: project_id");
13063
+ }
13064
+ const result = await client.projectIndexStatus(projectId);
13065
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13066
+ }
13067
+ case "ingest_local": {
13068
+ if (!input.path) {
13069
+ return errorResult("ingest_local requires: path");
13070
+ }
13071
+ const validPath = await validateReadableDirectory(input.path);
13072
+ if (!validPath.ok) {
13073
+ return errorResult(validPath.error);
13074
+ }
13075
+ const files = await readAllFilesInBatches(validPath.resolvedPath, async (batch) => {
13076
+ await client.ingestLocalFiles({
13077
+ project_id: projectId,
13078
+ files: batch,
13079
+ overwrite: input.overwrite,
13080
+ write_to_disk: input.write_to_disk
13081
+ });
13082
+ });
13083
+ const result = { files_ingested: files, project_id: projectId };
13084
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13085
+ }
13086
+ default:
13087
+ return errorResult(`Unknown action: ${input.action}`);
13088
+ }
13089
+ }
13090
+ );
13091
+ registerTool(
13092
+ "workspace",
13093
+ {
13094
+ title: "Workspace",
13095
+ description: `Workspace management. Actions: list, get, associate (link folder to workspace), bootstrap (create workspace and initialize).`,
13096
+ inputSchema: external_exports.object({
13097
+ action: external_exports.enum(["list", "get", "associate", "bootstrap"]).describe("Action to perform"),
13098
+ workspace_id: external_exports.string().uuid().optional(),
13099
+ // Associate/bootstrap params
13100
+ folder_path: external_exports.string().optional(),
13101
+ workspace_name: external_exports.string().optional(),
13102
+ create_parent_mapping: external_exports.boolean().optional(),
13103
+ generate_editor_rules: external_exports.boolean().optional(),
13104
+ // Bootstrap-specific
13105
+ description: external_exports.string().optional(),
13106
+ visibility: external_exports.enum(["private", "public"]).optional(),
13107
+ auto_index: external_exports.boolean().optional(),
13108
+ context_hint: external_exports.string().optional(),
13109
+ // Pagination
13110
+ page: external_exports.number().optional(),
13111
+ page_size: external_exports.number().optional()
13112
+ })
13113
+ },
13114
+ async (input) => {
13115
+ switch (input.action) {
13116
+ case "list": {
13117
+ const result = await client.listWorkspaces({
13118
+ page: input.page,
13119
+ page_size: input.page_size
13120
+ });
13121
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13122
+ }
13123
+ case "get": {
13124
+ if (!input.workspace_id) {
13125
+ return errorResult("get requires: workspace_id");
13126
+ }
13127
+ const result = await client.getWorkspace(input.workspace_id);
13128
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13129
+ }
13130
+ case "associate": {
13131
+ if (!input.folder_path || !input.workspace_id) {
13132
+ return errorResult("associate requires: folder_path, workspace_id");
13133
+ }
13134
+ const result = await client.associateWorkspace({
13135
+ folder_path: input.folder_path,
13136
+ workspace_id: input.workspace_id,
13137
+ workspace_name: input.workspace_name,
13138
+ create_parent_mapping: input.create_parent_mapping,
13139
+ generate_editor_rules: input.generate_editor_rules
13140
+ });
13141
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13142
+ }
13143
+ case "bootstrap": {
13144
+ if (!input.workspace_name) {
13145
+ return errorResult("bootstrap requires: workspace_name");
13146
+ }
13147
+ const result = await client.bootstrapWorkspace({
13148
+ workspace_name: input.workspace_name,
13149
+ folder_path: input.folder_path,
13150
+ description: input.description,
13151
+ visibility: input.visibility,
13152
+ create_parent_mapping: input.create_parent_mapping,
13153
+ generate_editor_rules: input.generate_editor_rules,
13154
+ auto_index: input.auto_index,
13155
+ context_hint: input.context_hint
13156
+ });
13157
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13158
+ }
13159
+ default:
13160
+ return errorResult(`Unknown action: ${input.action}`);
13161
+ }
13162
+ }
13163
+ );
13164
+ registerTool(
13165
+ "reminder",
13166
+ {
13167
+ title: "Reminder",
13168
+ description: `Reminder management. Actions: list, active (pending/overdue), create, snooze, complete, dismiss.`,
13169
+ inputSchema: external_exports.object({
13170
+ action: external_exports.enum(["list", "active", "create", "snooze", "complete", "dismiss"]).describe("Action to perform"),
13171
+ workspace_id: external_exports.string().uuid().optional(),
13172
+ project_id: external_exports.string().uuid().optional(),
13173
+ reminder_id: external_exports.string().uuid().optional(),
13174
+ // Create params
13175
+ title: external_exports.string().optional(),
13176
+ content: external_exports.string().optional(),
13177
+ remind_at: external_exports.string().optional().describe("ISO 8601 datetime"),
13178
+ priority: external_exports.enum(["low", "normal", "high", "urgent"]).optional(),
13179
+ recurrence: external_exports.enum(["daily", "weekly", "monthly"]).optional(),
13180
+ keywords: external_exports.array(external_exports.string()).optional(),
13181
+ // Snooze params
13182
+ until: external_exports.string().optional().describe("ISO 8601 datetime"),
13183
+ // Filter params
13184
+ status: external_exports.enum(["pending", "completed", "dismissed", "snoozed"]).optional(),
13185
+ context: external_exports.string().optional(),
13186
+ limit: external_exports.number().optional()
13187
+ })
13188
+ },
13189
+ async (input) => {
13190
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
13191
+ const projectId = resolveProjectId(input.project_id);
13192
+ switch (input.action) {
13193
+ case "list": {
13194
+ const result = await client.remindersList({
13195
+ workspace_id: workspaceId,
13196
+ project_id: projectId,
13197
+ status: input.status,
13198
+ priority: input.priority,
13199
+ limit: input.limit
13200
+ });
13201
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13202
+ }
13203
+ case "active": {
13204
+ const result = await client.remindersActive({
13205
+ workspace_id: workspaceId,
13206
+ project_id: projectId,
13207
+ context: input.context,
13208
+ limit: input.limit
13209
+ });
13210
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13211
+ }
13212
+ case "create": {
13213
+ if (!input.title || !input.content || !input.remind_at) {
13214
+ return errorResult("create requires: title, content, remind_at");
13215
+ }
13216
+ const result = await client.remindersCreate({
13217
+ workspace_id: workspaceId,
13218
+ project_id: projectId,
13219
+ title: input.title,
13220
+ content: input.content,
13221
+ remind_at: input.remind_at,
13222
+ priority: input.priority,
13223
+ recurrence: input.recurrence,
13224
+ keywords: input.keywords
13225
+ });
13226
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13227
+ }
13228
+ case "snooze": {
13229
+ if (!input.reminder_id || !input.until) {
13230
+ return errorResult("snooze requires: reminder_id, until");
13231
+ }
13232
+ const result = await client.remindersSnooze({
13233
+ reminder_id: input.reminder_id,
13234
+ until: input.until
13235
+ });
13236
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13237
+ }
13238
+ case "complete": {
13239
+ if (!input.reminder_id) {
13240
+ return errorResult("complete requires: reminder_id");
13241
+ }
13242
+ const result = await client.remindersComplete({
13243
+ reminder_id: input.reminder_id
13244
+ });
13245
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13246
+ }
13247
+ case "dismiss": {
13248
+ if (!input.reminder_id) {
13249
+ return errorResult("dismiss requires: reminder_id");
13250
+ }
13251
+ const result = await client.remindersDismiss({
13252
+ reminder_id: input.reminder_id
13253
+ });
13254
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13255
+ }
13256
+ default:
13257
+ return errorResult(`Unknown action: ${input.action}`);
13258
+ }
13259
+ }
13260
+ );
13261
+ registerTool(
13262
+ "integration",
13263
+ {
13264
+ title: "Integration",
13265
+ description: `Integration operations for Slack and GitHub. Provider: slack, github, all. Actions: status, search, stats, activity, contributors, knowledge, summary, channels (slack), discussions (slack), repos (github), issues (github).`,
13266
+ inputSchema: external_exports.object({
13267
+ provider: external_exports.enum(["slack", "github", "all"]).describe("Integration provider"),
13268
+ action: external_exports.enum([
13269
+ "status",
13270
+ "search",
13271
+ "stats",
13272
+ "activity",
13273
+ "contributors",
13274
+ "knowledge",
13275
+ "summary",
13276
+ "channels",
13277
+ "discussions",
13278
+ "sync_users",
13279
+ "repos",
13280
+ "issues"
13281
+ ]).describe("Action to perform"),
13282
+ workspace_id: external_exports.string().uuid().optional(),
13283
+ project_id: external_exports.string().uuid().optional(),
13284
+ query: external_exports.string().optional(),
13285
+ limit: external_exports.number().optional(),
13286
+ since: external_exports.string().optional(),
13287
+ until: external_exports.string().optional()
13288
+ })
13289
+ },
13290
+ async (input) => {
13291
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
13292
+ const projectId = resolveProjectId(input.project_id);
13293
+ const integrationGated = await gateIfIntegrationTool(
13294
+ input.provider === "slack" ? "slack_search" : input.provider === "github" ? "github_search" : "integrations_status"
13295
+ );
13296
+ if (integrationGated) return integrationGated;
13297
+ const params = {
13298
+ workspace_id: workspaceId,
13299
+ project_id: projectId,
13300
+ query: input.query,
13301
+ limit: input.limit,
13302
+ since: input.since,
13303
+ until: input.until
13304
+ };
13305
+ switch (input.action) {
13306
+ case "status": {
13307
+ const result = await client.integrationsStatus(params);
13308
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13309
+ }
13310
+ case "search": {
13311
+ if (input.provider === "slack") {
13312
+ const result = await client.slackSearch(params);
13313
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13314
+ } else if (input.provider === "github") {
13315
+ const result = await client.githubSearch(params);
13316
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13317
+ } else {
13318
+ const result = await client.integrationsSearch(params);
13319
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13320
+ }
13321
+ }
13322
+ case "stats": {
13323
+ if (input.provider === "slack") {
13324
+ const result = await client.slackStats(params);
13325
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13326
+ } else if (input.provider === "github") {
13327
+ const result = await client.githubStats(params);
13328
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13329
+ }
13330
+ return errorResult("stats requires provider: slack or github");
13331
+ }
13332
+ case "activity": {
13333
+ if (input.provider === "slack") {
13334
+ const result = await client.slackActivity(params);
13335
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13336
+ } else if (input.provider === "github") {
13337
+ const result = await client.githubActivity(params);
13338
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13339
+ }
13340
+ return errorResult("activity requires provider: slack or github");
13341
+ }
13342
+ case "contributors": {
13343
+ if (input.provider === "slack") {
13344
+ const result = await client.slackContributors(params);
13345
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13346
+ } else if (input.provider === "github") {
13347
+ const result = await client.githubContributors(params);
13348
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13349
+ }
13350
+ return errorResult("contributors requires provider: slack or github");
13351
+ }
13352
+ case "knowledge": {
13353
+ if (input.provider === "slack") {
13354
+ const result = await client.slackKnowledge(params);
13355
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13356
+ } else if (input.provider === "github") {
13357
+ const result = await client.githubKnowledge(params);
13358
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13359
+ } else {
13360
+ const result = await client.integrationsKnowledge(params);
13361
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13362
+ }
13363
+ }
13364
+ case "summary": {
13365
+ if (input.provider === "slack") {
13366
+ const result = await client.slackSummary(params);
13367
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13368
+ } else if (input.provider === "github") {
13369
+ const result = await client.githubSummary(params);
13370
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13371
+ } else {
13372
+ const result = await client.integrationsSummary(params);
13373
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13374
+ }
13375
+ }
13376
+ case "channels": {
13377
+ if (input.provider !== "slack") {
13378
+ return errorResult("channels is only available for slack provider");
13379
+ }
13380
+ const result = await client.slackChannels(params);
13381
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13382
+ }
13383
+ case "discussions": {
13384
+ if (input.provider !== "slack") {
13385
+ return errorResult("discussions is only available for slack provider");
13386
+ }
13387
+ const result = await client.slackDiscussions(params);
13388
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13389
+ }
13390
+ case "sync_users": {
13391
+ if (input.provider !== "slack") {
13392
+ return errorResult("sync_users is only available for slack provider");
13393
+ }
13394
+ const result = await client.slackSyncUsers(params);
13395
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13396
+ }
13397
+ case "repos": {
13398
+ if (input.provider !== "github") {
13399
+ return errorResult("repos is only available for github provider");
13400
+ }
13401
+ const result = await client.githubRepos(params);
13402
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13403
+ }
13404
+ case "issues": {
13405
+ if (input.provider !== "github") {
13406
+ return errorResult("issues is only available for github provider");
13407
+ }
13408
+ const result = await client.githubIssues(params);
13409
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13410
+ }
13411
+ default:
13412
+ return errorResult(`Unknown action: ${input.action}`);
13413
+ }
13414
+ }
13415
+ );
13416
+ registerTool(
13417
+ "help",
13418
+ {
13419
+ title: "Help",
13420
+ description: `Utility and help. Actions: tools (list available tools), auth (current user), version (server version), editor_rules (generate AI editor rules), enable_bundle (enable tool bundle in progressive mode).`,
13421
+ inputSchema: external_exports.object({
13422
+ action: external_exports.enum(["tools", "auth", "version", "editor_rules", "enable_bundle"]).describe("Action to perform"),
13423
+ // For tools
13424
+ format: external_exports.enum(["grouped", "minimal", "full"]).optional(),
13425
+ category: external_exports.string().optional(),
13426
+ // For editor_rules
13427
+ folder_path: external_exports.string().optional(),
13428
+ editors: external_exports.array(external_exports.string()).optional(),
13429
+ mode: external_exports.enum(["minimal", "full"]).optional(),
13430
+ dry_run: external_exports.boolean().optional(),
13431
+ workspace_id: external_exports.string().uuid().optional(),
13432
+ workspace_name: external_exports.string().optional(),
13433
+ project_name: external_exports.string().optional(),
13434
+ additional_rules: external_exports.string().optional(),
13435
+ // For enable_bundle
13436
+ bundle: external_exports.enum(["session", "memory", "search", "graph", "workspace", "project", "reminders", "integrations"]).optional(),
13437
+ list_bundles: external_exports.boolean().optional()
13438
+ })
13439
+ },
13440
+ async (input) => {
13441
+ switch (input.action) {
13442
+ case "tools": {
13443
+ const format = input.format || "grouped";
13444
+ const catalog = generateToolCatalog(format, input.category);
13445
+ const consolidatedInfo = CONSOLIDATED_MODE ? `
13446
+
13447
+ [Consolidated Mode]
13448
+ Domain tools: ${Array.from(CONSOLIDATED_TOOLS).join(", ")}
13449
+ Each domain tool has an 'action' parameter for specific operations.` : "";
13450
+ return {
13451
+ content: [{ type: "text", text: catalog + consolidatedInfo }],
13452
+ structuredContent: {
13453
+ format,
13454
+ catalog,
13455
+ consolidated_mode: CONSOLIDATED_MODE,
13456
+ domain_tools: CONSOLIDATED_MODE ? Array.from(CONSOLIDATED_TOOLS) : void 0
13457
+ }
13458
+ };
13459
+ }
13460
+ case "auth": {
13461
+ const result = await client.me();
13462
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13463
+ }
13464
+ case "version": {
13465
+ const result = { name: "contextstream-mcp", version: VERSION };
13466
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13467
+ }
13468
+ case "editor_rules": {
13469
+ if (!input.folder_path) {
13470
+ return errorResult("editor_rules requires: folder_path");
13471
+ }
13472
+ const result = await generateAllRuleFiles(input.folder_path, {
13473
+ editors: input.editors,
13474
+ mode: input.mode,
13475
+ dryRun: input.dry_run,
13476
+ workspaceId: input.workspace_id,
13477
+ workspaceName: input.workspace_name,
13478
+ projectName: input.project_name,
13479
+ additionalRules: input.additional_rules
13480
+ });
13481
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13482
+ }
13483
+ case "enable_bundle": {
13484
+ if (input.list_bundles) {
13485
+ const bundles = getBundleInfo();
13486
+ const result2 = {
13487
+ progressive_mode: PROGRESSIVE_MODE,
13488
+ consolidated_mode: CONSOLIDATED_MODE,
13489
+ bundles,
13490
+ hint: CONSOLIDATED_MODE ? "Consolidated mode is enabled. All operations are available via domain tools." : PROGRESSIVE_MODE ? "Progressive mode is enabled. Use enable_bundle to unlock additional tools." : "Neither progressive nor consolidated mode is enabled."
13491
+ };
13492
+ return { content: [{ type: "text", text: formatContent(result2) }], structuredContent: toStructured(result2) };
13493
+ }
13494
+ if (!input.bundle) {
13495
+ return errorResult("enable_bundle requires: bundle (or use list_bundles: true)");
13496
+ }
13497
+ if (CONSOLIDATED_MODE) {
13498
+ return {
13499
+ content: [{ type: "text", text: "Consolidated mode is enabled. All operations are available via domain tools (search, session, memory, graph, project, workspace, reminder, integration, help)." }]
13500
+ };
13501
+ }
13502
+ if (!PROGRESSIVE_MODE) {
13503
+ return {
13504
+ content: [{ type: "text", text: "Progressive mode is not enabled. All tools from your toolset are already available." }]
13505
+ };
13506
+ }
13507
+ const result = enableBundle(input.bundle);
13508
+ return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
13509
+ }
13510
+ default:
13511
+ return errorResult(`Unknown action: ${input.action}`);
13512
+ }
13513
+ }
13514
+ );
13515
+ console.error(`[ContextStream] Consolidated mode: Registered ${CONSOLIDATED_TOOLS.size} domain tools.`);
13516
+ }
12056
13517
  }
12057
13518
 
12058
13519
  // src/resources.ts
@@ -14534,6 +15995,9 @@ Environment variables:
14534
15995
  CONTEXTSTREAM_AUTO_HIDE_INTEGRATIONS Auto-hide Slack/GitHub tools when not connected (default: true)
14535
15996
  CONTEXTSTREAM_SCHEMA_MODE Schema verbosity: compact|full (default: full, compact reduces tokens)
14536
15997
  CONTEXTSTREAM_PROGRESSIVE_MODE Progressive disclosure: true|false (default: false, starts with ~13 core tools)
15998
+ CONTEXTSTREAM_ROUTER_MODE Router pattern: true|false (default: false, exposes only 2 meta-tools)
15999
+ CONTEXTSTREAM_OUTPUT_FORMAT Output verbosity: compact|pretty (default: compact, ~30% fewer tokens)
16000
+ CONTEXTSTREAM_CONSOLIDATED Consolidated domain tools: true|false (default: true in v0.4.x, ~75% token reduction)
14537
16001
  CONTEXTSTREAM_PRO_TOOLS Optional comma-separated PRO tool names (default: AI tools)
14538
16002
  CONTEXTSTREAM_UPGRADE_URL Optional upgrade URL shown for PRO tools on Free plan
14539
16003
  CONTEXTSTREAM_ENABLE_PROMPTS Enable MCP prompts list (default: true)