@contextstream/mcp-server 0.4.65 → 0.4.66

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 +337 -17
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12919,6 +12919,37 @@ function normalizeTags(tags) {
12919
12919
  );
12920
12920
  return normalized.length > 0 ? normalized : void 0;
12921
12921
  }
12922
+ function extractEventTags(item) {
12923
+ const tags = [];
12924
+ if (Array.isArray(item.tags)) {
12925
+ tags.push(...item.tags.filter((t) => typeof t === "string"));
12926
+ }
12927
+ const metaTags = item.metadata?.tags;
12928
+ if (Array.isArray(metaTags)) {
12929
+ tags.push(...metaTags.filter((t) => typeof t === "string"));
12930
+ }
12931
+ return tags;
12932
+ }
12933
+ function extractEffectiveEventType(item) {
12934
+ for (const field of ["event_type", "node_type", "type"]) {
12935
+ const val = item[field];
12936
+ if (typeof val === "string" && val.trim()) return val.trim();
12937
+ }
12938
+ for (const field of ["original_type", "node_type", "event_type", "type"]) {
12939
+ const val = item.metadata?.[field];
12940
+ if (typeof val === "string" && val.trim()) return val.trim();
12941
+ }
12942
+ return "unknown";
12943
+ }
12944
+ function isLessonResult(item) {
12945
+ const effectiveType = extractEffectiveEventType(item);
12946
+ if (effectiveType === "lesson") return true;
12947
+ const tags = extractEventTags(item);
12948
+ if (tags.some((t) => t === "lesson" || t === "lesson_system")) return true;
12949
+ const content = typeof item.content === "string" ? item.content : "";
12950
+ if (content.includes("### Prevention") && content.includes("### Trigger")) return true;
12951
+ return false;
12952
+ }
12922
12953
  function pickString(value) {
12923
12954
  if (typeof value !== "string") return null;
12924
12955
  const trimmed = value.trim();
@@ -13472,6 +13503,8 @@ var ContextStreamClient = class _ContextStreamClient {
13472
13503
  const query = new URLSearchParams();
13473
13504
  if (params?.limit) query.set("limit", String(params.limit));
13474
13505
  if (withDefaults.project_id) query.set("project_id", withDefaults.project_id);
13506
+ if (params?.event_type) query.set("event_type", params.event_type);
13507
+ if (params?.tags && params.tags.length > 0) query.set("tags", params.tags.join(","));
13475
13508
  const suffix = query.toString() ? `?${query.toString()}` : "";
13476
13509
  return request(this.config, `/memory/events/workspace/${withDefaults.workspace_id}${suffix}`, {
13477
13510
  method: "GET"
@@ -15835,14 +15868,13 @@ ${context}`;
15835
15868
  });
15836
15869
  if (!searchResult?.results) return [];
15837
15870
  const lessons = searchResult.results.filter((item) => {
15838
- const tags = item.metadata?.tags || [];
15839
- const isLesson = tags.includes("lesson") || tags.includes("lesson_system");
15840
- if (!isLesson) return false;
15871
+ if (!isLessonResult(item)) return false;
15872
+ const tags = extractEventTags(item);
15841
15873
  const severityTag = tags.find((t) => t.startsWith("severity:"));
15842
15874
  const severity = severityTag?.split(":")[1] || item.metadata?.importance || "medium";
15843
15875
  return severity === "critical" || severity === "high";
15844
15876
  }).slice(0, limit).map((item) => {
15845
- const tags = item.metadata?.tags || [];
15877
+ const tags = extractEventTags(item);
15846
15878
  const severityTag = tags.find((t) => t.startsWith("severity:"));
15847
15879
  const severity = severityTag?.split(":")[1] || item.metadata?.importance || "medium";
15848
15880
  const category = tags.find(
@@ -15856,7 +15888,7 @@ ${context}`;
15856
15888
  ) || "unknown";
15857
15889
  const content = item.content || "";
15858
15890
  const preventionMatch = content.match(/### Prevention\n([\s\S]*?)(?:\n\n|\n\*\*|$)/);
15859
- const prevention = preventionMatch?.[1]?.trim() || content.slice(0, 200);
15891
+ const prevention = preventionMatch?.[1]?.trim() || content.slice(0, 1e3);
15860
15892
  return {
15861
15893
  title: item.title || "Lesson",
15862
15894
  severity,
@@ -17111,6 +17143,55 @@ ${context}`;
17111
17143
  return request(this.config, `/docs/${params.doc_id}`, { method: "DELETE" });
17112
17144
  }
17113
17145
  // -------------------------------------------------------------------------
17146
+ // Skill methods (portable instruction + action bundles)
17147
+ // -------------------------------------------------------------------------
17148
+ async listSkills(params) {
17149
+ const withDefaults = this.withDefaults(params || {});
17150
+ const query = new URLSearchParams();
17151
+ if (withDefaults.workspace_id) query.set("workspace_id", withDefaults.workspace_id);
17152
+ if (params?.project_id) query.set("project_id", params.project_id);
17153
+ if (params?.scope) query.set("scope", params.scope);
17154
+ if (params?.status) query.set("status", params.status);
17155
+ if (params?.category) query.set("category", params.category);
17156
+ if (params?.query) query.set("query", params.query);
17157
+ if (params?.is_personal !== void 0) query.set("is_personal", String(params.is_personal));
17158
+ if (params?.limit) query.set("limit", String(params.limit));
17159
+ const suffix = query.toString() ? `?${query.toString()}` : "";
17160
+ return request(this.config, `/skills${suffix}`, { method: "GET" });
17161
+ }
17162
+ async getSkill(skillId) {
17163
+ return request(this.config, `/skills/${skillId}`, { method: "GET" });
17164
+ }
17165
+ async createSkill(params) {
17166
+ return request(this.config, "/skills", { body: this.withDefaults(params) });
17167
+ }
17168
+ async updateSkill(skillId, params) {
17169
+ return request(this.config, `/skills/${skillId}`, {
17170
+ method: "PATCH",
17171
+ body: params
17172
+ });
17173
+ }
17174
+ async runSkill(skillId, params) {
17175
+ return request(this.config, `/skills/${skillId}/run`, {
17176
+ body: params || {}
17177
+ });
17178
+ }
17179
+ async deleteSkill(skillId) {
17180
+ return request(this.config, `/skills/${skillId}`, { method: "DELETE" });
17181
+ }
17182
+ async importSkills(params) {
17183
+ return request(this.config, "/skills/import", { body: this.withDefaults(params) });
17184
+ }
17185
+ async exportSkills(params) {
17186
+ const withDefaults = this.withDefaults(params || {});
17187
+ return request(this.config, "/skills/export", { body: withDefaults });
17188
+ }
17189
+ async shareSkill(skillId, scope) {
17190
+ return request(this.config, `/skills/${skillId}/share`, {
17191
+ body: { scope }
17192
+ });
17193
+ }
17194
+ // -------------------------------------------------------------------------
17114
17195
  // Transcript methods (conversation session storage)
17115
17196
  // -------------------------------------------------------------------------
17116
17197
  /**
@@ -17202,14 +17283,14 @@ ${context}`;
17202
17283
  };
17203
17284
 
17204
17285
  // src/tools.ts
17205
- init_files();
17206
- init_rules_templates();
17207
- init_version();
17208
17286
  import * as fs5 from "node:fs";
17209
17287
  import * as path6 from "node:path";
17210
17288
  import { execFile } from "node:child_process";
17211
17289
  import { homedir as homedir4 } from "node:os";
17212
17290
  import { promisify as promisify2 } from "node:util";
17291
+ init_files();
17292
+ init_rules_templates();
17293
+ init_version();
17213
17294
 
17214
17295
  // src/tool-catalog.ts
17215
17296
  var TOOL_CATALOG = [
@@ -19313,6 +19394,8 @@ var CONSOLIDATED_TOOLS = /* @__PURE__ */ new Set([
19313
19394
  // Consolidates slack_*, github_*, notion_*, integrations_*
19314
19395
  "media",
19315
19396
  // Consolidates media indexing, search, and clip retrieval for Remotion/FFmpeg
19397
+ "skill",
19398
+ // Skill management: list, get, create, update, run, delete, import, export, share
19316
19399
  "help"
19317
19400
  // Consolidates session_tools, auth_me, mcp_server_version, etc.
19318
19401
  ]);
@@ -19332,6 +19415,7 @@ function mapToolToConsolidatedDomain(toolName) {
19332
19415
  return "integration";
19333
19416
  }
19334
19417
  if (toolName.startsWith("media_")) return "media";
19418
+ if (toolName.startsWith("skill_")) return "skill";
19335
19419
  if (toolName === "session_tools" || toolName === "auth_me" || toolName === "mcp_server_version" || toolName === "tools_enable_bundle") {
19336
19420
  return "help";
19337
19421
  }
@@ -19427,6 +19511,31 @@ function toStructured(data) {
19427
19511
  }
19428
19512
  return void 0;
19429
19513
  }
19514
+ function formatSkillDetail(skill) {
19515
+ const lines = [
19516
+ `**${skill.title || skill.name || "?"}** (${skill.name || "?"})`,
19517
+ `- ID: ${skill.id || "?"}`,
19518
+ `- Scope: ${skill.scope || "personal"} | Status: ${skill.status || "active"}`
19519
+ ];
19520
+ if (skill.description) lines.push(`- Description: ${skill.description}`);
19521
+ if (skill.trigger_patterns?.length) lines.push(`- Triggers: ${skill.trigger_patterns.join(", ")}`);
19522
+ if (skill.categories?.length) lines.push(`- Categories: ${skill.categories.join(", ")}`);
19523
+ if (skill.priority != null) lines.push(`- Priority: ${skill.priority}`);
19524
+ if (skill.version) lines.push(`- Version: ${skill.version}`);
19525
+ if (skill.instruction_body) {
19526
+ const body = String(skill.instruction_body);
19527
+ lines.push(`
19528
+ ### Instruction
19529
+ ${body.length > 2e3 ? body.slice(0, 2e3) + "\u2026" : body}`);
19530
+ }
19531
+ return lines.join("\n");
19532
+ }
19533
+ function formatRunResult(result) {
19534
+ if (result.instruction) return result.instruction;
19535
+ if (result.output) return `Skill output:
19536
+ ${result.output}`;
19537
+ return JSON.stringify(result, null, 2);
19538
+ }
19430
19539
  function readStatNumber(payload, key) {
19431
19540
  if (!payload || typeof payload !== "object") return void 0;
19432
19541
  const direct = payload[key];
@@ -21750,6 +21859,201 @@ Access: Free`,
21750
21859
  };
21751
21860
  }
21752
21861
  );
21862
+ registerTool(
21863
+ "skill",
21864
+ {
21865
+ title: "Manage reusable skills",
21866
+ description: `Manage and execute reusable skills (instruction + action bundles). Skills are portable across projects, sessions, and tools.
21867
+
21868
+ Actions:
21869
+ - list: Browse skills (filter by scope, status, category)
21870
+ - get: Get skill details by ID or name
21871
+ - create: Define a new skill with name, instruction, and triggers
21872
+ - update: Modify an existing skill
21873
+ - run: Execute a skill (by ID or name)
21874
+ - delete: Remove a skill
21875
+ - import: Import skills from file or content (supports markdown, JSON, cursorrules, claude_md)
21876
+ - export: Export skills in various formats
21877
+ - share: Change skill visibility scope`,
21878
+ inputSchema: external_exports.object({
21879
+ action: external_exports.enum(["list", "get", "create", "update", "run", "delete", "import", "export", "share"]).describe("The action to perform"),
21880
+ skill_id: external_exports.string().optional().describe("Skill ID (UUID)"),
21881
+ name: external_exports.string().optional().describe("Skill name (slug, e.g. 'deploy-checker')"),
21882
+ title: external_exports.string().optional().describe("Skill display title"),
21883
+ description: external_exports.string().optional().describe("Skill description"),
21884
+ instruction_body: external_exports.string().optional().describe("Markdown instruction text (the prompt)"),
21885
+ trigger_patterns: external_exports.array(external_exports.string()).optional().describe("Keywords/phrases for auto-activation"),
21886
+ trigger_regex: external_exports.string().optional().describe("Optional regex for advanced trigger matching"),
21887
+ categories: external_exports.array(external_exports.string()).optional().describe("Tags for discovery/filtering"),
21888
+ actions: external_exports.any().optional().describe("Action steps array [{type, tool, params, ...}]"),
21889
+ params: external_exports.any().optional().describe("Parameters passed to skill execution"),
21890
+ dry_run: external_exports.boolean().optional().describe("Preview execution without running"),
21891
+ scope: external_exports.enum(["personal", "team", "public", "all"]).optional().describe("Visibility scope"),
21892
+ status: external_exports.enum(["active", "draft", "archived"]).optional().describe("Skill status"),
21893
+ is_personal: external_exports.boolean().optional().describe("Whether skill is personal"),
21894
+ priority: external_exports.number().optional().describe("Skill priority 0-100 (higher = matched first)"),
21895
+ content: external_exports.string().optional().describe("Content string for import"),
21896
+ file_path: external_exports.string().optional().describe("Local file path for import"),
21897
+ format: external_exports.enum(["auto", "json", "markdown", "skills_md", "cursorrules", "claude_md", "aider", "zip"]).optional().describe("Import/export format"),
21898
+ source_tool: external_exports.string().optional().describe("Source tool name (for import provenance)"),
21899
+ source_file: external_exports.string().optional().describe("Source filename (for import provenance)"),
21900
+ skill_ids: external_exports.array(external_exports.string()).optional().describe("Skill IDs for export"),
21901
+ change_summary: external_exports.string().optional().describe("Summary of changes (for version history)"),
21902
+ workspace_id: external_exports.string().optional().describe("Workspace ID (UUID)"),
21903
+ project_id: external_exports.string().optional().describe("Project ID (UUID)"),
21904
+ query: external_exports.string().optional().describe("Search query"),
21905
+ category: external_exports.string().optional().describe("Filter by category tag"),
21906
+ limit: external_exports.number().optional().describe("Max results to return")
21907
+ })
21908
+ },
21909
+ async (input) => {
21910
+ const action = input.action;
21911
+ switch (action) {
21912
+ case "list": {
21913
+ const result = await client.listSkills({
21914
+ workspace_id: input.workspace_id,
21915
+ project_id: input.project_id,
21916
+ scope: input.scope,
21917
+ status: input.status,
21918
+ category: input.category,
21919
+ query: input.query,
21920
+ is_personal: input.is_personal,
21921
+ limit: input.limit
21922
+ });
21923
+ const items = result.items || [];
21924
+ let text = `Found ${items.length} skill(s).
21925
+ `;
21926
+ for (const item of items) {
21927
+ const name = item.name || "?";
21928
+ const title = item.title || "?";
21929
+ const scope = item.scope || "?";
21930
+ const status = item.status || "?";
21931
+ const id = item.id || "?";
21932
+ text += `- ${title} (${name}) [${scope}|${status}] id=${id}
21933
+ `;
21934
+ }
21935
+ return { content: [{ type: "text", text }] };
21936
+ }
21937
+ case "get": {
21938
+ let skillData;
21939
+ if (input.skill_id) {
21940
+ skillData = await client.getSkill(input.skill_id);
21941
+ } else if (input.name) {
21942
+ const result = await client.listSkills({
21943
+ workspace_id: input.workspace_id,
21944
+ query: input.name,
21945
+ limit: 1
21946
+ });
21947
+ skillData = result.items?.find((s) => s.name === input.name) || result.items?.[0];
21948
+ if (!skillData) throw new Error(`Skill '${input.name}' not found`);
21949
+ } else {
21950
+ throw new Error("Either skill_id or name is required for 'get'");
21951
+ }
21952
+ const detail = formatSkillDetail(skillData);
21953
+ return { content: [{ type: "text", text: detail }] };
21954
+ }
21955
+ case "create": {
21956
+ if (!input.name) throw new Error("'name' is required for create");
21957
+ if (!input.instruction_body) throw new Error("'instruction_body' is required for create");
21958
+ const result = await client.createSkill({
21959
+ name: input.name,
21960
+ title: input.title || input.name,
21961
+ instruction_body: input.instruction_body,
21962
+ description: input.description,
21963
+ trigger_patterns: input.trigger_patterns,
21964
+ trigger_regex: input.trigger_regex,
21965
+ categories: input.categories,
21966
+ actions: input.actions,
21967
+ scope: input.scope,
21968
+ is_personal: input.is_personal,
21969
+ priority: input.priority,
21970
+ workspace_id: input.scope === "team" ? input.workspace_id : void 0,
21971
+ project_id: void 0,
21972
+ // Skills are account-level by default
21973
+ source_tool: input.source_tool,
21974
+ source_file: input.source_file
21975
+ });
21976
+ return { content: [{ type: "text", text: `Skill '${input.name}' created (id=${result.id || "?"}).` }] };
21977
+ }
21978
+ case "update": {
21979
+ if (!input.skill_id) throw new Error("'skill_id' is required for update");
21980
+ const result = await client.updateSkill(input.skill_id, {
21981
+ title: input.title,
21982
+ description: input.description,
21983
+ instruction_body: input.instruction_body,
21984
+ trigger_patterns: input.trigger_patterns,
21985
+ trigger_regex: input.trigger_regex,
21986
+ categories: input.categories,
21987
+ actions: input.actions,
21988
+ scope: input.scope,
21989
+ status: input.status,
21990
+ is_personal: input.is_personal,
21991
+ priority: input.priority,
21992
+ change_summary: input.change_summary
21993
+ });
21994
+ return { content: [{ type: "text", text: `Skill ${input.skill_id} updated (version=${result.version || 0}).` }] };
21995
+ }
21996
+ case "run": {
21997
+ let resolvedId = input.skill_id;
21998
+ if (!resolvedId && input.name) {
21999
+ const result2 = await client.listSkills({
22000
+ workspace_id: input.workspace_id,
22001
+ query: input.name,
22002
+ limit: 1
22003
+ });
22004
+ const found = result2.items?.find((s) => s.name === input.name) || result2.items?.[0];
22005
+ if (!found?.id) throw new Error(`Skill '${input.name}' not found`);
22006
+ resolvedId = found.id;
22007
+ }
22008
+ if (!resolvedId) throw new Error("Either skill_id or name is required for 'run'");
22009
+ const result = await client.runSkill(resolvedId, {
22010
+ params: input.params,
22011
+ dry_run: input.dry_run
22012
+ });
22013
+ return { content: [{ type: "text", text: formatRunResult(result) }] };
22014
+ }
22015
+ case "delete": {
22016
+ if (!input.skill_id) throw new Error("'skill_id' is required for delete");
22017
+ await client.deleteSkill(input.skill_id);
22018
+ return { content: [{ type: "text", text: `Skill ${input.skill_id} deleted.` }] };
22019
+ }
22020
+ case "import": {
22021
+ let importContent = input.content;
22022
+ if (!importContent && input.file_path) {
22023
+ const { readFile: readFile4 } = await import("fs/promises");
22024
+ importContent = await readFile4(input.file_path, "utf-8");
22025
+ }
22026
+ if (!importContent) throw new Error("Either 'content' or 'file_path' is required for import");
22027
+ const result = await client.importSkills({
22028
+ content: importContent,
22029
+ format: input.format,
22030
+ source_tool: input.source_tool,
22031
+ source_file: input.source_file || input.file_path,
22032
+ scope: input.scope,
22033
+ workspace_id: input.workspace_id
22034
+ });
22035
+ return { content: [{ type: "text", text: `Import complete: ${result.imported || 0} imported, ${result.skipped || 0} skipped (duplicates).` }] };
22036
+ }
22037
+ case "export": {
22038
+ const result = await client.exportSkills({
22039
+ skill_ids: input.skill_ids,
22040
+ format: input.format,
22041
+ scope: input.scope,
22042
+ workspace_id: input.workspace_id
22043
+ });
22044
+ return { content: [{ type: "text", text: result.content || JSON.stringify(result, null, 2) }] };
22045
+ }
22046
+ case "share": {
22047
+ if (!input.skill_id) throw new Error("'skill_id' is required for share");
22048
+ if (!input.scope) throw new Error("'scope' is required for share");
22049
+ const result = await client.shareSkill(input.skill_id, input.scope);
22050
+ return { content: [{ type: "text", text: `Skill ${input.skill_id} shared with scope=${result.scope || input.scope}.` }] };
22051
+ }
22052
+ default:
22053
+ throw new Error(`Invalid skill action: '${action}'. Valid: list, get, create, update, run, delete, import, export, share`);
22054
+ }
22055
+ }
22056
+ );
21753
22057
  registerTool(
21754
22058
  "memory_bulk_ingest",
21755
22059
  {
@@ -21772,15 +22076,24 @@ Access: Free`,
21772
22076
  "memory_list_events",
21773
22077
  {
21774
22078
  title: "List memory events",
21775
- description: "List memory events (optionally scoped)",
22079
+ description: "List memory events (optionally scoped). Supports tag-based and event_type filtering for precise provenance tracking.",
21776
22080
  inputSchema: external_exports.object({
21777
22081
  workspace_id: external_exports.string().uuid().optional(),
21778
22082
  project_id: external_exports.string().uuid().optional(),
21779
- limit: external_exports.number().optional()
22083
+ limit: external_exports.number().optional(),
22084
+ tags: external_exports.array(external_exports.string()).optional().describe("Filter events that contain ALL of these tags"),
22085
+ event_type: external_exports.string().optional().describe("Filter by event type (e.g. decision, lesson, manual_note)")
21780
22086
  })
21781
22087
  },
21782
22088
  async (input) => {
21783
22089
  const result = await client.listMemoryEvents(input);
22090
+ if (input.tags && input.tags.length > 0 && result.items) {
22091
+ const requiredTags = input.tags;
22092
+ result.items = result.items.filter((item) => {
22093
+ const itemTags = extractEventTags(item);
22094
+ return requiredTags.every((tag) => itemTags.includes(tag));
22095
+ });
22096
+ }
21784
22097
  return {
21785
22098
  content: [{ type: "text", text: formatContent(result) }]
21786
22099
  };
@@ -21834,16 +22147,24 @@ Access: Free`,
21834
22147
  "memory_search",
21835
22148
  {
21836
22149
  title: "Memory-aware search",
21837
- description: "Search memory events/notes",
22150
+ description: "Search memory events/notes. Supports optional tag-based pre-filtering.",
21838
22151
  inputSchema: external_exports.object({
21839
22152
  query: external_exports.string(),
21840
22153
  workspace_id: external_exports.string().uuid().optional(),
21841
22154
  project_id: external_exports.string().uuid().optional(),
21842
- limit: external_exports.number().optional()
22155
+ limit: external_exports.number().optional(),
22156
+ tags: external_exports.array(external_exports.string()).optional().describe("Filter results that contain ALL of these tags")
21843
22157
  })
21844
22158
  },
21845
22159
  async (input) => {
21846
22160
  const result = await client.memorySearch(input);
22161
+ if (input.tags && input.tags.length > 0 && result.results) {
22162
+ const requiredTags = input.tags;
22163
+ result.results = result.results.filter((item) => {
22164
+ const itemTags = extractEventTags(item);
22165
+ return requiredTags.every((tag) => itemTags.includes(tag));
22166
+ });
22167
+ }
21847
22168
  return {
21848
22169
  content: [{ type: "text", text: formatContent(result) }]
21849
22170
  };
@@ -23631,9 +23952,8 @@ Returns lessons filtered by:
23631
23952
  // Fetch more to filter
23632
23953
  });
23633
23954
  const lessons = (searchResult.results || []).filter((item) => {
23634
- const tags = item.metadata?.tags || [];
23635
- const isLesson = tags.includes("lesson");
23636
- if (!isLesson) return false;
23955
+ if (!isLessonResult(item)) return false;
23956
+ const tags = extractEventTags(item);
23637
23957
  if (input.category && !tags.includes(input.category)) {
23638
23958
  return false;
23639
23959
  }
@@ -23652,7 +23972,7 @@ Returns lessons filtered by:
23652
23972
  };
23653
23973
  }
23654
23974
  const formattedLessons = lessons.map((lesson, i) => {
23655
- const tags = lesson.metadata?.tags || [];
23975
+ const tags = extractEventTags(lesson);
23656
23976
  const severity = tags.find((t) => t.startsWith("severity:"))?.split(":")[1] || "medium";
23657
23977
  const category = tags.find(
23658
23978
  (t) => [
@@ -23671,7 +23991,7 @@ Returns lessons filtered by:
23671
23991
  }[severity] || "\u26AA";
23672
23992
  return `${i + 1}. ${severityEmoji} **${lesson.title}**
23673
23993
  Category: ${category} | Severity: ${severity}
23674
- ${lesson.content?.slice(0, 200)}...`;
23994
+ ${lesson.content?.slice(0, 500)}...`;
23675
23995
  }).join("\n\n");
23676
23996
  return {
23677
23997
  content: [
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.4.65",
4
+ "version": "0.4.66",
5
5
  "description": "ContextStream MCP server - v0.4.x with consolidated domain tools (~11 tools, ~75% token reduction). Code context, memory, search, and AI tools.",
6
6
  "type": "module",
7
7
  "license": "MIT",