@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.
- package/dist/index.js +337 -17
- 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
|
-
|
|
15839
|
-
const
|
|
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
|
|
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,
|
|
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
|
-
|
|
23635
|
-
const
|
|
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
|
|
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,
|
|
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.
|
|
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",
|