@contextstream/mcp-server 0.3.63 → 0.3.64
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 +1109 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7788,6 +7788,198 @@ function getCoreToolsHint() {
|
|
|
7788
7788
|
// src/tools.ts
|
|
7789
7789
|
var LESSON_DEDUP_WINDOW_MS = 2 * 60 * 1e3;
|
|
7790
7790
|
var recentLessonCaptures = /* @__PURE__ */ new Map();
|
|
7791
|
+
var DEFAULT_PARAM_DESCRIPTIONS = {
|
|
7792
|
+
api_key: "ContextStream API key.",
|
|
7793
|
+
apiKey: "ContextStream API key.",
|
|
7794
|
+
jwt: "ContextStream JWT for authentication.",
|
|
7795
|
+
workspace_id: "Workspace ID (UUID).",
|
|
7796
|
+
workspaceId: "Workspace ID (UUID).",
|
|
7797
|
+
project_id: "Project ID (UUID).",
|
|
7798
|
+
projectId: "Project ID (UUID).",
|
|
7799
|
+
node_id: "Node ID (UUID).",
|
|
7800
|
+
event_id: "Event ID (UUID).",
|
|
7801
|
+
reminder_id: "Reminder ID (UUID).",
|
|
7802
|
+
folder_path: "Absolute path to the local folder.",
|
|
7803
|
+
file_path: "Filesystem path to the file.",
|
|
7804
|
+
path: "Filesystem path.",
|
|
7805
|
+
name: "Name for the resource.",
|
|
7806
|
+
title: "Short descriptive title.",
|
|
7807
|
+
description: "Short description.",
|
|
7808
|
+
content: "Full content/body.",
|
|
7809
|
+
query: "Search query string.",
|
|
7810
|
+
limit: "Maximum number of results to return.",
|
|
7811
|
+
page: "Page number for pagination.",
|
|
7812
|
+
page_size: "Results per page.",
|
|
7813
|
+
include_decisions: "Include related decisions.",
|
|
7814
|
+
include_related: "Include related context.",
|
|
7815
|
+
include_transitive: "Include transitive dependencies.",
|
|
7816
|
+
max_depth: "Maximum traversal depth.",
|
|
7817
|
+
since: "ISO 8601 timestamp to query changes since.",
|
|
7818
|
+
remind_at: "ISO 8601 datetime for the reminder.",
|
|
7819
|
+
priority: "Priority level.",
|
|
7820
|
+
recurrence: "Recurrence pattern (daily, weekly, monthly).",
|
|
7821
|
+
keywords: "Keywords for matching.",
|
|
7822
|
+
overwrite: "Allow overwriting existing files on disk.",
|
|
7823
|
+
write_to_disk: "Write ingested files to disk before indexing.",
|
|
7824
|
+
await_indexing: "Wait for indexing to finish before returning.",
|
|
7825
|
+
auto_index: "Automatically index on creation.",
|
|
7826
|
+
session_id: "Session identifier.",
|
|
7827
|
+
context_hint: "User message used to fetch relevant context.",
|
|
7828
|
+
context: "Context to match relevant reminders."
|
|
7829
|
+
};
|
|
7830
|
+
var WRITE_VERBS = /* @__PURE__ */ new Set([
|
|
7831
|
+
"create",
|
|
7832
|
+
"update",
|
|
7833
|
+
"delete",
|
|
7834
|
+
"ingest",
|
|
7835
|
+
"index",
|
|
7836
|
+
"capture",
|
|
7837
|
+
"remember",
|
|
7838
|
+
"associate",
|
|
7839
|
+
"bootstrap",
|
|
7840
|
+
"snooze",
|
|
7841
|
+
"complete",
|
|
7842
|
+
"dismiss",
|
|
7843
|
+
"generate",
|
|
7844
|
+
"sync",
|
|
7845
|
+
"publish",
|
|
7846
|
+
"set",
|
|
7847
|
+
"add",
|
|
7848
|
+
"remove",
|
|
7849
|
+
"revoke",
|
|
7850
|
+
"upload",
|
|
7851
|
+
"compress",
|
|
7852
|
+
"init"
|
|
7853
|
+
]);
|
|
7854
|
+
var READ_ONLY_OVERRIDES = /* @__PURE__ */ new Set([
|
|
7855
|
+
"session_tools",
|
|
7856
|
+
"context_smart",
|
|
7857
|
+
"session_summary",
|
|
7858
|
+
"session_recall",
|
|
7859
|
+
"session_get_user_context",
|
|
7860
|
+
"session_get_lessons",
|
|
7861
|
+
"session_smart_search",
|
|
7862
|
+
"session_delta",
|
|
7863
|
+
"projects_list",
|
|
7864
|
+
"projects_get",
|
|
7865
|
+
"projects_overview",
|
|
7866
|
+
"projects_statistics",
|
|
7867
|
+
"projects_files",
|
|
7868
|
+
"projects_index_status",
|
|
7869
|
+
"workspaces_list",
|
|
7870
|
+
"workspaces_get",
|
|
7871
|
+
"memory_search",
|
|
7872
|
+
"memory_decisions",
|
|
7873
|
+
"memory_get_event",
|
|
7874
|
+
"memory_list_events",
|
|
7875
|
+
"memory_list_nodes",
|
|
7876
|
+
"memory_summary",
|
|
7877
|
+
"memory_timeline",
|
|
7878
|
+
"graph_related",
|
|
7879
|
+
"graph_decisions",
|
|
7880
|
+
"graph_path",
|
|
7881
|
+
"graph_dependencies",
|
|
7882
|
+
"graph_call_path",
|
|
7883
|
+
"graph_impact",
|
|
7884
|
+
"graph_circular_dependencies",
|
|
7885
|
+
"graph_unused_code",
|
|
7886
|
+
"search_semantic",
|
|
7887
|
+
"search_hybrid",
|
|
7888
|
+
"search_keyword",
|
|
7889
|
+
"search_pattern",
|
|
7890
|
+
"reminders_list",
|
|
7891
|
+
"reminders_active",
|
|
7892
|
+
"auth_me",
|
|
7893
|
+
"mcp_server_version"
|
|
7894
|
+
]);
|
|
7895
|
+
var DESTRUCTIVE_VERBS = /* @__PURE__ */ new Set(["delete", "dismiss", "remove", "revoke", "supersede"]);
|
|
7896
|
+
var OPEN_WORLD_PREFIXES = /* @__PURE__ */ new Set(["github", "slack", "integrations"]);
|
|
7897
|
+
function humanizeKey(raw) {
|
|
7898
|
+
const withSpaces = raw.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ");
|
|
7899
|
+
return withSpaces.toLowerCase();
|
|
7900
|
+
}
|
|
7901
|
+
function buildParamDescription(key, path7) {
|
|
7902
|
+
const normalized = key in DEFAULT_PARAM_DESCRIPTIONS ? key : key.toLowerCase();
|
|
7903
|
+
const parent = path7[path7.length - 1];
|
|
7904
|
+
if (parent === "target") {
|
|
7905
|
+
if (key === "id") return "Target identifier (module path, function id, etc.).";
|
|
7906
|
+
if (key === "type") return "Target type (module, file, function, type, variable).";
|
|
7907
|
+
}
|
|
7908
|
+
if (parent === "source") {
|
|
7909
|
+
if (key === "id") return "Source identifier (module path, function id, etc.).";
|
|
7910
|
+
if (key === "type") return "Source type (module, file, function, type, variable).";
|
|
7911
|
+
}
|
|
7912
|
+
if (DEFAULT_PARAM_DESCRIPTIONS[normalized]) {
|
|
7913
|
+
return DEFAULT_PARAM_DESCRIPTIONS[normalized];
|
|
7914
|
+
}
|
|
7915
|
+
if (normalized.endsWith("_id")) {
|
|
7916
|
+
return `ID for the ${humanizeKey(normalized.replace(/_id$/, ""))}.`;
|
|
7917
|
+
}
|
|
7918
|
+
if (normalized.startsWith("include_")) {
|
|
7919
|
+
return `Whether to include ${humanizeKey(normalized.replace("include_", ""))}.`;
|
|
7920
|
+
}
|
|
7921
|
+
if (normalized.startsWith("max_")) {
|
|
7922
|
+
return `Maximum ${humanizeKey(normalized.replace("max_", ""))}.`;
|
|
7923
|
+
}
|
|
7924
|
+
if (normalized.startsWith("min_")) {
|
|
7925
|
+
return `Minimum ${humanizeKey(normalized.replace("min_", ""))}.`;
|
|
7926
|
+
}
|
|
7927
|
+
return `Input parameter: ${humanizeKey(normalized)}.`;
|
|
7928
|
+
}
|
|
7929
|
+
function getDescription(schema) {
|
|
7930
|
+
const def = schema._def;
|
|
7931
|
+
if (def?.description && def.description.trim()) return def.description;
|
|
7932
|
+
return void 0;
|
|
7933
|
+
}
|
|
7934
|
+
function applyParamDescriptions(schema, path7 = []) {
|
|
7935
|
+
if (!(schema instanceof external_exports.ZodObject)) {
|
|
7936
|
+
return schema;
|
|
7937
|
+
}
|
|
7938
|
+
const shape = schema.shape;
|
|
7939
|
+
let changed = false;
|
|
7940
|
+
const nextShape = {};
|
|
7941
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
7942
|
+
let nextField = field;
|
|
7943
|
+
const existingDescription = getDescription(field);
|
|
7944
|
+
if (field instanceof external_exports.ZodObject) {
|
|
7945
|
+
const nested = applyParamDescriptions(field, [...path7, key]);
|
|
7946
|
+
if (nested !== field) {
|
|
7947
|
+
nextField = nested;
|
|
7948
|
+
changed = true;
|
|
7949
|
+
}
|
|
7950
|
+
}
|
|
7951
|
+
if (existingDescription) {
|
|
7952
|
+
if (!getDescription(nextField)) {
|
|
7953
|
+
nextField = nextField.describe(existingDescription);
|
|
7954
|
+
changed = true;
|
|
7955
|
+
}
|
|
7956
|
+
} else {
|
|
7957
|
+
nextField = nextField.describe(buildParamDescription(key, path7));
|
|
7958
|
+
changed = true;
|
|
7959
|
+
}
|
|
7960
|
+
nextShape[key] = nextField;
|
|
7961
|
+
}
|
|
7962
|
+
if (!changed) return schema;
|
|
7963
|
+
let nextSchema = external_exports.object(nextShape);
|
|
7964
|
+
const def = schema._def;
|
|
7965
|
+
if (def?.catchall) nextSchema = nextSchema.catchall(def.catchall);
|
|
7966
|
+
if (def?.unknownKeys === "passthrough") nextSchema = nextSchema.passthrough();
|
|
7967
|
+
if (def?.unknownKeys === "strict") nextSchema = nextSchema.strict();
|
|
7968
|
+
return nextSchema;
|
|
7969
|
+
}
|
|
7970
|
+
function inferToolAnnotations(toolName) {
|
|
7971
|
+
const parts = toolName.split("_");
|
|
7972
|
+
const prefix = parts[0] || toolName;
|
|
7973
|
+
const readOnly = READ_ONLY_OVERRIDES.has(toolName) || !parts.some((part) => WRITE_VERBS.has(part));
|
|
7974
|
+
const destructive = readOnly ? false : parts.some((part) => DESTRUCTIVE_VERBS.has(part));
|
|
7975
|
+
const openWorld = OPEN_WORLD_PREFIXES.has(prefix);
|
|
7976
|
+
return {
|
|
7977
|
+
readOnlyHint: readOnly,
|
|
7978
|
+
destructiveHint: readOnly ? false : destructive,
|
|
7979
|
+
idempotentHint: readOnly,
|
|
7980
|
+
openWorldHint: openWorld
|
|
7981
|
+
};
|
|
7982
|
+
}
|
|
7791
7983
|
function normalizeHeaderValue(value) {
|
|
7792
7984
|
if (!value) return void 0;
|
|
7793
7985
|
return Array.isArray(value) ? value[0] : value;
|
|
@@ -8043,7 +8235,7 @@ function isDuplicateLessonCapture(signature) {
|
|
|
8043
8235
|
return false;
|
|
8044
8236
|
}
|
|
8045
8237
|
function registerTools(server, client, sessionManager) {
|
|
8046
|
-
const
|
|
8238
|
+
const upgradeUrl2 = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
|
|
8047
8239
|
const toolFilter = resolveToolFilter();
|
|
8048
8240
|
const toolAllowlist = toolFilter.allowlist;
|
|
8049
8241
|
if (toolAllowlist) {
|
|
@@ -8099,7 +8291,7 @@ function registerTools(server, client, sessionManager) {
|
|
|
8099
8291
|
return errorResult(
|
|
8100
8292
|
[
|
|
8101
8293
|
`Access denied: \`${toolName}\` requires ContextStream PRO.`,
|
|
8102
|
-
`Upgrade: ${
|
|
8294
|
+
`Upgrade: ${upgradeUrl2}`
|
|
8103
8295
|
].join("\n")
|
|
8104
8296
|
);
|
|
8105
8297
|
}
|
|
@@ -8127,7 +8319,7 @@ function registerTools(server, client, sessionManager) {
|
|
|
8127
8319
|
[
|
|
8128
8320
|
`Access denied: \`${toolName}\` is limited to Graph-Lite (module-level, 1-hop queries).`,
|
|
8129
8321
|
detail,
|
|
8130
|
-
`Upgrade to Elite or Team for full graph access: ${
|
|
8322
|
+
`Upgrade to Elite or Team for full graph access: ${upgradeUrl2}`
|
|
8131
8323
|
].join("\n")
|
|
8132
8324
|
);
|
|
8133
8325
|
}
|
|
@@ -8142,7 +8334,7 @@ function registerTools(server, client, sessionManager) {
|
|
|
8142
8334
|
[
|
|
8143
8335
|
`Access denied: \`${toolName}\` requires Elite or Team (Full Graph).`,
|
|
8144
8336
|
"Pro includes Graph-Lite (module-level dependencies and 1-hop impact only).",
|
|
8145
|
-
`Upgrade: ${
|
|
8337
|
+
`Upgrade: ${upgradeUrl2}`
|
|
8146
8338
|
].join("\n")
|
|
8147
8339
|
);
|
|
8148
8340
|
}
|
|
@@ -8187,7 +8379,7 @@ function registerTools(server, client, sessionManager) {
|
|
|
8187
8379
|
return errorResult(
|
|
8188
8380
|
[
|
|
8189
8381
|
`Access denied: \`${toolName}\` requires ContextStream Pro (Graph-Lite) or Elite/Team (Full Graph).`,
|
|
8190
|
-
`Upgrade: ${
|
|
8382
|
+
`Upgrade: ${upgradeUrl2}`
|
|
8191
8383
|
].join("\n")
|
|
8192
8384
|
);
|
|
8193
8385
|
}
|
|
@@ -8235,7 +8427,15 @@ function registerTools(server, client, sessionManager) {
|
|
|
8235
8427
|
title: `${config.title} (${accessLabel})`,
|
|
8236
8428
|
description: `${config.description}
|
|
8237
8429
|
|
|
8238
|
-
Access: ${accessLabel}${showUpgrade ? ` (upgrade: ${
|
|
8430
|
+
Access: ${accessLabel}${showUpgrade ? ` (upgrade: ${upgradeUrl2})` : ""}`
|
|
8431
|
+
};
|
|
8432
|
+
const annotatedConfig = {
|
|
8433
|
+
...labeledConfig,
|
|
8434
|
+
inputSchema: labeledConfig.inputSchema ? applyParamDescriptions(labeledConfig.inputSchema) : void 0,
|
|
8435
|
+
annotations: {
|
|
8436
|
+
...inferToolAnnotations(name),
|
|
8437
|
+
...labeledConfig.annotations
|
|
8438
|
+
}
|
|
8239
8439
|
};
|
|
8240
8440
|
const safeHandler = async (input, extra) => {
|
|
8241
8441
|
try {
|
|
@@ -8248,7 +8448,7 @@ Access: ${accessLabel}${showUpgrade ? ` (upgrade: ${upgradeUrl})` : ""}`
|
|
|
8248
8448
|
const errorCode = error?.code || error?.status || "UNKNOWN_ERROR";
|
|
8249
8449
|
const isPlanLimit = String(errorCode).toUpperCase() === "FORBIDDEN" && String(errorMessage).toLowerCase().includes("plan limit reached");
|
|
8250
8450
|
const upgradeHint = isPlanLimit ? `
|
|
8251
|
-
Upgrade: ${
|
|
8451
|
+
Upgrade: ${upgradeUrl2}` : "";
|
|
8252
8452
|
const errorPayload = {
|
|
8253
8453
|
success: false,
|
|
8254
8454
|
error: {
|
|
@@ -8267,7 +8467,7 @@ Upgrade: ${upgradeUrl}` : "";
|
|
|
8267
8467
|
};
|
|
8268
8468
|
server.registerTool(
|
|
8269
8469
|
name,
|
|
8270
|
-
|
|
8470
|
+
annotatedConfig,
|
|
8271
8471
|
wrapWithAutoContext(name, safeHandler)
|
|
8272
8472
|
);
|
|
8273
8473
|
}
|
|
@@ -11132,10 +11332,33 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
11132
11332
|
function wrapText(uri, text) {
|
|
11133
11333
|
return { contents: [{ uri, text }] };
|
|
11134
11334
|
}
|
|
11335
|
+
function wrapResource(resource) {
|
|
11336
|
+
return { resources: [resource] };
|
|
11337
|
+
}
|
|
11338
|
+
function extractItems(payload) {
|
|
11339
|
+
if (!payload || typeof payload !== "object") return [];
|
|
11340
|
+
const direct = payload.items;
|
|
11341
|
+
if (Array.isArray(direct)) return direct;
|
|
11342
|
+
const nested = payload.data;
|
|
11343
|
+
if (nested && typeof nested === "object") {
|
|
11344
|
+
const nestedItems = nested.items;
|
|
11345
|
+
if (Array.isArray(nestedItems)) return nestedItems;
|
|
11346
|
+
if (Array.isArray(nested)) return nested;
|
|
11347
|
+
}
|
|
11348
|
+
return [];
|
|
11349
|
+
}
|
|
11135
11350
|
function registerResources(server, client, apiUrl) {
|
|
11136
11351
|
server.registerResource(
|
|
11137
11352
|
"contextstream-openapi",
|
|
11138
|
-
new ResourceTemplate("contextstream:openapi", {
|
|
11353
|
+
new ResourceTemplate("contextstream:openapi", {
|
|
11354
|
+
list: () => wrapResource({
|
|
11355
|
+
uri: "contextstream:openapi",
|
|
11356
|
+
name: "contextstream-openapi",
|
|
11357
|
+
title: "ContextStream OpenAPI",
|
|
11358
|
+
description: "Machine-readable OpenAPI from the configured API endpoint",
|
|
11359
|
+
mimeType: "application/json"
|
|
11360
|
+
})
|
|
11361
|
+
}),
|
|
11139
11362
|
{
|
|
11140
11363
|
title: "ContextStream OpenAPI spec",
|
|
11141
11364
|
description: "Machine-readable OpenAPI from the configured API endpoint",
|
|
@@ -11150,7 +11373,15 @@ function registerResources(server, client, apiUrl) {
|
|
|
11150
11373
|
);
|
|
11151
11374
|
server.registerResource(
|
|
11152
11375
|
"contextstream-workspaces",
|
|
11153
|
-
new ResourceTemplate("contextstream:workspaces", {
|
|
11376
|
+
new ResourceTemplate("contextstream:workspaces", {
|
|
11377
|
+
list: () => wrapResource({
|
|
11378
|
+
uri: "contextstream:workspaces",
|
|
11379
|
+
name: "contextstream-workspaces",
|
|
11380
|
+
title: "Workspaces",
|
|
11381
|
+
description: "List of accessible workspaces",
|
|
11382
|
+
mimeType: "application/json"
|
|
11383
|
+
})
|
|
11384
|
+
}),
|
|
11154
11385
|
{ title: "Workspaces", description: "List of accessible workspaces" },
|
|
11155
11386
|
async () => {
|
|
11156
11387
|
const data = await client.listWorkspaces();
|
|
@@ -11159,7 +11390,36 @@ function registerResources(server, client, apiUrl) {
|
|
|
11159
11390
|
);
|
|
11160
11391
|
server.registerResource(
|
|
11161
11392
|
"contextstream-projects",
|
|
11162
|
-
new ResourceTemplate("contextstream:projects/{workspaceId}", {
|
|
11393
|
+
new ResourceTemplate("contextstream:projects/{workspaceId}", {
|
|
11394
|
+
list: async () => {
|
|
11395
|
+
try {
|
|
11396
|
+
const workspaces = await client.listWorkspaces({ page_size: 50 });
|
|
11397
|
+
const items = extractItems(workspaces);
|
|
11398
|
+
return {
|
|
11399
|
+
resources: items.map((workspace) => ({
|
|
11400
|
+
uri: `contextstream:projects/${workspace.id}`,
|
|
11401
|
+
name: `contextstream-projects-${workspace.id}`,
|
|
11402
|
+
title: workspace.name ? `Projects in ${workspace.name}` : "Projects in workspace",
|
|
11403
|
+
description: "Projects in the specified workspace",
|
|
11404
|
+
mimeType: "application/json"
|
|
11405
|
+
}))
|
|
11406
|
+
};
|
|
11407
|
+
} catch {
|
|
11408
|
+
return { resources: [] };
|
|
11409
|
+
}
|
|
11410
|
+
},
|
|
11411
|
+
complete: {
|
|
11412
|
+
workspaceId: async () => {
|
|
11413
|
+
try {
|
|
11414
|
+
const workspaces = await client.listWorkspaces({ page_size: 50 });
|
|
11415
|
+
const items = extractItems(workspaces);
|
|
11416
|
+
return items.map((workspace) => workspace.id);
|
|
11417
|
+
} catch {
|
|
11418
|
+
return [];
|
|
11419
|
+
}
|
|
11420
|
+
}
|
|
11421
|
+
}
|
|
11422
|
+
}),
|
|
11163
11423
|
{ title: "Projects for workspace", description: "Projects in the specified workspace" },
|
|
11164
11424
|
async (uri, { workspaceId }) => {
|
|
11165
11425
|
const wsId = Array.isArray(workspaceId) ? workspaceId[0] : workspaceId;
|
|
@@ -11169,6 +11429,723 @@ function registerResources(server, client, apiUrl) {
|
|
|
11169
11429
|
);
|
|
11170
11430
|
}
|
|
11171
11431
|
|
|
11432
|
+
// src/prompts.ts
|
|
11433
|
+
var ID_NOTES = [
|
|
11434
|
+
"Notes:",
|
|
11435
|
+
"- If ContextStream is not initialized in this conversation, call `session_init` first (omit ids).",
|
|
11436
|
+
"- Do not ask me for `workspace_id`/`project_id` \u2014 use session defaults or IDs returned by `session_init`.",
|
|
11437
|
+
"- Prefer omitting IDs in tool calls when the tool supports defaults."
|
|
11438
|
+
];
|
|
11439
|
+
var upgradeUrl = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
|
|
11440
|
+
var proPrompts = /* @__PURE__ */ new Set([
|
|
11441
|
+
"build-context",
|
|
11442
|
+
"generate-plan",
|
|
11443
|
+
"generate-tasks",
|
|
11444
|
+
"token-budget-context"
|
|
11445
|
+
]);
|
|
11446
|
+
function promptAccessLabel(promptName) {
|
|
11447
|
+
return proPrompts.has(promptName) ? "PRO" : "Free";
|
|
11448
|
+
}
|
|
11449
|
+
function registerPrompts(server) {
|
|
11450
|
+
server.registerPrompt(
|
|
11451
|
+
"explore-codebase",
|
|
11452
|
+
{
|
|
11453
|
+
title: `Explore Codebase (${promptAccessLabel("explore-codebase")})`,
|
|
11454
|
+
description: "Get an overview of a project codebase structure and key components"
|
|
11455
|
+
},
|
|
11456
|
+
async () => ({
|
|
11457
|
+
messages: [
|
|
11458
|
+
{
|
|
11459
|
+
role: "user",
|
|
11460
|
+
content: {
|
|
11461
|
+
type: "text",
|
|
11462
|
+
text: [
|
|
11463
|
+
"I want to understand the current codebase.",
|
|
11464
|
+
"",
|
|
11465
|
+
...ID_NOTES,
|
|
11466
|
+
"",
|
|
11467
|
+
"Please help me by:",
|
|
11468
|
+
"1. Use `projects_overview` to get a project summary (use session defaults; only pass `project_id` if required).",
|
|
11469
|
+
"2. Use `projects_files` to identify key entry points.",
|
|
11470
|
+
"3. If a focus area is clear from our conversation, prioritize it; otherwise ask me what to focus on.",
|
|
11471
|
+
"4. Use `search_semantic` (and optionally `search_hybrid`) to find the most relevant files.",
|
|
11472
|
+
"5. Summarize the architecture, major modules, and where to start editing."
|
|
11473
|
+
].join("\n")
|
|
11474
|
+
}
|
|
11475
|
+
}
|
|
11476
|
+
]
|
|
11477
|
+
})
|
|
11478
|
+
);
|
|
11479
|
+
server.registerPrompt(
|
|
11480
|
+
"capture-decision",
|
|
11481
|
+
{
|
|
11482
|
+
title: `Capture Decision (${promptAccessLabel("capture-decision")})`,
|
|
11483
|
+
description: "Document an architectural or technical decision in workspace memory"
|
|
11484
|
+
},
|
|
11485
|
+
async () => ({
|
|
11486
|
+
messages: [
|
|
11487
|
+
{
|
|
11488
|
+
role: "user",
|
|
11489
|
+
content: {
|
|
11490
|
+
type: "text",
|
|
11491
|
+
text: [
|
|
11492
|
+
"Please capture an architectural/technical decision in ContextStream memory.",
|
|
11493
|
+
"",
|
|
11494
|
+
...ID_NOTES,
|
|
11495
|
+
"",
|
|
11496
|
+
"Instructions:",
|
|
11497
|
+
"- If the decision is already described in this conversation, extract: title, context, decision, consequences/tradeoffs.",
|
|
11498
|
+
"- If anything is missing, ask me 1\u20133 quick questions to fill the gaps.",
|
|
11499
|
+
"- Then call `session_capture` with:",
|
|
11500
|
+
' - event_type: "decision"',
|
|
11501
|
+
" - title: (short ADR title)",
|
|
11502
|
+
" - content: a well-formatted ADR (Context, Decision, Consequences)",
|
|
11503
|
+
' - tags: include relevant tags (e.g., "adr", "architecture")',
|
|
11504
|
+
' - importance: "high"',
|
|
11505
|
+
"",
|
|
11506
|
+
"After capturing, confirm what was saved."
|
|
11507
|
+
].join("\n")
|
|
11508
|
+
}
|
|
11509
|
+
}
|
|
11510
|
+
]
|
|
11511
|
+
})
|
|
11512
|
+
);
|
|
11513
|
+
server.registerPrompt(
|
|
11514
|
+
"review-context",
|
|
11515
|
+
{
|
|
11516
|
+
title: `Code Review Context (${promptAccessLabel("review-context")})`,
|
|
11517
|
+
description: "Build context for reviewing code changes"
|
|
11518
|
+
},
|
|
11519
|
+
async () => ({
|
|
11520
|
+
messages: [
|
|
11521
|
+
{
|
|
11522
|
+
role: "user",
|
|
11523
|
+
content: {
|
|
11524
|
+
type: "text",
|
|
11525
|
+
text: [
|
|
11526
|
+
"I need context to review a set of code changes.",
|
|
11527
|
+
"",
|
|
11528
|
+
...ID_NOTES,
|
|
11529
|
+
"",
|
|
11530
|
+
"First:",
|
|
11531
|
+
"- If file paths and a short change description are not already in this conversation, ask me for them.",
|
|
11532
|
+
"",
|
|
11533
|
+
"Then build review context by:",
|
|
11534
|
+
"1. Using `graph_dependencies` to find what depends on the changed areas.",
|
|
11535
|
+
"2. Using `graph_impact` to assess potential blast radius.",
|
|
11536
|
+
"3. Using `memory_search` to find related decisions/notes.",
|
|
11537
|
+
"4. Using `search_semantic` to find related code patterns.",
|
|
11538
|
+
"",
|
|
11539
|
+
"Provide:",
|
|
11540
|
+
"- What the files/components do",
|
|
11541
|
+
"- What might be affected",
|
|
11542
|
+
"- Relevant prior decisions/lessons",
|
|
11543
|
+
"- Review checklist + risks to focus on"
|
|
11544
|
+
].join("\n")
|
|
11545
|
+
}
|
|
11546
|
+
}
|
|
11547
|
+
]
|
|
11548
|
+
})
|
|
11549
|
+
);
|
|
11550
|
+
server.registerPrompt(
|
|
11551
|
+
"investigate-bug",
|
|
11552
|
+
{
|
|
11553
|
+
title: `Investigate Bug (${promptAccessLabel("investigate-bug")})`,
|
|
11554
|
+
description: "Build context for debugging an issue"
|
|
11555
|
+
},
|
|
11556
|
+
async () => ({
|
|
11557
|
+
messages: [
|
|
11558
|
+
{
|
|
11559
|
+
role: "user",
|
|
11560
|
+
content: {
|
|
11561
|
+
type: "text",
|
|
11562
|
+
text: [
|
|
11563
|
+
"I want help investigating a bug.",
|
|
11564
|
+
"",
|
|
11565
|
+
...ID_NOTES,
|
|
11566
|
+
"",
|
|
11567
|
+
"First:",
|
|
11568
|
+
"- If the error/symptom is not already stated, ask me for the exact error message and what I expected vs what happened.",
|
|
11569
|
+
"- If an affected area/component is not known, ask me where I noticed it.",
|
|
11570
|
+
"",
|
|
11571
|
+
"Then:",
|
|
11572
|
+
"1. Use `search_semantic` to find code related to the error/symptom.",
|
|
11573
|
+
"2. Use `search_pattern` to locate where similar errors are thrown or logged.",
|
|
11574
|
+
"3. If you identify key functions, use `graph_call_path` to trace call flows.",
|
|
11575
|
+
"4. Use `memory_search` to check if we have prior notes/bugs about this area.",
|
|
11576
|
+
"",
|
|
11577
|
+
"Return:",
|
|
11578
|
+
"- Likely origin locations",
|
|
11579
|
+
"- Call flow (if found)",
|
|
11580
|
+
"- Related past context",
|
|
11581
|
+
"- Suggested debugging steps"
|
|
11582
|
+
].join("\n")
|
|
11583
|
+
}
|
|
11584
|
+
}
|
|
11585
|
+
]
|
|
11586
|
+
})
|
|
11587
|
+
);
|
|
11588
|
+
server.registerPrompt(
|
|
11589
|
+
"explore-knowledge",
|
|
11590
|
+
{
|
|
11591
|
+
title: `Explore Knowledge Graph (${promptAccessLabel("explore-knowledge")})`,
|
|
11592
|
+
description: "Navigate and understand the knowledge graph for a workspace"
|
|
11593
|
+
},
|
|
11594
|
+
async () => ({
|
|
11595
|
+
messages: [
|
|
11596
|
+
{
|
|
11597
|
+
role: "user",
|
|
11598
|
+
content: {
|
|
11599
|
+
type: "text",
|
|
11600
|
+
text: [
|
|
11601
|
+
"Help me explore the knowledge captured in this workspace.",
|
|
11602
|
+
"",
|
|
11603
|
+
...ID_NOTES,
|
|
11604
|
+
"",
|
|
11605
|
+
"Approach:",
|
|
11606
|
+
"1. Use `memory_summary` for a high-level overview.",
|
|
11607
|
+
"2. Use `memory_decisions` to see decision history (titles + a few key details).",
|
|
11608
|
+
"3. Use `memory_list_nodes` to see available knowledge nodes.",
|
|
11609
|
+
"4. If a starting topic is clear from the conversation, use `memory_search` for it.",
|
|
11610
|
+
"5. Use `graph_related` on the most relevant nodes to expand connections.",
|
|
11611
|
+
"",
|
|
11612
|
+
"Provide:",
|
|
11613
|
+
"- Key themes and topics",
|
|
11614
|
+
"- Important decisions + rationale",
|
|
11615
|
+
"- Suggested \u201Cnext nodes\u201D to explore"
|
|
11616
|
+
].join("\n")
|
|
11617
|
+
}
|
|
11618
|
+
}
|
|
11619
|
+
]
|
|
11620
|
+
})
|
|
11621
|
+
);
|
|
11622
|
+
server.registerPrompt(
|
|
11623
|
+
"onboard-to-project",
|
|
11624
|
+
{
|
|
11625
|
+
title: `Project Onboarding (${promptAccessLabel("onboard-to-project")})`,
|
|
11626
|
+
description: "Generate onboarding context for a new team member"
|
|
11627
|
+
},
|
|
11628
|
+
async () => ({
|
|
11629
|
+
messages: [
|
|
11630
|
+
{
|
|
11631
|
+
role: "user",
|
|
11632
|
+
content: {
|
|
11633
|
+
type: "text",
|
|
11634
|
+
text: [
|
|
11635
|
+
"Create an onboarding guide for a new team member joining this project.",
|
|
11636
|
+
"",
|
|
11637
|
+
...ID_NOTES,
|
|
11638
|
+
"",
|
|
11639
|
+
"First:",
|
|
11640
|
+
"- If the role is not specified, ask me what role they are onboarding into (backend, frontend, fullstack, etc.).",
|
|
11641
|
+
"",
|
|
11642
|
+
"Gather context:",
|
|
11643
|
+
"1. Use `projects_overview` and `projects_statistics` for project summary.",
|
|
11644
|
+
"2. Use `projects_files` to identify key entry points.",
|
|
11645
|
+
"3. Use `memory_timeline` and `memory_decisions` to understand recent changes and architectural choices.",
|
|
11646
|
+
"4. Use `search_semantic` to find READMEs/docs/setup instructions.",
|
|
11647
|
+
"",
|
|
11648
|
+
"Output:",
|
|
11649
|
+
"- Project overview and purpose",
|
|
11650
|
+
"- Tech stack + architecture map",
|
|
11651
|
+
"- Key files/entry points relevant to the role",
|
|
11652
|
+
"- Important decisions + rationale",
|
|
11653
|
+
"- Recent changes/current focus",
|
|
11654
|
+
"- Step-by-step getting started"
|
|
11655
|
+
].join("\n")
|
|
11656
|
+
}
|
|
11657
|
+
}
|
|
11658
|
+
]
|
|
11659
|
+
})
|
|
11660
|
+
);
|
|
11661
|
+
server.registerPrompt(
|
|
11662
|
+
"analyze-refactoring",
|
|
11663
|
+
{
|
|
11664
|
+
title: `Refactoring Analysis (${promptAccessLabel("analyze-refactoring")})`,
|
|
11665
|
+
description: "Analyze a codebase for refactoring opportunities"
|
|
11666
|
+
},
|
|
11667
|
+
async () => ({
|
|
11668
|
+
messages: [
|
|
11669
|
+
{
|
|
11670
|
+
role: "user",
|
|
11671
|
+
content: {
|
|
11672
|
+
type: "text",
|
|
11673
|
+
text: [
|
|
11674
|
+
"Analyze the codebase for refactoring opportunities.",
|
|
11675
|
+
"",
|
|
11676
|
+
...ID_NOTES,
|
|
11677
|
+
"",
|
|
11678
|
+
"If a target area is obvious from our conversation, focus there; otherwise ask me what area to analyze.",
|
|
11679
|
+
"",
|
|
11680
|
+
"Please investigate:",
|
|
11681
|
+
"1. `graph_circular_dependencies` (circular deps to break)",
|
|
11682
|
+
"2. `graph_unused_code` (dead code to remove)",
|
|
11683
|
+
"3. `search_pattern` (duplication patterns)",
|
|
11684
|
+
"4. `projects_statistics` (high complexity hotspots)",
|
|
11685
|
+
"",
|
|
11686
|
+
"Provide a prioritized list with quick wins vs deeper refactors."
|
|
11687
|
+
].join("\n")
|
|
11688
|
+
}
|
|
11689
|
+
}
|
|
11690
|
+
]
|
|
11691
|
+
})
|
|
11692
|
+
);
|
|
11693
|
+
server.registerPrompt(
|
|
11694
|
+
"build-context",
|
|
11695
|
+
{
|
|
11696
|
+
title: `Build LLM Context (${promptAccessLabel("build-context")})`,
|
|
11697
|
+
description: "Build comprehensive context for an LLM task"
|
|
11698
|
+
},
|
|
11699
|
+
async () => ({
|
|
11700
|
+
messages: [
|
|
11701
|
+
{
|
|
11702
|
+
role: "user",
|
|
11703
|
+
content: {
|
|
11704
|
+
type: "text",
|
|
11705
|
+
text: [
|
|
11706
|
+
"Build comprehensive context for the task we are working on.",
|
|
11707
|
+
"",
|
|
11708
|
+
`Access: ${promptAccessLabel("build-context")}${promptAccessLabel("build-context") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
|
|
11709
|
+
"",
|
|
11710
|
+
...ID_NOTES,
|
|
11711
|
+
"",
|
|
11712
|
+
"First:",
|
|
11713
|
+
"- If the \u201Cquery\u201D is clear from the latest user request, use that.",
|
|
11714
|
+
"- Otherwise ask me: \u201CWhat do you need context for?\u201D",
|
|
11715
|
+
"",
|
|
11716
|
+
"Then:",
|
|
11717
|
+
"- Call `ai_enhanced_context` with include_code=true, include_docs=true, include_memory=true (omit IDs unless required).",
|
|
11718
|
+
"- Synthesize the returned context into a short briefing with links/file paths and key decisions/risks."
|
|
11719
|
+
].join("\n")
|
|
11720
|
+
}
|
|
11721
|
+
}
|
|
11722
|
+
]
|
|
11723
|
+
})
|
|
11724
|
+
);
|
|
11725
|
+
server.registerPrompt(
|
|
11726
|
+
"smart-search",
|
|
11727
|
+
{
|
|
11728
|
+
title: `Smart Search (${promptAccessLabel("smart-search")})`,
|
|
11729
|
+
description: "Search across memory, decisions, and code for a query"
|
|
11730
|
+
},
|
|
11731
|
+
async () => ({
|
|
11732
|
+
messages: [
|
|
11733
|
+
{
|
|
11734
|
+
role: "user",
|
|
11735
|
+
content: {
|
|
11736
|
+
type: "text",
|
|
11737
|
+
text: [
|
|
11738
|
+
"Find the most relevant context for what I am asking about.",
|
|
11739
|
+
"",
|
|
11740
|
+
...ID_NOTES,
|
|
11741
|
+
"",
|
|
11742
|
+
"First:",
|
|
11743
|
+
"- If a query is clear from the conversation, use it.",
|
|
11744
|
+
"- Otherwise ask me what I want to find.",
|
|
11745
|
+
"",
|
|
11746
|
+
"Then:",
|
|
11747
|
+
"1. Use `session_smart_search` for the query.",
|
|
11748
|
+
"2. If results are thin, follow up with `search_hybrid` and `memory_search`.",
|
|
11749
|
+
"3. Return the top results with file paths/links and a short synthesis."
|
|
11750
|
+
].join("\n")
|
|
11751
|
+
}
|
|
11752
|
+
}
|
|
11753
|
+
]
|
|
11754
|
+
})
|
|
11755
|
+
);
|
|
11756
|
+
server.registerPrompt(
|
|
11757
|
+
"recall-context",
|
|
11758
|
+
{
|
|
11759
|
+
title: `Recall Context (${promptAccessLabel("recall-context")})`,
|
|
11760
|
+
description: "Retrieve relevant past decisions and memory for a query"
|
|
11761
|
+
},
|
|
11762
|
+
async () => ({
|
|
11763
|
+
messages: [
|
|
11764
|
+
{
|
|
11765
|
+
role: "user",
|
|
11766
|
+
content: {
|
|
11767
|
+
type: "text",
|
|
11768
|
+
text: [
|
|
11769
|
+
"Recall relevant past context (decisions, notes, lessons) for what I am asking about.",
|
|
11770
|
+
"",
|
|
11771
|
+
...ID_NOTES,
|
|
11772
|
+
"",
|
|
11773
|
+
"First:",
|
|
11774
|
+
"- If a recall query is clear from the conversation, use it.",
|
|
11775
|
+
"- Otherwise ask me what topic I want to recall.",
|
|
11776
|
+
"",
|
|
11777
|
+
"Then:",
|
|
11778
|
+
"- Use `session_recall` with the query (omit IDs unless required).",
|
|
11779
|
+
"- Summarize the key points and any relevant decisions/lessons."
|
|
11780
|
+
].join("\n")
|
|
11781
|
+
}
|
|
11782
|
+
}
|
|
11783
|
+
]
|
|
11784
|
+
})
|
|
11785
|
+
);
|
|
11786
|
+
server.registerPrompt(
|
|
11787
|
+
"session-summary",
|
|
11788
|
+
{
|
|
11789
|
+
title: `Session Summary (${promptAccessLabel("session-summary")})`,
|
|
11790
|
+
description: "Get a compact summary of workspace/project context"
|
|
11791
|
+
},
|
|
11792
|
+
async () => ({
|
|
11793
|
+
messages: [
|
|
11794
|
+
{
|
|
11795
|
+
role: "user",
|
|
11796
|
+
content: {
|
|
11797
|
+
type: "text",
|
|
11798
|
+
text: [
|
|
11799
|
+
"Generate a compact, token-efficient summary of the current workspace/project context.",
|
|
11800
|
+
"",
|
|
11801
|
+
...ID_NOTES,
|
|
11802
|
+
"",
|
|
11803
|
+
"Use `session_summary` (default max_tokens=500 unless I specify otherwise).",
|
|
11804
|
+
"Then list:",
|
|
11805
|
+
"- Top decisions (titles only)",
|
|
11806
|
+
"- Any high-priority lessons to watch for"
|
|
11807
|
+
].join("\n")
|
|
11808
|
+
}
|
|
11809
|
+
}
|
|
11810
|
+
]
|
|
11811
|
+
})
|
|
11812
|
+
);
|
|
11813
|
+
server.registerPrompt(
|
|
11814
|
+
"capture-lesson",
|
|
11815
|
+
{
|
|
11816
|
+
title: `Capture Lesson (${promptAccessLabel("capture-lesson")})`,
|
|
11817
|
+
description: "Record a lesson learned from an error or correction"
|
|
11818
|
+
},
|
|
11819
|
+
async () => ({
|
|
11820
|
+
messages: [
|
|
11821
|
+
{
|
|
11822
|
+
role: "user",
|
|
11823
|
+
content: {
|
|
11824
|
+
type: "text",
|
|
11825
|
+
text: [
|
|
11826
|
+
"Capture a lesson learned so it is surfaced in future sessions.",
|
|
11827
|
+
"",
|
|
11828
|
+
...ID_NOTES,
|
|
11829
|
+
"",
|
|
11830
|
+
"If the lesson details are not fully present in the conversation, ask me for:",
|
|
11831
|
+
"- title (what to remember)",
|
|
11832
|
+
"- severity (low|medium|high|critical, default medium)",
|
|
11833
|
+
"- category (workflow|code_quality|verification|communication|project_specific)",
|
|
11834
|
+
"- trigger (what caused it)",
|
|
11835
|
+
"- impact (what went wrong)",
|
|
11836
|
+
"- prevention (how to prevent it)",
|
|
11837
|
+
"- keywords (optional)",
|
|
11838
|
+
"",
|
|
11839
|
+
"Then call `session_capture_lesson` with those fields and confirm it was saved."
|
|
11840
|
+
].join("\n")
|
|
11841
|
+
}
|
|
11842
|
+
}
|
|
11843
|
+
]
|
|
11844
|
+
})
|
|
11845
|
+
);
|
|
11846
|
+
server.registerPrompt(
|
|
11847
|
+
"capture-preference",
|
|
11848
|
+
{
|
|
11849
|
+
title: `Capture Preference (${promptAccessLabel("capture-preference")})`,
|
|
11850
|
+
description: "Save a user preference to memory"
|
|
11851
|
+
},
|
|
11852
|
+
async () => ({
|
|
11853
|
+
messages: [
|
|
11854
|
+
{
|
|
11855
|
+
role: "user",
|
|
11856
|
+
content: {
|
|
11857
|
+
type: "text",
|
|
11858
|
+
text: [
|
|
11859
|
+
"Save a user preference to ContextStream memory.",
|
|
11860
|
+
"",
|
|
11861
|
+
...ID_NOTES,
|
|
11862
|
+
"",
|
|
11863
|
+
"If the preference is not explicit in the conversation, ask me what to remember.",
|
|
11864
|
+
"",
|
|
11865
|
+
"Then call `session_capture` with:",
|
|
11866
|
+
'- event_type: "preference"',
|
|
11867
|
+
"- title: (short title)",
|
|
11868
|
+
"- content: (preference text)",
|
|
11869
|
+
'- importance: "medium"'
|
|
11870
|
+
].join("\n")
|
|
11871
|
+
}
|
|
11872
|
+
}
|
|
11873
|
+
]
|
|
11874
|
+
})
|
|
11875
|
+
);
|
|
11876
|
+
server.registerPrompt(
|
|
11877
|
+
"capture-task",
|
|
11878
|
+
{
|
|
11879
|
+
title: `Capture Task (${promptAccessLabel("capture-task")})`,
|
|
11880
|
+
description: "Capture an action item into memory"
|
|
11881
|
+
},
|
|
11882
|
+
async () => ({
|
|
11883
|
+
messages: [
|
|
11884
|
+
{
|
|
11885
|
+
role: "user",
|
|
11886
|
+
content: {
|
|
11887
|
+
type: "text",
|
|
11888
|
+
text: [
|
|
11889
|
+
"Capture an action item into ContextStream memory.",
|
|
11890
|
+
"",
|
|
11891
|
+
...ID_NOTES,
|
|
11892
|
+
"",
|
|
11893
|
+
"If the task is not explicit in the conversation, ask me what to capture.",
|
|
11894
|
+
"",
|
|
11895
|
+
"Then call `session_capture` with:",
|
|
11896
|
+
'- event_type: "task"',
|
|
11897
|
+
"- title: (short title)",
|
|
11898
|
+
"- content: (task details)",
|
|
11899
|
+
'- importance: "medium"'
|
|
11900
|
+
].join("\n")
|
|
11901
|
+
}
|
|
11902
|
+
}
|
|
11903
|
+
]
|
|
11904
|
+
})
|
|
11905
|
+
);
|
|
11906
|
+
server.registerPrompt(
|
|
11907
|
+
"capture-bug",
|
|
11908
|
+
{
|
|
11909
|
+
title: `Capture Bug (${promptAccessLabel("capture-bug")})`,
|
|
11910
|
+
description: "Capture a bug report into workspace memory"
|
|
11911
|
+
},
|
|
11912
|
+
async () => ({
|
|
11913
|
+
messages: [
|
|
11914
|
+
{
|
|
11915
|
+
role: "user",
|
|
11916
|
+
content: {
|
|
11917
|
+
type: "text",
|
|
11918
|
+
text: [
|
|
11919
|
+
"Capture a bug report in ContextStream memory.",
|
|
11920
|
+
"",
|
|
11921
|
+
...ID_NOTES,
|
|
11922
|
+
"",
|
|
11923
|
+
"If details are missing, ask me for:",
|
|
11924
|
+
"- title",
|
|
11925
|
+
"- description",
|
|
11926
|
+
"- steps to reproduce (optional)",
|
|
11927
|
+
"- expected behavior (optional)",
|
|
11928
|
+
"- actual behavior (optional)",
|
|
11929
|
+
"",
|
|
11930
|
+
"Then call `session_capture` with:",
|
|
11931
|
+
'- event_type: "bug"',
|
|
11932
|
+
"- title: (bug title)",
|
|
11933
|
+
"- content: a well-formatted bug report (include all provided details)",
|
|
11934
|
+
"- tags: component/area tags",
|
|
11935
|
+
'- importance: "high"'
|
|
11936
|
+
].join("\n")
|
|
11937
|
+
}
|
|
11938
|
+
}
|
|
11939
|
+
]
|
|
11940
|
+
})
|
|
11941
|
+
);
|
|
11942
|
+
server.registerPrompt(
|
|
11943
|
+
"capture-feature",
|
|
11944
|
+
{
|
|
11945
|
+
title: `Capture Feature (${promptAccessLabel("capture-feature")})`,
|
|
11946
|
+
description: "Capture a feature request into workspace memory"
|
|
11947
|
+
},
|
|
11948
|
+
async () => ({
|
|
11949
|
+
messages: [
|
|
11950
|
+
{
|
|
11951
|
+
role: "user",
|
|
11952
|
+
content: {
|
|
11953
|
+
type: "text",
|
|
11954
|
+
text: [
|
|
11955
|
+
"Capture a feature request in ContextStream memory.",
|
|
11956
|
+
"",
|
|
11957
|
+
...ID_NOTES,
|
|
11958
|
+
"",
|
|
11959
|
+
"If details are missing, ask me for:",
|
|
11960
|
+
"- title",
|
|
11961
|
+
"- description",
|
|
11962
|
+
"- rationale (optional)",
|
|
11963
|
+
"- acceptance criteria (optional)",
|
|
11964
|
+
"",
|
|
11965
|
+
"Then call `session_capture` with:",
|
|
11966
|
+
'- event_type: "feature"',
|
|
11967
|
+
"- title: (feature title)",
|
|
11968
|
+
"- content: a well-formatted feature request",
|
|
11969
|
+
"- tags: component/area tags",
|
|
11970
|
+
'- importance: "medium"'
|
|
11971
|
+
].join("\n")
|
|
11972
|
+
}
|
|
11973
|
+
}
|
|
11974
|
+
]
|
|
11975
|
+
})
|
|
11976
|
+
);
|
|
11977
|
+
server.registerPrompt(
|
|
11978
|
+
"generate-plan",
|
|
11979
|
+
{
|
|
11980
|
+
title: `Generate Plan (${promptAccessLabel("generate-plan")})`,
|
|
11981
|
+
description: "Generate a development plan from a description"
|
|
11982
|
+
},
|
|
11983
|
+
async () => ({
|
|
11984
|
+
messages: [
|
|
11985
|
+
{
|
|
11986
|
+
role: "user",
|
|
11987
|
+
content: {
|
|
11988
|
+
type: "text",
|
|
11989
|
+
text: [
|
|
11990
|
+
"Generate a development plan for what I am trying to build/fix.",
|
|
11991
|
+
"",
|
|
11992
|
+
`Access: ${promptAccessLabel("generate-plan")}${promptAccessLabel("generate-plan") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
|
|
11993
|
+
"",
|
|
11994
|
+
...ID_NOTES,
|
|
11995
|
+
"",
|
|
11996
|
+
"Use the most recent user request as the plan description. If unclear, ask me for a one-paragraph description.",
|
|
11997
|
+
"",
|
|
11998
|
+
"Then call `ai_plan` and present the plan as an ordered list with milestones and risks."
|
|
11999
|
+
].join("\n")
|
|
12000
|
+
}
|
|
12001
|
+
}
|
|
12002
|
+
]
|
|
12003
|
+
})
|
|
12004
|
+
);
|
|
12005
|
+
server.registerPrompt(
|
|
12006
|
+
"generate-tasks",
|
|
12007
|
+
{
|
|
12008
|
+
title: `Generate Tasks (${promptAccessLabel("generate-tasks")})`,
|
|
12009
|
+
description: "Generate actionable tasks from a plan or description"
|
|
12010
|
+
},
|
|
12011
|
+
async () => ({
|
|
12012
|
+
messages: [
|
|
12013
|
+
{
|
|
12014
|
+
role: "user",
|
|
12015
|
+
content: {
|
|
12016
|
+
type: "text",
|
|
12017
|
+
text: [
|
|
12018
|
+
"Generate actionable tasks for the work we are discussing.",
|
|
12019
|
+
"",
|
|
12020
|
+
`Access: ${promptAccessLabel("generate-tasks")}${promptAccessLabel("generate-tasks") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
|
|
12021
|
+
"",
|
|
12022
|
+
...ID_NOTES,
|
|
12023
|
+
"",
|
|
12024
|
+
"If a plan_id exists in the conversation, use it. Otherwise use the latest user request as the description.",
|
|
12025
|
+
"If granularity is not specified, default to medium.",
|
|
12026
|
+
"",
|
|
12027
|
+
"Call `ai_tasks` and return a checklist of tasks with acceptance criteria for each."
|
|
12028
|
+
].join("\n")
|
|
12029
|
+
}
|
|
12030
|
+
}
|
|
12031
|
+
]
|
|
12032
|
+
})
|
|
12033
|
+
);
|
|
12034
|
+
server.registerPrompt(
|
|
12035
|
+
"token-budget-context",
|
|
12036
|
+
{
|
|
12037
|
+
title: `Token-Budget Context (${promptAccessLabel("token-budget-context")})`,
|
|
12038
|
+
description: "Get the most relevant context that fits within a token budget"
|
|
12039
|
+
},
|
|
12040
|
+
async () => ({
|
|
12041
|
+
messages: [
|
|
12042
|
+
{
|
|
12043
|
+
role: "user",
|
|
12044
|
+
content: {
|
|
12045
|
+
type: "text",
|
|
12046
|
+
text: [
|
|
12047
|
+
"Build the most relevant context that fits within a token budget.",
|
|
12048
|
+
"",
|
|
12049
|
+
`Access: ${promptAccessLabel("token-budget-context")}${promptAccessLabel("token-budget-context") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
|
|
12050
|
+
"",
|
|
12051
|
+
...ID_NOTES,
|
|
12052
|
+
"",
|
|
12053
|
+
"First:",
|
|
12054
|
+
"- If a query is clear from the conversation, use it; otherwise ask me for a query.",
|
|
12055
|
+
"- If max_tokens is not specified, ask me for a token budget (e.g., 500/1000/2000).",
|
|
12056
|
+
"",
|
|
12057
|
+
"Then call `ai_context_budget` and return the packed context plus a short note about what was included/excluded."
|
|
12058
|
+
].join("\n")
|
|
12059
|
+
}
|
|
12060
|
+
}
|
|
12061
|
+
]
|
|
12062
|
+
})
|
|
12063
|
+
);
|
|
12064
|
+
server.registerPrompt(
|
|
12065
|
+
"find-todos",
|
|
12066
|
+
{
|
|
12067
|
+
title: `Find TODOs (${promptAccessLabel("find-todos")})`,
|
|
12068
|
+
description: "Scan the codebase for TODO/FIXME/HACK notes and summarize"
|
|
12069
|
+
},
|
|
12070
|
+
async () => ({
|
|
12071
|
+
messages: [
|
|
12072
|
+
{
|
|
12073
|
+
role: "user",
|
|
12074
|
+
content: {
|
|
12075
|
+
type: "text",
|
|
12076
|
+
text: [
|
|
12077
|
+
"Scan the codebase for TODO/FIXME/HACK notes and summarize them.",
|
|
12078
|
+
"",
|
|
12079
|
+
...ID_NOTES,
|
|
12080
|
+
"",
|
|
12081
|
+
"Use `search_pattern` with query `TODO|FIXME|HACK` (or a pattern inferred from the conversation).",
|
|
12082
|
+
"Group results by file path, summarize themes, and propose a small prioritized cleanup list."
|
|
12083
|
+
].join("\n")
|
|
12084
|
+
}
|
|
12085
|
+
}
|
|
12086
|
+
]
|
|
12087
|
+
})
|
|
12088
|
+
);
|
|
12089
|
+
server.registerPrompt(
|
|
12090
|
+
"generate-editor-rules",
|
|
12091
|
+
{
|
|
12092
|
+
title: `Generate Editor Rules (${promptAccessLabel("generate-editor-rules")})`,
|
|
12093
|
+
description: "Generate ContextStream AI rule files for your editor"
|
|
12094
|
+
},
|
|
12095
|
+
async () => ({
|
|
12096
|
+
messages: [
|
|
12097
|
+
{
|
|
12098
|
+
role: "user",
|
|
12099
|
+
content: {
|
|
12100
|
+
type: "text",
|
|
12101
|
+
text: [
|
|
12102
|
+
"Generate ContextStream AI rule files for my editor.",
|
|
12103
|
+
"",
|
|
12104
|
+
...ID_NOTES,
|
|
12105
|
+
"",
|
|
12106
|
+
"First:",
|
|
12107
|
+
"- If you can infer the project folder path from the environment/IDE roots, use it.",
|
|
12108
|
+
"- Otherwise ask me for an absolute folder path.",
|
|
12109
|
+
"- Ask which editor(s) (windsurf,cursor,cline,kilo,roo,claude,aider) or default to all.",
|
|
12110
|
+
"",
|
|
12111
|
+
"Then call `generate_editor_rules` and confirm which files were created/updated."
|
|
12112
|
+
].join("\n")
|
|
12113
|
+
}
|
|
12114
|
+
}
|
|
12115
|
+
]
|
|
12116
|
+
})
|
|
12117
|
+
);
|
|
12118
|
+
server.registerPrompt(
|
|
12119
|
+
"index-local-repo",
|
|
12120
|
+
{
|
|
12121
|
+
title: `Index Local Repo (${promptAccessLabel("index-local-repo")})`,
|
|
12122
|
+
description: "Ingest local files into ContextStream for indexing/search"
|
|
12123
|
+
},
|
|
12124
|
+
async () => ({
|
|
12125
|
+
messages: [
|
|
12126
|
+
{
|
|
12127
|
+
role: "user",
|
|
12128
|
+
content: {
|
|
12129
|
+
type: "text",
|
|
12130
|
+
text: [
|
|
12131
|
+
"Ingest local files into ContextStream for indexing/search.",
|
|
12132
|
+
"",
|
|
12133
|
+
...ID_NOTES,
|
|
12134
|
+
"",
|
|
12135
|
+
"First:",
|
|
12136
|
+
"- Ask me for the local directory path to ingest if it is not already specified.",
|
|
12137
|
+
"",
|
|
12138
|
+
"Then:",
|
|
12139
|
+
"- Call `projects_ingest_local` with the path (use session defaults for project, or the `project_id` returned by `session_init`).",
|
|
12140
|
+
"- Explain how to monitor progress via `projects_index_status`."
|
|
12141
|
+
].join("\n")
|
|
12142
|
+
}
|
|
12143
|
+
}
|
|
12144
|
+
]
|
|
12145
|
+
})
|
|
12146
|
+
);
|
|
12147
|
+
}
|
|
12148
|
+
|
|
11172
12149
|
// src/session-manager.ts
|
|
11173
12150
|
var SessionManager = class {
|
|
11174
12151
|
constructor(server, client) {
|
|
@@ -11467,6 +12444,12 @@ var PORT = Number.parseInt(process.env.MCP_HTTP_PORT || "8787", 10);
|
|
|
11467
12444
|
var MCP_PATH = process.env.MCP_HTTP_PATH || "/mcp";
|
|
11468
12445
|
var REQUIRE_AUTH = (process.env.MCP_HTTP_REQUIRE_AUTH || "true").toLowerCase() !== "false";
|
|
11469
12446
|
var ENABLE_JSON_RESPONSE = (process.env.MCP_HTTP_JSON_RESPONSE || "false").toLowerCase() === "true";
|
|
12447
|
+
var ENABLE_PROMPTS = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
|
|
12448
|
+
var WELL_KNOWN_CONFIG_PATH = "/.well-known/mcp-config";
|
|
12449
|
+
var WELL_KNOWN_CARD_PATHS = /* @__PURE__ */ new Set([
|
|
12450
|
+
"/.well-known/mcp.json",
|
|
12451
|
+
"/.well-known/mcp-server.json"
|
|
12452
|
+
]);
|
|
11470
12453
|
var sessions = /* @__PURE__ */ new Map();
|
|
11471
12454
|
function normalizeHeaderValue2(value) {
|
|
11472
12455
|
if (!value) return void 0;
|
|
@@ -11514,6 +12497,105 @@ function attachAuthInfo(req, token, tokenType) {
|
|
|
11514
12497
|
extra: { tokenType }
|
|
11515
12498
|
};
|
|
11516
12499
|
}
|
|
12500
|
+
function getBaseUrl(req) {
|
|
12501
|
+
const host = req.headers.host || "localhost";
|
|
12502
|
+
const forwardedProto = normalizeHeaderValue2(req.headers["x-forwarded-proto"]);
|
|
12503
|
+
const proto = forwardedProto || "http";
|
|
12504
|
+
return `${proto}://${host}`;
|
|
12505
|
+
}
|
|
12506
|
+
function buildMcpConfigSchema(baseUrl) {
|
|
12507
|
+
return {
|
|
12508
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
12509
|
+
$id: `${baseUrl}${WELL_KNOWN_CONFIG_PATH}`,
|
|
12510
|
+
title: "ContextStream MCP Session Configuration",
|
|
12511
|
+
description: "Configuration for connecting to the ContextStream MCP HTTP gateway.",
|
|
12512
|
+
"x-query-style": "dot+bracket",
|
|
12513
|
+
type: "object",
|
|
12514
|
+
properties: {
|
|
12515
|
+
apiKey: {
|
|
12516
|
+
type: "string",
|
|
12517
|
+
title: "API Key or JWT",
|
|
12518
|
+
description: "ContextStream API key or JWT used for authentication."
|
|
12519
|
+
},
|
|
12520
|
+
workspaceId: {
|
|
12521
|
+
type: "string",
|
|
12522
|
+
title: "Workspace ID",
|
|
12523
|
+
description: "Optional workspace ID to scope requests.",
|
|
12524
|
+
format: "uuid"
|
|
12525
|
+
},
|
|
12526
|
+
projectId: {
|
|
12527
|
+
type: "string",
|
|
12528
|
+
title: "Project ID",
|
|
12529
|
+
description: "Optional project ID to scope requests.",
|
|
12530
|
+
format: "uuid"
|
|
12531
|
+
}
|
|
12532
|
+
},
|
|
12533
|
+
required: ["apiKey"],
|
|
12534
|
+
additionalProperties: false
|
|
12535
|
+
};
|
|
12536
|
+
}
|
|
12537
|
+
function buildServerCard(baseUrl) {
|
|
12538
|
+
const mcpUrl = `${baseUrl}${MCP_PATH}`;
|
|
12539
|
+
return {
|
|
12540
|
+
$schema: "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
12541
|
+
name: "io.github.contextstreamio/mcp-server",
|
|
12542
|
+
title: "ContextStream MCP Server",
|
|
12543
|
+
description: "ContextStream MCP server for code context, memory, search, and AI tools.",
|
|
12544
|
+
version: VERSION,
|
|
12545
|
+
websiteUrl: "https://contextstream.io/docs/mcp",
|
|
12546
|
+
repository: {
|
|
12547
|
+
url: "https://github.com/contextstream/mcp-server",
|
|
12548
|
+
source: "github"
|
|
12549
|
+
},
|
|
12550
|
+
icons: [
|
|
12551
|
+
{
|
|
12552
|
+
src: "https://contextstream.io/favicon.svg",
|
|
12553
|
+
mimeType: "image/svg+xml",
|
|
12554
|
+
sizes: ["any"]
|
|
12555
|
+
}
|
|
12556
|
+
],
|
|
12557
|
+
remotes: [
|
|
12558
|
+
{
|
|
12559
|
+
type: "streamable-http",
|
|
12560
|
+
url: mcpUrl,
|
|
12561
|
+
headers: [
|
|
12562
|
+
{
|
|
12563
|
+
name: "Authorization",
|
|
12564
|
+
value: "Bearer {apiKey}",
|
|
12565
|
+
variables: {
|
|
12566
|
+
apiKey: {
|
|
12567
|
+
description: "ContextStream API key or JWT.",
|
|
12568
|
+
isRequired: true,
|
|
12569
|
+
isSecret: true,
|
|
12570
|
+
placeholder: "cbiq_..."
|
|
12571
|
+
}
|
|
12572
|
+
}
|
|
12573
|
+
},
|
|
12574
|
+
{
|
|
12575
|
+
name: "X-ContextStream-Workspace-Id",
|
|
12576
|
+
value: "{workspaceId}",
|
|
12577
|
+
variables: {
|
|
12578
|
+
workspaceId: {
|
|
12579
|
+
description: "Optional workspace ID.",
|
|
12580
|
+
isRequired: false
|
|
12581
|
+
}
|
|
12582
|
+
}
|
|
12583
|
+
},
|
|
12584
|
+
{
|
|
12585
|
+
name: "X-ContextStream-Project-Id",
|
|
12586
|
+
value: "{projectId}",
|
|
12587
|
+
variables: {
|
|
12588
|
+
projectId: {
|
|
12589
|
+
description: "Optional project ID.",
|
|
12590
|
+
isRequired: false
|
|
12591
|
+
}
|
|
12592
|
+
}
|
|
12593
|
+
}
|
|
12594
|
+
]
|
|
12595
|
+
}
|
|
12596
|
+
]
|
|
12597
|
+
};
|
|
12598
|
+
}
|
|
11517
12599
|
async function createSession() {
|
|
11518
12600
|
const config = loadConfig();
|
|
11519
12601
|
const client = new ContextStreamClient(config);
|
|
@@ -11524,6 +12606,9 @@ async function createSession() {
|
|
|
11524
12606
|
const sessionManager = new SessionManager(server, client);
|
|
11525
12607
|
registerTools(server, client, sessionManager);
|
|
11526
12608
|
registerResources(server, client, config.apiUrl);
|
|
12609
|
+
if (ENABLE_PROMPTS) {
|
|
12610
|
+
registerPrompts(server);
|
|
12611
|
+
}
|
|
11527
12612
|
const transport = new StreamableHTTPServerTransport({
|
|
11528
12613
|
sessionIdGenerator: () => randomUUID2(),
|
|
11529
12614
|
enableJsonResponse: ENABLE_JSON_RESPONSE,
|
|
@@ -11595,6 +12680,14 @@ async function runHttpGateway() {
|
|
|
11595
12680
|
writeJson(res, 200, { status: "ok", version: VERSION });
|
|
11596
12681
|
return;
|
|
11597
12682
|
}
|
|
12683
|
+
if (url.pathname === WELL_KNOWN_CONFIG_PATH) {
|
|
12684
|
+
writeJson(res, 200, buildMcpConfigSchema(getBaseUrl(req)));
|
|
12685
|
+
return;
|
|
12686
|
+
}
|
|
12687
|
+
if (WELL_KNOWN_CARD_PATHS.has(url.pathname)) {
|
|
12688
|
+
writeJson(res, 200, buildServerCard(getBaseUrl(req)));
|
|
12689
|
+
return;
|
|
12690
|
+
}
|
|
11598
12691
|
if (url.pathname !== MCP_PATH) {
|
|
11599
12692
|
writeJson(res, 404, { error: "Not found" });
|
|
11600
12693
|
return;
|
|
@@ -12650,6 +13743,7 @@ Applying to ${projects.length} project(s)...`);
|
|
|
12650
13743
|
}
|
|
12651
13744
|
|
|
12652
13745
|
// src/index.ts
|
|
13746
|
+
var ENABLE_PROMPTS2 = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
|
|
12653
13747
|
function showFirstRunMessage() {
|
|
12654
13748
|
const configDir = join8(homedir4(), ".contextstream");
|
|
12655
13749
|
const starShownFile = join8(configDir, ".star-shown");
|
|
@@ -12699,6 +13793,7 @@ Environment variables:
|
|
|
12699
13793
|
CONTEXTSTREAM_TOOL_ALLOWLIST Optional comma-separated tool names to expose (overrides toolset)
|
|
12700
13794
|
CONTEXTSTREAM_PRO_TOOLS Optional comma-separated PRO tool names (default: AI tools)
|
|
12701
13795
|
CONTEXTSTREAM_UPGRADE_URL Optional upgrade URL shown for PRO tools on Free plan
|
|
13796
|
+
CONTEXTSTREAM_ENABLE_PROMPTS Enable MCP prompts list (default: true)
|
|
12702
13797
|
MCP_HTTP_HOST HTTP gateway host (default: 0.0.0.0)
|
|
12703
13798
|
MCP_HTTP_PORT HTTP gateway port (default: 8787)
|
|
12704
13799
|
MCP_HTTP_PATH HTTP gateway path (default: /mcp)
|
|
@@ -12748,6 +13843,9 @@ async function main() {
|
|
|
12748
13843
|
const sessionManager = new SessionManager(server, client);
|
|
12749
13844
|
registerTools(server, client, sessionManager);
|
|
12750
13845
|
registerResources(server, client, config.apiUrl);
|
|
13846
|
+
if (ENABLE_PROMPTS2) {
|
|
13847
|
+
registerPrompts(server);
|
|
13848
|
+
}
|
|
12751
13849
|
console.error(`ContextStream MCP server v${VERSION} starting...`);
|
|
12752
13850
|
console.error(`API URL: ${config.apiUrl}`);
|
|
12753
13851
|
console.error(`Auth: ${config.apiKey ? "API Key" : config.jwt ? "JWT" : "None"}`);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contextstream/mcp-server",
|
|
3
3
|
"mcpName": "io.github.contextstreamio/mcp-server",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.64",
|
|
5
5
|
"description": "MCP server exposing ContextStream public API - code context, memory, search, and AI tools for developers",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|