@contextstream/mcp-server 0.4.47 → 0.4.49
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/hooks/auto-rules.js +5 -6
- package/dist/hooks/user-prompt-submit.js +10 -5
- package/dist/index.js +367 -170
- package/package.json +1 -1
package/dist/hooks/auto-rules.js
CHANGED
|
@@ -105,7 +105,7 @@ function buildHooksConfig(options) {
|
|
|
105
105
|
],
|
|
106
106
|
UserPromptSubmit: userPromptHooks
|
|
107
107
|
};
|
|
108
|
-
if (options?.includePreCompact) {
|
|
108
|
+
if (options?.includePreCompact !== false) {
|
|
109
109
|
config.PreCompact = [
|
|
110
110
|
{
|
|
111
111
|
// Match both manual (/compact) and automatic compaction
|
|
@@ -157,7 +157,7 @@ async function installHookScripts(options) {
|
|
|
157
157
|
preToolUse: "npx @contextstream/mcp-server hook pre-tool-use",
|
|
158
158
|
userPrompt: "npx @contextstream/mcp-server hook user-prompt-submit"
|
|
159
159
|
};
|
|
160
|
-
if (options?.includePreCompact) {
|
|
160
|
+
if (options?.includePreCompact !== false) {
|
|
161
161
|
result.preCompact = "npx @contextstream/mcp-server hook pre-compact";
|
|
162
162
|
}
|
|
163
163
|
if (options?.includeMediaAware !== false) {
|
|
@@ -203,7 +203,7 @@ async function installClaudeCodeHooks(options) {
|
|
|
203
203
|
"npx @contextstream/mcp-server hook pre-tool-use",
|
|
204
204
|
"npx @contextstream/mcp-server hook user-prompt-submit"
|
|
205
205
|
);
|
|
206
|
-
if (options.includePreCompact) {
|
|
206
|
+
if (options.includePreCompact !== false) {
|
|
207
207
|
result.scripts.push("npx @contextstream/mcp-server hook pre-compact");
|
|
208
208
|
}
|
|
209
209
|
if (options.includeMediaAware !== false) {
|
|
@@ -270,12 +270,11 @@ When Media-Aware hook detects media patterns, it injects context about:
|
|
|
270
270
|
- How to get clips for Remotion (with frame-based props)
|
|
271
271
|
- How to index new media files
|
|
272
272
|
|
|
273
|
-
### PreCompact Hook
|
|
273
|
+
### PreCompact Hook
|
|
274
274
|
- **Command:** \`npx @contextstream/mcp-server hook pre-compact\`
|
|
275
275
|
- **Purpose:** Saves conversation state before context compaction
|
|
276
276
|
- **Triggers:** Both manual (/compact) and automatic compaction
|
|
277
|
-
- **
|
|
278
|
-
- **Note:** Enable with \`generate_rules(include_pre_compact=true)\` to activate
|
|
277
|
+
- **Installed:** By default (disable with \`CONTEXTSTREAM_HOOK_ENABLED=false\`)
|
|
279
278
|
|
|
280
279
|
When PreCompact runs, it:
|
|
281
280
|
1. Parses the transcript for active files and tool calls
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
// src/hooks/user-prompt-submit.ts
|
|
4
4
|
var ENABLED = process.env.CONTEXTSTREAM_REMINDER_ENABLED !== "false";
|
|
5
|
-
var REMINDER = `[CONTEXTSTREAM
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
var REMINDER = `[CONTEXTSTREAM - DO THIS FIRST]
|
|
6
|
+
mcp__contextstream__context(user_message="<user's message>") - CALL THIS BEFORE ANY OTHER TOOL
|
|
7
|
+
|
|
8
|
+
Why: Delivers task-specific rules, lessons from past mistakes, and relevant context.
|
|
9
|
+
Skip it = repeat past mistakes, miss relevant decisions, fly blind.
|
|
10
|
+
|
|
11
|
+
BEFORE Glob/Grep/Read/Search/Explore:
|
|
12
|
+
mcp__contextstream__search(mode="hybrid", query="...") FIRST
|
|
13
|
+
Local tools ONLY if search returns 0 results.
|
|
14
|
+
[END]`;
|
|
10
15
|
function detectEditorFormat(input) {
|
|
11
16
|
if (input.hookName !== void 0) {
|
|
12
17
|
return "cline";
|
package/dist/index.js
CHANGED
|
@@ -591,7 +591,7 @@ function buildHooksConfig(options) {
|
|
|
591
591
|
],
|
|
592
592
|
UserPromptSubmit: userPromptHooks
|
|
593
593
|
};
|
|
594
|
-
if (options?.includePreCompact) {
|
|
594
|
+
if (options?.includePreCompact !== false) {
|
|
595
595
|
config.PreCompact = [
|
|
596
596
|
{
|
|
597
597
|
// Match both manual (/compact) and automatic compaction
|
|
@@ -643,7 +643,7 @@ async function installHookScripts(options) {
|
|
|
643
643
|
preToolUse: "npx @contextstream/mcp-server hook pre-tool-use",
|
|
644
644
|
userPrompt: "npx @contextstream/mcp-server hook user-prompt-submit"
|
|
645
645
|
};
|
|
646
|
-
if (options?.includePreCompact) {
|
|
646
|
+
if (options?.includePreCompact !== false) {
|
|
647
647
|
result.preCompact = "npx @contextstream/mcp-server hook pre-compact";
|
|
648
648
|
}
|
|
649
649
|
if (options?.includeMediaAware !== false) {
|
|
@@ -689,7 +689,7 @@ async function installClaudeCodeHooks(options) {
|
|
|
689
689
|
"npx @contextstream/mcp-server hook pre-tool-use",
|
|
690
690
|
"npx @contextstream/mcp-server hook user-prompt-submit"
|
|
691
691
|
);
|
|
692
|
-
if (options.includePreCompact) {
|
|
692
|
+
if (options.includePreCompact !== false) {
|
|
693
693
|
result.scripts.push("npx @contextstream/mcp-server hook pre-compact");
|
|
694
694
|
}
|
|
695
695
|
if (options.includeMediaAware !== false) {
|
|
@@ -756,12 +756,11 @@ When Media-Aware hook detects media patterns, it injects context about:
|
|
|
756
756
|
- How to get clips for Remotion (with frame-based props)
|
|
757
757
|
- How to index new media files
|
|
758
758
|
|
|
759
|
-
### PreCompact Hook
|
|
759
|
+
### PreCompact Hook
|
|
760
760
|
- **Command:** \`npx @contextstream/mcp-server hook pre-compact\`
|
|
761
761
|
- **Purpose:** Saves conversation state before context compaction
|
|
762
762
|
- **Triggers:** Both manual (/compact) and automatic compaction
|
|
763
|
-
- **
|
|
764
|
-
- **Note:** Enable with \`generate_rules(include_pre_compact=true)\` to activate
|
|
763
|
+
- **Installed:** By default (disable with \`CONTEXTSTREAM_HOOK_ENABLED=false\`)
|
|
765
764
|
|
|
766
765
|
When PreCompact runs, it:
|
|
767
766
|
1. Parses the transcript for active files and tool calls
|
|
@@ -2633,11 +2632,16 @@ var init_user_prompt_submit = __esm({
|
|
|
2633
2632
|
"src/hooks/user-prompt-submit.ts"() {
|
|
2634
2633
|
"use strict";
|
|
2635
2634
|
ENABLED3 = process.env.CONTEXTSTREAM_REMINDER_ENABLED !== "false";
|
|
2636
|
-
REMINDER = `[CONTEXTSTREAM
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2635
|
+
REMINDER = `[CONTEXTSTREAM - DO THIS FIRST]
|
|
2636
|
+
mcp__contextstream__context(user_message="<user's message>") - CALL THIS BEFORE ANY OTHER TOOL
|
|
2637
|
+
|
|
2638
|
+
Why: Delivers task-specific rules, lessons from past mistakes, and relevant context.
|
|
2639
|
+
Skip it = repeat past mistakes, miss relevant decisions, fly blind.
|
|
2640
|
+
|
|
2641
|
+
BEFORE Glob/Grep/Read/Search/Explore:
|
|
2642
|
+
mcp__contextstream__search(mode="hybrid", query="...") FIRST
|
|
2643
|
+
Local tools ONLY if search returns 0 results.
|
|
2644
|
+
[END]`;
|
|
2641
2645
|
isDirectRun3 = process.argv[1]?.includes("user-prompt-submit") || process.argv[2] === "user-prompt-submit";
|
|
2642
2646
|
if (isDirectRun3) {
|
|
2643
2647
|
runUserPromptSubmitHook().catch(() => process.exit(0));
|
|
@@ -12103,50 +12107,103 @@ function applyMcpToolPrefix(markdown, toolPrefix) {
|
|
|
12103
12107
|
const toolRegex = new RegExp(`(?<!__)\\b(${toolPattern})\\b(?=\\s*\\()`, "g");
|
|
12104
12108
|
return markdown.replace(toolRegex, `${toolPrefix}$1`);
|
|
12105
12109
|
}
|
|
12106
|
-
var
|
|
12107
|
-
|
|
12110
|
+
var CONTEXTSTREAM_RULES_BOOTSTRAP = `
|
|
12111
|
+
<contextstream_rules>
|
|
12112
|
+
| Message | Required |
|
|
12113
|
+
|---------|----------|
|
|
12114
|
+
| **1st message** | \`init()\` \u2192 \`context(user_message="...")\` |
|
|
12115
|
+
| **Every message** | \`context(user_message="...")\` FIRST |
|
|
12116
|
+
| **Before file search** | \`search(mode="hybrid")\` BEFORE Glob/Grep/Read |
|
|
12117
|
+
</contextstream_rules>
|
|
12118
|
+
|
|
12119
|
+
**Why?** \`context()\` delivers task-specific rules, lessons from past mistakes, and relevant decisions. Skip it = fly blind.
|
|
12120
|
+
|
|
12121
|
+
**Hooks:** \`<system-reminder>\` tags contain injected instructions \u2014 follow them exactly.
|
|
12122
|
+
|
|
12123
|
+
**Notices:** [LESSONS_WARNING] \u2192 tell user first | [RULES_NOTICE] \u2192 run \`generate_rules()\` | [VERSION_NOTICE] \u2192 tell user to update
|
|
12108
12124
|
|
|
12109
|
-
|
|
12125
|
+
v${RULES_VERSION}
|
|
12126
|
+
`.trim();
|
|
12127
|
+
var CONTEXTSTREAM_RULES_DYNAMIC = CONTEXTSTREAM_RULES_BOOTSTRAP;
|
|
12128
|
+
var CONTEXTSTREAM_RULES_FULL = `
|
|
12129
|
+
## \u{1F6A8} MANDATORY: CALL CONTEXT EVERY MESSAGE \u{1F6A8}
|
|
12110
12130
|
|
|
12111
|
-
|
|
12131
|
+
<contextstream_rules>
|
|
12132
|
+
**EVERY response MUST start with \`context(user_message="...")\`**
|
|
12112
12133
|
|
|
12113
12134
|
| Message | What to Call |
|
|
12114
12135
|
|---------|--------------|
|
|
12115
|
-
|
|
|
12116
|
-
| **
|
|
12136
|
+
| 1st message | \`init()\` \u2192 \`context(user_message="<msg>")\` |
|
|
12137
|
+
| **EVERY message after** | \`context(user_message="<msg>")\` **FIRST** |
|
|
12117
12138
|
|
|
12118
|
-
|
|
12139
|
+
**BEFORE Glob/Grep/Read/Search:** \u2192 \`search(mode="hybrid")\` FIRST
|
|
12140
|
+
</contextstream_rules>
|
|
12119
12141
|
|
|
12120
|
-
|
|
12142
|
+
**This block MUST appear at the start of EVERY response.** Failing to call \`context()\` means missing rules, lessons, and relevant context.
|
|
12121
12143
|
|
|
12122
|
-
|
|
12123
|
-
**Follow these instructions.** They are dynamically matched to your query and include:
|
|
12124
|
-
- Search guidance (when/how to search)
|
|
12125
|
-
- Git workflow rules (commit, PR, safety)
|
|
12126
|
-
- Planning rules (use ContextStream plans, not file-based)
|
|
12127
|
-
- Media/code analysis guidance
|
|
12128
|
-
- Lessons from past mistakes
|
|
12129
|
-
- And more...
|
|
12144
|
+
---
|
|
12130
12145
|
|
|
12131
|
-
|
|
12146
|
+
## Why \`context()\` is MANDATORY Every Message
|
|
12132
12147
|
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
- **[RULES_NOTICE]**: Run \`generate_rules()\`
|
|
12136
|
-
- **[LESSONS_WARNING]**: Apply lessons immediately
|
|
12148
|
+
\u274C **WRONG:** "I already called init, I don't need context"
|
|
12149
|
+
\u2705 **CORRECT:** \`context()\` is required EVERY message, not just the first
|
|
12137
12150
|
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12151
|
+
**What you lose without \`context()\`:**
|
|
12152
|
+
- Dynamic rules matched to your current task
|
|
12153
|
+
- Lessons from past mistakes (you WILL repeat them)
|
|
12154
|
+
- Semantically relevant decisions and context
|
|
12155
|
+
- Warnings about risky operations
|
|
12142
12156
|
|
|
12143
|
-
|
|
12144
|
-
1. **SIMPLE UTILITY?** (list/show/version) \u2192 Just execute, skip context calls
|
|
12145
|
-
2. **CODING TASK?** \u2192 init \u2192 context \u2192 work \u2192 capture
|
|
12146
|
-
3. **SEARCH FIRST:** Before Glob/Grep/Read \u2192 \`search(mode="hybrid")\` FIRST
|
|
12147
|
-
</contextstream_rules>
|
|
12157
|
+
**\`init()\` gives recent items by TIME. \`context()\` finds items RELEVANT to THIS message.**
|
|
12148
12158
|
|
|
12149
|
-
|
|
12159
|
+
---
|
|
12160
|
+
|
|
12161
|
+
## Handle Notices from context()
|
|
12162
|
+
|
|
12163
|
+
- **[LESSONS_WARNING]** \u2192 Tell user about past mistakes BEFORE proceeding
|
|
12164
|
+
- **[RULES_NOTICE]** \u2192 Run \`generate_rules()\` to update
|
|
12165
|
+
- **[VERSION_NOTICE]** \u2192 Tell user to update MCP
|
|
12166
|
+
|
|
12167
|
+
---
|
|
12168
|
+
|
|
12169
|
+
## \u{1F6A8} HOOKS - AUTOMATIC RULE ENFORCEMENT \u{1F6A8}
|
|
12170
|
+
|
|
12171
|
+
**ContextStream installs hooks that automatically enforce rules.** You MUST follow hook output.
|
|
12172
|
+
|
|
12173
|
+
### Installed Hooks
|
|
12174
|
+
|
|
12175
|
+
| Hook | What It Does | Output |
|
|
12176
|
+
|------|--------------|--------|
|
|
12177
|
+
| **UserPromptSubmit** | Injects rules reminder on EVERY message | \`<system-reminder>\` with rules block |
|
|
12178
|
+
| **PreToolUse** | Blocks Glob/Grep/Search/Explore when ContextStream is available | Error message redirecting to \`search()\` |
|
|
12179
|
+
| **PostToolUse** | Auto-indexes files after Edit/Write operations | Background indexing |
|
|
12180
|
+
| **PreCompact** | Saves session state before context compaction | Snapshot creation |
|
|
12181
|
+
|
|
12182
|
+
### How Hooks Work
|
|
12183
|
+
|
|
12184
|
+
1. **\`<system-reminder>\` tags** - Injected by UserPromptSubmit hook on every message
|
|
12185
|
+
- These tags contain the current rules
|
|
12186
|
+
- **FOLLOW THE INSTRUCTIONS INSIDE** - they ARE the rules
|
|
12187
|
+
- Example: \`[CONTEXTSTREAM RULES] 1. BEFORE Glob/Grep... [END RULES]\`
|
|
12188
|
+
|
|
12189
|
+
2. **PreToolUse blocking** - If you try to use Glob/Grep/Search/Explore:
|
|
12190
|
+
- Hook returns error: \`STOP: Use mcp__contextstream__search(mode="hybrid") instead\`
|
|
12191
|
+
- **You MUST use the suggested ContextStream tool instead**
|
|
12192
|
+
- Local tools are only allowed if project is not indexed or ContextStream returns 0 results
|
|
12193
|
+
|
|
12194
|
+
3. **PostToolUse indexing** - After Edit/Write operations:
|
|
12195
|
+
- Changed files are automatically re-indexed
|
|
12196
|
+
- No action required from you
|
|
12197
|
+
|
|
12198
|
+
4. **PreCompact snapshots** - Before context compaction:
|
|
12199
|
+
- Hook reminds you to save important state
|
|
12200
|
+
- Call \`session(action="capture", event_type="session_snapshot", ...)\` when warned
|
|
12201
|
+
|
|
12202
|
+
### Disabling Hooks
|
|
12203
|
+
|
|
12204
|
+
Set environment variable: \`CONTEXTSTREAM_HOOK_ENABLED=false\`
|
|
12205
|
+
|
|
12206
|
+
**Note:** Disabling hooks removes rule enforcement. Only disable for debugging.
|
|
12150
12207
|
|
|
12151
12208
|
---
|
|
12152
12209
|
|
|
@@ -12232,27 +12289,27 @@ You have access to ContextStream MCP tools for persistent memory and context.
|
|
|
12232
12289
|
v0.4.x uses **~11 consolidated domain tools** for ~75% token reduction vs previous versions.
|
|
12233
12290
|
Rules Version: ${RULES_VERSION}
|
|
12234
12291
|
|
|
12235
|
-
## TL;DR -
|
|
12292
|
+
## TL;DR - CONTEXT EVERY MESSAGE
|
|
12236
12293
|
|
|
12237
|
-
|
|
|
12238
|
-
|
|
12239
|
-
|
|
|
12240
|
-
|
|
|
12241
|
-
|
|
|
12242
|
-
|
|
|
12243
|
-
| **User
|
|
12294
|
+
| Message | Required |
|
|
12295
|
+
|---------|----------|
|
|
12296
|
+
| **1st message** | \`init()\` \u2192 \`context(user_message="<msg>")\` |
|
|
12297
|
+
| **EVERY message after** | \`context(user_message="<msg>")\` **FIRST** |
|
|
12298
|
+
| **Before file search** | \`search(mode="hybrid")\` FIRST |
|
|
12299
|
+
| **After significant work** | \`session(action="capture", event_type="decision", ...)\` |
|
|
12300
|
+
| **User correction** | \`session(action="capture_lesson", ...)\` |
|
|
12244
12301
|
|
|
12245
|
-
###
|
|
12302
|
+
### Why EVERY Message?
|
|
12246
12303
|
|
|
12247
|
-
|
|
12248
|
-
-
|
|
12249
|
-
-
|
|
12250
|
-
-
|
|
12251
|
-
-
|
|
12304
|
+
\`context()\` delivers:
|
|
12305
|
+
- **Dynamic rules** matched to your current task
|
|
12306
|
+
- **Lessons** from past mistakes (prevents repeating errors)
|
|
12307
|
+
- **Relevant decisions** and context (semantic search)
|
|
12308
|
+
- **Warnings** about risky operations
|
|
12252
12309
|
|
|
12253
|
-
**
|
|
12310
|
+
**Without \`context()\`, you are blind to relevant context and will repeat past mistakes.**
|
|
12254
12311
|
|
|
12255
|
-
###
|
|
12312
|
+
### Protocol
|
|
12256
12313
|
|
|
12257
12314
|
| Step | What to Call |
|
|
12258
12315
|
|------|--------------|
|
|
@@ -12263,12 +12320,7 @@ Rules Version: ${RULES_VERSION}
|
|
|
12263
12320
|
| **User correction** | \`session(action="capture_lesson", ...)\` |
|
|
12264
12321
|
| **\u26A0\uFE0F When warnings received** | **STOP**, acknowledge, explain mitigation, then proceed |
|
|
12265
12322
|
|
|
12266
|
-
**
|
|
12267
|
-
- Single-word commands: "list", "show", "version", "help"
|
|
12268
|
-
- Data retrieval with no context dependency: "list my workspaces", "what projects do I have"
|
|
12269
|
-
- Status checks: "am I authenticated?", "what's the server version?"
|
|
12270
|
-
|
|
12271
|
-
**First message rule (for coding tasks):** After \`init\`:
|
|
12323
|
+
**First message rule:** After \`init\`:
|
|
12272
12324
|
1. Check for \`lessons\` in response - if present, READ and SUMMARIZE them to user
|
|
12273
12325
|
2. Then call \`context\` before any other tool or response
|
|
12274
12326
|
|
|
@@ -12368,8 +12420,8 @@ ContextStream tracks context pressure to help you stay ahead of conversation com
|
|
|
12368
12420
|
- \`prepare_save\`: Start thinking about saving important state
|
|
12369
12421
|
- \`save_now\`: Immediately call \`session(action="capture", event_type="session_snapshot")\` to preserve state
|
|
12370
12422
|
|
|
12371
|
-
**PreCompact Hook
|
|
12372
|
-
|
|
12423
|
+
**PreCompact Hook:** Automatically saves session state before context compaction.
|
|
12424
|
+
Installed by default. Disable with: \`CONTEXTSTREAM_HOOK_ENABLED=false\`
|
|
12373
12425
|
|
|
12374
12426
|
**Before compaction happens (when warned):**
|
|
12375
12427
|
\`\`\`
|
|
@@ -12591,83 +12643,71 @@ memory(action="create_task", title="<task title>", plan_id="<plan_id from step 1
|
|
|
12591
12643
|
See full documentation: https://contextstream.io/docs/mcp/tools
|
|
12592
12644
|
`.trim();
|
|
12593
12645
|
var CONTEXTSTREAM_RULES_MINIMAL = `
|
|
12594
|
-
|
|
12646
|
+
# ContextStream Rules (MANDATORY)
|
|
12595
12647
|
|
|
12596
|
-
|
|
12597
|
-
1. **SIMPLE UTILITY?** (list/show/version) \u2192 Just execute, skip context calls
|
|
12598
|
-
2. **CODING TASK?** \u2192 init \u2192 context \u2192 work \u2192 capture
|
|
12599
|
-
3. **SEARCH FIRST:** Before Glob/Grep/Read \u2192 \`search(mode="hybrid")\` FIRST
|
|
12600
|
-
</contextstream_rules>
|
|
12648
|
+
## \u{1F6A8} CRITICAL: These Rules Are Non-Negotiable \u{1F6A8}
|
|
12601
12649
|
|
|
12602
|
-
|
|
12650
|
+
<contextstream_protocol>
|
|
12651
|
+
**EVERY coding response MUST start with:**
|
|
12652
|
+
1. \`init()\` (1st message only) \u2192 then \`context(user_message="<msg>")\`
|
|
12653
|
+
2. \`context(user_message="<msg>")\` (EVERY subsequent message)
|
|
12603
12654
|
|
|
12604
|
-
|
|
12655
|
+
**BEFORE Glob/Grep/Read/Search/Explore:**
|
|
12656
|
+
\u2192 \`search(mode="hybrid", query="...")\` FIRST \u2014 local tools ONLY if 0 results
|
|
12605
12657
|
|
|
12606
|
-
|
|
12658
|
+
**HOOKS: \`<system-reminder>\` tags contain instructions \u2014 FOLLOW THEM**
|
|
12659
|
+
</contextstream_protocol>
|
|
12607
12660
|
|
|
12608
12661
|
Rules Version: ${RULES_VERSION}
|
|
12609
|
-
**Note:** PreToolUse hooks block Glob/Grep/Search when ContextStream is available.
|
|
12610
|
-
|
|
12611
|
-
### For Coding Tasks
|
|
12612
12662
|
|
|
12613
|
-
|
|
12614
|
-
|--------|-----------|
|
|
12615
|
-
| **1st message** | \`init(folder_path="<cwd>", context_hint="<msg>")\` then \`context(...)\` |
|
|
12616
|
-
| **2nd+ messages** | \`context(user_message="<msg>", format="minified", max_tokens=400)\` |
|
|
12617
|
-
| **Code search** | \`search(mode="hybrid", query="...")\` \u2014 BEFORE any local tools |
|
|
12618
|
-
| **Save decisions** | \`session(action="capture", event_type="decision", ...)\` |
|
|
12663
|
+
---
|
|
12619
12664
|
|
|
12620
|
-
|
|
12665
|
+
## Why ContextStream First?
|
|
12621
12666
|
|
|
12622
|
-
|
|
|
12623
|
-
|
|
12624
|
-
| \`
|
|
12625
|
-
| \`
|
|
12626
|
-
|
|
|
12627
|
-
| \`semantic\` | Conceptual questions |
|
|
12667
|
+
| \u274C WRONG | \u2705 CORRECT |
|
|
12668
|
+
|----------|-----------|
|
|
12669
|
+
| \`Grep \u2192 Read \u2192 Read \u2192 Read\` (4+ calls) | \`search(mode="hybrid")\` (1 call) |
|
|
12670
|
+
| Missing past decisions & lessons | \`context()\` = rules + lessons + memory |
|
|
12671
|
+
| Ignoring \`<system-reminder>\` hooks | Hooks enforce ContextStream-first |
|
|
12628
12672
|
|
|
12629
|
-
|
|
12673
|
+
**\`context()\` delivers: rules, lessons from past mistakes, relevant decisions, semantic matches**
|
|
12674
|
+
**\`search()\` is indexed: faster, returns context, one call vs many**
|
|
12675
|
+
**Hooks inject \`<system-reminder>\` tags: these ARE the rules, follow them**
|
|
12630
12676
|
|
|
12631
|
-
|
|
12632
|
-
\u2705 **CORRECT:** \`search(mode="hybrid")\` (1 call, returns context)
|
|
12677
|
+
---
|
|
12633
12678
|
|
|
12634
|
-
|
|
12679
|
+
## Protocol
|
|
12635
12680
|
|
|
12636
|
-
|
|
12681
|
+
| When | Call |
|
|
12682
|
+
|------|------|
|
|
12683
|
+
| 1st message | \`init()\` \u2192 \`context(user_message="...")\` |
|
|
12684
|
+
| Every message after | \`context(user_message="...")\` |
|
|
12685
|
+
| Before ANY file discovery | \`search(mode="hybrid", query="...")\` |
|
|
12686
|
+
| On \`<system-reminder>\` | **Follow instructions inside** |
|
|
12687
|
+
| Save important decisions | \`session(action="capture", event_type="decision", ...)\` |
|
|
12688
|
+
| Check past mistakes | \`session(action="get_lessons", query="...")\` |
|
|
12637
12689
|
|
|
12638
|
-
|
|
12639
|
-
|------|---------|
|
|
12640
|
-
| \`search\` | \`search(mode="hybrid", query="auth", limit=3)\` |
|
|
12641
|
-
| \`session\` | \`session(action="capture", event_type="decision", title="...", content="...")\` |
|
|
12642
|
-
| \`memory\` | \`memory(action="list_events", limit=10)\` |
|
|
12643
|
-
| \`graph\` | \`graph(action="dependencies", file_path="...")\` |
|
|
12690
|
+
## Search Modes
|
|
12644
12691
|
|
|
12645
|
-
|
|
12692
|
+
| Mode | When |
|
|
12693
|
+
|------|------|
|
|
12694
|
+
| \`hybrid\` | Default \u2014 semantic + keyword |
|
|
12695
|
+
| \`keyword\` | Exact symbol match |
|
|
12696
|
+
| \`exhaustive\` | Find ALL occurrences |
|
|
12697
|
+
| \`semantic\` | Conceptual questions |
|
|
12646
12698
|
|
|
12647
|
-
|
|
12699
|
+
## Handle Notices from context()
|
|
12648
12700
|
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
| List projects | \`project(action="list")\` | init, context, capture |
|
|
12653
|
-
| Show version | \`help(action="version")\` | init, context, capture |
|
|
12654
|
-
| List reminders | \`reminder(action="list")\` | init, context, capture |
|
|
12655
|
-
| Check auth | \`help(action="auth")\` | init, context, capture |
|
|
12701
|
+
- **[LESSONS_WARNING]** \u2192 Tell user about past mistakes BEFORE proceeding
|
|
12702
|
+
- **[RULES_NOTICE]** \u2192 Run \`generate_rules()\`
|
|
12703
|
+
- **[VERSION_NOTICE]** \u2192 Tell user to update MCP
|
|
12656
12704
|
|
|
12657
|
-
|
|
12658
|
-
- "list ...", "show ...", "what are my ...", "get ..."
|
|
12659
|
-
- Single-action queries with no context dependency
|
|
12660
|
-
- User just wants data, not analysis or coding help
|
|
12705
|
+
## Fast Path (Simple Utilities Only)
|
|
12661
12706
|
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
- \u274C Don't call context for simple queries
|
|
12665
|
-
- \u274C Don't capture "listed workspaces" as an event (that's noise)
|
|
12707
|
+
Skip init/context ONLY for: "list workspaces", "show version", "list reminders"
|
|
12708
|
+
\u2192 Just call: \`workspace(action="list")\`, \`help(action="version")\`, etc.
|
|
12666
12709
|
|
|
12667
|
-
|
|
12668
|
-
- Coding tasks (edit, create, refactor, debug)
|
|
12669
|
-
- Search/discovery (finding code, understanding architecture)
|
|
12670
|
-
- Tasks where past decisions or lessons matter
|
|
12710
|
+
Everything else = full protocol (init \u2192 context \u2192 search \u2192 work)
|
|
12671
12711
|
|
|
12672
12712
|
### Lessons (Past Mistakes)
|
|
12673
12713
|
|
|
@@ -12678,7 +12718,7 @@ ContextStream search is **indexed** and returns semantic matches + context in ON
|
|
|
12678
12718
|
### Context Pressure & Compaction
|
|
12679
12719
|
|
|
12680
12720
|
- If \`context\` returns high/critical \`context_pressure\`: call \`session(action="capture", ...)\` to save state
|
|
12681
|
-
- PreCompact hooks automatically save snapshots before compaction
|
|
12721
|
+
- PreCompact hooks automatically save snapshots before compaction
|
|
12682
12722
|
|
|
12683
12723
|
### Enhanced Context (Warnings)
|
|
12684
12724
|
|
|
@@ -12793,8 +12833,8 @@ function getTemplate(editor) {
|
|
|
12793
12833
|
function generateRuleContent(editor, options) {
|
|
12794
12834
|
const template = getTemplate(editor);
|
|
12795
12835
|
if (!template) return null;
|
|
12796
|
-
const mode = options?.mode || "
|
|
12797
|
-
const rules = mode === "full" ? CONTEXTSTREAM_RULES_FULL : mode === "minimal" ? CONTEXTSTREAM_RULES_MINIMAL : CONTEXTSTREAM_RULES_DYNAMIC;
|
|
12836
|
+
const mode = options?.mode || "bootstrap";
|
|
12837
|
+
const rules = mode === "full" ? CONTEXTSTREAM_RULES_FULL : mode === "minimal" ? CONTEXTSTREAM_RULES_MINIMAL : mode === "bootstrap" ? CONTEXTSTREAM_RULES_BOOTSTRAP : CONTEXTSTREAM_RULES_DYNAMIC;
|
|
12798
12838
|
let content = template.build(rules);
|
|
12799
12839
|
if (options?.workspaceName || options?.projectName) {
|
|
12800
12840
|
const header = `
|
|
@@ -13070,6 +13110,112 @@ function trackToolTokenSavings(client, tool, contextText, params, extraMetadata)
|
|
|
13070
13110
|
}
|
|
13071
13111
|
}
|
|
13072
13112
|
|
|
13113
|
+
// src/educational-microcopy.ts
|
|
13114
|
+
var SESSION_INIT_TIPS = [
|
|
13115
|
+
"AI work that doesn't disappear.",
|
|
13116
|
+
"Every conversation builds context. Every artifact persists.",
|
|
13117
|
+
"Your AI remembers. Now you can see what it knows.",
|
|
13118
|
+
"Context that survives sessions.",
|
|
13119
|
+
"The bridge between AI conversations and human artifacts."
|
|
13120
|
+
];
|
|
13121
|
+
function getSessionInitTip(sessionId) {
|
|
13122
|
+
const index = sessionId ? Math.abs(hashString(sessionId)) % SESSION_INIT_TIPS.length : Math.floor(Math.random() * SESSION_INIT_TIPS.length);
|
|
13123
|
+
return SESSION_INIT_TIPS[index];
|
|
13124
|
+
}
|
|
13125
|
+
var CAPTURE_HINTS = {
|
|
13126
|
+
// Core event types
|
|
13127
|
+
decision: "Future you will thank present you.",
|
|
13128
|
+
preference: "Noted. This will inform future suggestions.",
|
|
13129
|
+
insight: "Captured for future reference.",
|
|
13130
|
+
note: "Saved. Won't disappear when the chat does.",
|
|
13131
|
+
implementation: "Implementation recorded.",
|
|
13132
|
+
task: "Task tracked.",
|
|
13133
|
+
bug: "Bug logged for tracking.",
|
|
13134
|
+
feature: "Feature request captured.",
|
|
13135
|
+
plan: "This plan will be here when you come back.",
|
|
13136
|
+
correction: "Correction noted. Learning from this.",
|
|
13137
|
+
lesson: "Learn once, remember forever.",
|
|
13138
|
+
warning: "Warning logged.",
|
|
13139
|
+
frustration: "Feedback captured. We're listening.",
|
|
13140
|
+
conversation: "Conversation preserved.",
|
|
13141
|
+
session_snapshot: "Session state saved. Ready to resume anytime."
|
|
13142
|
+
};
|
|
13143
|
+
function getCaptureHint(eventType) {
|
|
13144
|
+
return CAPTURE_HINTS[eventType] || "Captured. This will survive when the chat disappears.";
|
|
13145
|
+
}
|
|
13146
|
+
var EMPTY_STATE_HINTS = {
|
|
13147
|
+
// Plans
|
|
13148
|
+
list_plans: "No plans yet. Plans live here, not in chat transcripts.",
|
|
13149
|
+
get_plan: "Plan not found. Create one to track implementation across sessions.",
|
|
13150
|
+
// Memory & Search
|
|
13151
|
+
recall: "Nothing found yet. Context builds over time.",
|
|
13152
|
+
search: "No matches. Try a different query or let context accumulate.",
|
|
13153
|
+
list_events: "No events yet. Start capturing decisions and insights.",
|
|
13154
|
+
decisions: "No decisions captured yet. Record the 'why' behind your choices.",
|
|
13155
|
+
timeline: "Timeline empty. Events will appear as you work.",
|
|
13156
|
+
// Lessons
|
|
13157
|
+
get_lessons: "No lessons yet. Capture mistakes to learn from them.",
|
|
13158
|
+
// Tasks
|
|
13159
|
+
list_tasks: "No tasks yet. Break plans into trackable tasks.",
|
|
13160
|
+
// Todos
|
|
13161
|
+
list_todos: "No todos yet. Action items will appear here.",
|
|
13162
|
+
// Diagrams
|
|
13163
|
+
list_diagrams: "No diagrams yet. AI-generated diagrams persist here.",
|
|
13164
|
+
// Docs
|
|
13165
|
+
list_docs: "No docs yet. Turn AI explanations into shareable documentation.",
|
|
13166
|
+
// Reminders
|
|
13167
|
+
list_reminders: "No reminders set. Schedule follow-ups that won't be forgotten.",
|
|
13168
|
+
// Generic
|
|
13169
|
+
default: "Nothing yet. Start a conversation\u2014context builds over time."
|
|
13170
|
+
};
|
|
13171
|
+
function getEmptyStateHint(action) {
|
|
13172
|
+
return EMPTY_STATE_HINTS[action] || EMPTY_STATE_HINTS.default;
|
|
13173
|
+
}
|
|
13174
|
+
var POST_COMPACT_HINTS = {
|
|
13175
|
+
restored: "Picked up where you left off. Session ended, memory didn't.",
|
|
13176
|
+
restored_with_session: (sessionId) => `Restored from session ${sessionId}. Session ended, memory didn't.`,
|
|
13177
|
+
no_snapshot: "No prior session found. Fresh start\u2014context will build as you work.",
|
|
13178
|
+
failed: "Couldn't restore previous session. Use context to retrieve what you need."
|
|
13179
|
+
};
|
|
13180
|
+
var PLAN_HINTS = {
|
|
13181
|
+
created: "Plan saved. It will be here when you come back.",
|
|
13182
|
+
activated: "Plan is now active. Track progress across sessions.",
|
|
13183
|
+
completed: "Plan completed. The journey is preserved for future reference.",
|
|
13184
|
+
abandoned: "Plan archived. Abandoned plans still teach.",
|
|
13185
|
+
updated: "Plan updated. Changes are preserved."
|
|
13186
|
+
};
|
|
13187
|
+
function getPlanStatusHint(status) {
|
|
13188
|
+
const statusMap = {
|
|
13189
|
+
draft: PLAN_HINTS.created,
|
|
13190
|
+
active: PLAN_HINTS.activated,
|
|
13191
|
+
completed: PLAN_HINTS.completed,
|
|
13192
|
+
abandoned: PLAN_HINTS.abandoned,
|
|
13193
|
+
archived: PLAN_HINTS.abandoned
|
|
13194
|
+
};
|
|
13195
|
+
return statusMap[status] || PLAN_HINTS.updated;
|
|
13196
|
+
}
|
|
13197
|
+
var TASK_HINTS = {
|
|
13198
|
+
created: "Task tracked. It won't disappear when the chat does.",
|
|
13199
|
+
completed: "Task done. Progress is preserved.",
|
|
13200
|
+
blocked: "Task blocked. Capture what's blocking for future reference.",
|
|
13201
|
+
cancelled: "Task cancelled. The history remains."
|
|
13202
|
+
};
|
|
13203
|
+
var INTEGRATION_HINTS = {
|
|
13204
|
+
not_connected: "Connect integrations to sync context where your team already works.",
|
|
13205
|
+
slack: "Context from Slack conversations, connected.",
|
|
13206
|
+
github: "Issues and PRs linked to the decisions behind them.",
|
|
13207
|
+
notion: "Decisions synced to where your team documents."
|
|
13208
|
+
};
|
|
13209
|
+
function hashString(str) {
|
|
13210
|
+
let hash = 0;
|
|
13211
|
+
for (let i = 0; i < str.length; i++) {
|
|
13212
|
+
const char = str.charCodeAt(i);
|
|
13213
|
+
hash = (hash << 5) - hash + char;
|
|
13214
|
+
hash = hash & hash;
|
|
13215
|
+
}
|
|
13216
|
+
return hash;
|
|
13217
|
+
}
|
|
13218
|
+
|
|
13073
13219
|
// src/tools.ts
|
|
13074
13220
|
var LOG_LEVEL = (process.env.CONTEXTSTREAM_LOG_LEVEL || "normal").toLowerCase();
|
|
13075
13221
|
var LOG_QUIET = LOG_LEVEL === "quiet";
|
|
@@ -13135,6 +13281,7 @@ var lastAutoSavePressureLevel = "";
|
|
|
13135
13281
|
var contextCallsSinceLastSave = 0;
|
|
13136
13282
|
var SEARCH_RULES_REMINDER_ENABLED = process.env.CONTEXTSTREAM_SEARCH_REMINDER?.toLowerCase() !== "false";
|
|
13137
13283
|
var SEARCH_RULES_REMINDER = `[SEARCH] Use search(mode="hybrid") before Glob/Grep/Read. Local tools only if 0 results.`;
|
|
13284
|
+
var CONTEXT_CALL_REMINDER = `[CONTEXT] Call context(user_message="...") at start of EVERY response. This is MANDATORY.`;
|
|
13138
13285
|
var LESSONS_REMINDER_PREFIX = `
|
|
13139
13286
|
\u{1F6A8} [LESSONS_WARNING] Past Mistakes Found - READ BEFORE PROCEEDING!
|
|
13140
13287
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
@@ -16821,6 +16968,8 @@ This does semantic search on the first message. You only need context on subsequ
|
|
|
16821
16968
|
ideRoots
|
|
16822
16969
|
);
|
|
16823
16970
|
result.tools_hint = getCoreToolsHint();
|
|
16971
|
+
const sessionId = typeof result.session_id === "string" ? result.session_id : void 0;
|
|
16972
|
+
result.educational_tip = getSessionInitTip(sessionId);
|
|
16824
16973
|
const shouldRestoreContext = input.is_post_compact ?? RESTORE_CONTEXT_DEFAULT;
|
|
16825
16974
|
if (shouldRestoreContext) {
|
|
16826
16975
|
result.is_post_compact = true;
|
|
@@ -16890,15 +17039,15 @@ This does semantic search on the first message. You only need context on subsequ
|
|
|
16890
17039
|
...snapshotData
|
|
16891
17040
|
};
|
|
16892
17041
|
result.is_post_compact = true;
|
|
16893
|
-
result.post_compact_hint = prevSessionId ?
|
|
17042
|
+
result.post_compact_hint = prevSessionId ? POST_COMPACT_HINTS.restored_with_session(prevSessionId) : POST_COMPACT_HINTS.restored;
|
|
16894
17043
|
} else {
|
|
16895
17044
|
result.is_post_compact = true;
|
|
16896
|
-
result.post_compact_hint =
|
|
17045
|
+
result.post_compact_hint = POST_COMPACT_HINTS.no_snapshot;
|
|
16897
17046
|
}
|
|
16898
17047
|
} catch (err) {
|
|
16899
17048
|
logDebug(`Failed to restore post-compact context: ${err}`);
|
|
16900
17049
|
result.is_post_compact = true;
|
|
16901
|
-
result.post_compact_hint =
|
|
17050
|
+
result.post_compact_hint = POST_COMPACT_HINTS.failed;
|
|
16902
17051
|
}
|
|
16903
17052
|
}
|
|
16904
17053
|
}
|
|
@@ -16934,7 +17083,7 @@ This does semantic search on the first message. You only need context on subsequ
|
|
|
16934
17083
|
slack_connected: intStatus.slack,
|
|
16935
17084
|
github_connected: intStatus.github,
|
|
16936
17085
|
auto_hide_enabled: true,
|
|
16937
|
-
hint: intStatus.slack || intStatus.github ? "Integration tools are now available in the tool list." :
|
|
17086
|
+
hint: intStatus.slack || intStatus.github ? "Integration tools are now available in the tool list." : INTEGRATION_HINTS.not_connected + " https://contextstream.io/settings/integrations"
|
|
16938
17087
|
};
|
|
16939
17088
|
} catch (error) {
|
|
16940
17089
|
logDebug(`Failed to check integration status: ${error}`);
|
|
@@ -17946,11 +18095,11 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
|
|
|
17946
18095
|
workspace_id: external_exports.string().uuid().optional().describe("Workspace ID to include in rules"),
|
|
17947
18096
|
project_name: external_exports.string().optional().describe("Project name to include in rules"),
|
|
17948
18097
|
additional_rules: external_exports.string().optional().describe("Additional project-specific rules to append"),
|
|
17949
|
-
mode: external_exports.enum(["minimal", "full"]).optional().describe("Rule verbosity
|
|
17950
|
-
overwrite_existing: external_exports.boolean().optional().describe("
|
|
18098
|
+
mode: external_exports.enum(["minimal", "full", "bootstrap"]).optional().default("bootstrap").describe("Rule verbosity: bootstrap (~15 lines, recommended), minimal (~80 lines), full (~600 lines)"),
|
|
18099
|
+
overwrite_existing: external_exports.boolean().optional().default(true).describe("Overwrite ContextStream block in existing rule files (default: true). User content outside the block is preserved."),
|
|
17951
18100
|
apply_global: external_exports.boolean().optional().describe("Also write global rule files for supported editors"),
|
|
17952
18101
|
install_hooks: external_exports.boolean().optional().describe("Install Claude Code hooks to enforce ContextStream-first search. Defaults to true for Claude users. Set to false to skip."),
|
|
17953
|
-
include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for automatic state saving before context compaction. Defaults to
|
|
18102
|
+
include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for automatic state saving before context compaction. Defaults to true."),
|
|
17954
18103
|
dry_run: external_exports.boolean().optional().describe("If true, return content without writing files")
|
|
17955
18104
|
})
|
|
17956
18105
|
},
|
|
@@ -18041,7 +18190,7 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
|
|
|
18041
18190
|
{ editor, file: "~/.claude/hooks/contextstream-reminder.py", status: "dry run - would create" },
|
|
18042
18191
|
{ editor, file: "~/.claude/settings.json", status: "dry run - would update" }
|
|
18043
18192
|
);
|
|
18044
|
-
if (input.include_pre_compact) {
|
|
18193
|
+
if (input.include_pre_compact !== false) {
|
|
18045
18194
|
hooksResults.push({ editor, file: "~/.claude/hooks/contextstream-precompact.py", status: "dry run - would create" });
|
|
18046
18195
|
}
|
|
18047
18196
|
} else if (editor === "cline") {
|
|
@@ -18072,7 +18221,7 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
|
|
|
18072
18221
|
const allHookResults = await installAllEditorHooks({
|
|
18073
18222
|
scope: "global",
|
|
18074
18223
|
editors: hookSupportedEditors,
|
|
18075
|
-
includePreCompact: input.include_pre_compact
|
|
18224
|
+
includePreCompact: input.include_pre_compact !== false
|
|
18076
18225
|
});
|
|
18077
18226
|
for (const result of allHookResults) {
|
|
18078
18227
|
for (const file of result.installed) {
|
|
@@ -18659,6 +18808,9 @@ Action: ${cp.suggested_action === "prepare_save" ? "Consider saving important de
|
|
|
18659
18808
|
const instructionsLine = result.instructions ? `
|
|
18660
18809
|
|
|
18661
18810
|
[INSTRUCTIONS] ${result.instructions}` : "";
|
|
18811
|
+
const contextRulesLine = `
|
|
18812
|
+
|
|
18813
|
+
${CONTEXT_CALL_REMINDER}`;
|
|
18662
18814
|
const allWarnings = [
|
|
18663
18815
|
serverWarningsLine || lessonsWarningLine,
|
|
18664
18816
|
// Server warnings OR client-side lesson detection
|
|
@@ -18671,6 +18823,8 @@ ${versionWarningLine}` : "",
|
|
|
18671
18823
|
contextPressureWarning,
|
|
18672
18824
|
semanticHints,
|
|
18673
18825
|
instructionsLine,
|
|
18826
|
+
contextRulesLine,
|
|
18827
|
+
// Reinforce context() must be called every message
|
|
18674
18828
|
searchRulesLine
|
|
18675
18829
|
].filter(Boolean).join("");
|
|
18676
18830
|
const finalContext = postCompactContext + result.context;
|
|
@@ -19929,8 +20083,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
19929
20083
|
code_refs: input.code_refs,
|
|
19930
20084
|
provenance: input.provenance
|
|
19931
20085
|
});
|
|
20086
|
+
const captureHint = getCaptureHint(input.event_type);
|
|
20087
|
+
const resultWithHint = { ...result, hint: captureHint };
|
|
19932
20088
|
return {
|
|
19933
|
-
content: [{ type: "text", text: formatContent(
|
|
20089
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
19934
20090
|
};
|
|
19935
20091
|
}
|
|
19936
20092
|
case "capture_lesson": {
|
|
@@ -19986,8 +20142,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
19986
20142
|
importance: input.severity === "critical" ? "critical" : input.severity === "high" ? "high" : "medium",
|
|
19987
20143
|
tags: input.keywords || []
|
|
19988
20144
|
});
|
|
20145
|
+
const lessonHint = getCaptureHint("lesson");
|
|
20146
|
+
const resultWithHint = { ...result, hint: lessonHint };
|
|
19989
20147
|
return {
|
|
19990
|
-
content: [{ type: "text", text: formatContent(
|
|
20148
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
19991
20149
|
};
|
|
19992
20150
|
}
|
|
19993
20151
|
case "get_lessons": {
|
|
@@ -20000,8 +20158,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
20000
20158
|
context_hint: input.query,
|
|
20001
20159
|
limit: input.limit
|
|
20002
20160
|
});
|
|
20161
|
+
const lessons = result?.data?.lessons || result?.lessons || [];
|
|
20162
|
+
const resultWithHint = Array.isArray(lessons) && lessons.length === 0 ? { ...result, hint: getEmptyStateHint("get_lessons") } : result;
|
|
20003
20163
|
return {
|
|
20004
|
-
content: [{ type: "text", text: formatContent(
|
|
20164
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20005
20165
|
};
|
|
20006
20166
|
}
|
|
20007
20167
|
case "recall": {
|
|
@@ -20015,7 +20175,9 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
20015
20175
|
include_related: input.include_related,
|
|
20016
20176
|
include_decisions: input.include_decisions
|
|
20017
20177
|
});
|
|
20018
|
-
const
|
|
20178
|
+
const recallResults = result?.data?.results || result?.results || [];
|
|
20179
|
+
const recallWithHint = Array.isArray(recallResults) && recallResults.length === 0 ? { ...result, hint: getEmptyStateHint("recall") } : result;
|
|
20180
|
+
const outputText = formatContent(recallWithHint);
|
|
20019
20181
|
trackToolTokenSavings(client, "session_recall", outputText, {
|
|
20020
20182
|
workspace_id: workspaceId,
|
|
20021
20183
|
project_id: projectId
|
|
@@ -20035,8 +20197,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
20035
20197
|
content: input.content,
|
|
20036
20198
|
importance
|
|
20037
20199
|
});
|
|
20200
|
+
const rememberHint = getCaptureHint("preference");
|
|
20201
|
+
const resultWithHint = { ...result, hint: rememberHint };
|
|
20038
20202
|
return {
|
|
20039
|
-
content: [{ type: "text", text: formatContent(
|
|
20203
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20040
20204
|
};
|
|
20041
20205
|
}
|
|
20042
20206
|
case "user_context": {
|
|
@@ -20149,8 +20313,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
20149
20313
|
source_tool: input.source_tool || "mcp",
|
|
20150
20314
|
is_personal: input.is_personal
|
|
20151
20315
|
});
|
|
20316
|
+
const planHint = getPlanStatusHint(input.status || "draft");
|
|
20317
|
+
const resultWithHint = { ...result, hint: planHint };
|
|
20152
20318
|
return {
|
|
20153
|
-
content: [{ type: "text", text: formatContent(
|
|
20319
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20154
20320
|
};
|
|
20155
20321
|
}
|
|
20156
20322
|
case "get_plan": {
|
|
@@ -20180,8 +20346,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
20180
20346
|
tags: input.tags,
|
|
20181
20347
|
due_at: input.due_at
|
|
20182
20348
|
});
|
|
20349
|
+
const planUpdateHint = input.status ? getPlanStatusHint(input.status) : "Plan updated. Changes are preserved.";
|
|
20350
|
+
const resultWithHint = { ...result, hint: planUpdateHint };
|
|
20183
20351
|
return {
|
|
20184
|
-
content: [{ type: "text", text: formatContent(
|
|
20352
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20185
20353
|
};
|
|
20186
20354
|
}
|
|
20187
20355
|
case "list_plans": {
|
|
@@ -20195,8 +20363,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
20195
20363
|
limit: input.limit,
|
|
20196
20364
|
is_personal: input.is_personal
|
|
20197
20365
|
});
|
|
20366
|
+
const plans = result?.data?.plans || result?.plans || result?.data?.items || result?.items || [];
|
|
20367
|
+
const resultWithHint = plans.length === 0 ? { ...result, hint: getEmptyStateHint("list_plans") } : result;
|
|
20198
20368
|
return {
|
|
20199
|
-
content: [{ type: "text", text: formatContent(
|
|
20369
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20200
20370
|
};
|
|
20201
20371
|
}
|
|
20202
20372
|
case "restore_context": {
|
|
@@ -20690,8 +20860,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
20690
20860
|
project_id: projectId,
|
|
20691
20861
|
limit: input.limit
|
|
20692
20862
|
});
|
|
20863
|
+
const events = result?.data?.items || result?.items || result?.data || [];
|
|
20864
|
+
const resultWithHint = Array.isArray(events) && events.length === 0 ? { ...result, hint: getEmptyStateHint("list_events") } : result;
|
|
20693
20865
|
return {
|
|
20694
|
-
content: [{ type: "text", text: formatContent(
|
|
20866
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20695
20867
|
};
|
|
20696
20868
|
}
|
|
20697
20869
|
case "import_batch": {
|
|
@@ -20884,8 +21056,10 @@ ${formatContent(result)}`
|
|
|
20884
21056
|
tags: input.tags,
|
|
20885
21057
|
is_personal: input.is_personal
|
|
20886
21058
|
});
|
|
21059
|
+
const taskCreateHint = TASK_HINTS.created;
|
|
21060
|
+
const resultWithHint = { ...result, hint: taskCreateHint };
|
|
20887
21061
|
return {
|
|
20888
|
-
content: [{ type: "text", text: formatContent(
|
|
21062
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20889
21063
|
};
|
|
20890
21064
|
}
|
|
20891
21065
|
case "get_task": {
|
|
@@ -20917,8 +21091,17 @@ ${formatContent(result)}`
|
|
|
20917
21091
|
tags: input.tags,
|
|
20918
21092
|
blocked_reason: input.blocked_reason
|
|
20919
21093
|
});
|
|
21094
|
+
let taskUpdateHint = "Task updated.";
|
|
21095
|
+
if (input.task_status === "completed") {
|
|
21096
|
+
taskUpdateHint = TASK_HINTS.completed;
|
|
21097
|
+
} else if (input.task_status === "blocked") {
|
|
21098
|
+
taskUpdateHint = TASK_HINTS.blocked;
|
|
21099
|
+
} else if (input.task_status === "cancelled") {
|
|
21100
|
+
taskUpdateHint = TASK_HINTS.cancelled;
|
|
21101
|
+
}
|
|
21102
|
+
const resultWithHint = { ...result, hint: taskUpdateHint };
|
|
20920
21103
|
return {
|
|
20921
|
-
content: [{ type: "text", text: formatContent(
|
|
21104
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20922
21105
|
};
|
|
20923
21106
|
}
|
|
20924
21107
|
case "delete_task": {
|
|
@@ -20945,8 +21128,10 @@ ${formatContent(result)}`
|
|
|
20945
21128
|
limit: input.limit,
|
|
20946
21129
|
is_personal: input.is_personal
|
|
20947
21130
|
});
|
|
21131
|
+
const tasks = result?.data?.tasks || result?.tasks || result?.data?.items || result?.items || [];
|
|
21132
|
+
const resultWithHint = Array.isArray(tasks) && tasks.length === 0 ? { ...result, hint: getEmptyStateHint("list_tasks") } : result;
|
|
20948
21133
|
return {
|
|
20949
|
-
content: [{ type: "text", text: formatContent(
|
|
21134
|
+
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
20950
21135
|
};
|
|
20951
21136
|
}
|
|
20952
21137
|
case "reorder_tasks": {
|
|
@@ -20998,8 +21183,10 @@ ${formatContent(result)}`
|
|
|
20998
21183
|
priority: input.todo_priority,
|
|
20999
21184
|
is_personal: input.is_personal
|
|
21000
21185
|
});
|
|
21186
|
+
const todos = todosResult?.data?.todos || todosResult?.todos || todosResult?.data?.items || todosResult?.items || [];
|
|
21187
|
+
const todosWithHint = Array.isArray(todos) && todos.length === 0 ? { ...todosResult, hint: getEmptyStateHint("list_todos") } : todosResult;
|
|
21001
21188
|
return {
|
|
21002
|
-
content: [{ type: "text", text: formatContent(
|
|
21189
|
+
content: [{ type: "text", text: formatContent(todosWithHint) }]
|
|
21003
21190
|
};
|
|
21004
21191
|
}
|
|
21005
21192
|
case "get_todo": {
|
|
@@ -21075,8 +21262,10 @@ ${formatContent(result)}`
|
|
|
21075
21262
|
diagram_type: input.diagram_type,
|
|
21076
21263
|
is_personal: input.is_personal
|
|
21077
21264
|
});
|
|
21265
|
+
const diagrams = diagramsResult?.data?.diagrams || diagramsResult?.diagrams || diagramsResult?.data?.items || diagramsResult?.items || [];
|
|
21266
|
+
const diagramsWithHint = Array.isArray(diagrams) && diagrams.length === 0 ? { ...diagramsResult, hint: getEmptyStateHint("list_diagrams") } : diagramsResult;
|
|
21078
21267
|
return {
|
|
21079
|
-
content: [{ type: "text", text: formatContent(
|
|
21268
|
+
content: [{ type: "text", text: formatContent(diagramsWithHint) }]
|
|
21080
21269
|
};
|
|
21081
21270
|
}
|
|
21082
21271
|
case "get_diagram": {
|
|
@@ -21120,13 +21309,19 @@ ${formatContent(result)}`
|
|
|
21120
21309
|
if (!workspaceId) {
|
|
21121
21310
|
return errorResult("create_doc requires workspace_id. Call session_init first.");
|
|
21122
21311
|
}
|
|
21312
|
+
const detectedEditor = getDetectedClientName();
|
|
21313
|
+
const aiMetadata = detectedEditor ? {
|
|
21314
|
+
created_by_ai: true,
|
|
21315
|
+
ai_editor: detectedEditor,
|
|
21316
|
+
...input.metadata || {}
|
|
21317
|
+
} : input.metadata;
|
|
21123
21318
|
const docResult = await client.docsCreate({
|
|
21124
21319
|
workspace_id: workspaceId,
|
|
21125
21320
|
project_id: projectId,
|
|
21126
21321
|
title: input.title,
|
|
21127
21322
|
content: input.content,
|
|
21128
21323
|
doc_type: input.doc_type,
|
|
21129
|
-
metadata:
|
|
21324
|
+
metadata: aiMetadata,
|
|
21130
21325
|
is_personal: input.is_personal
|
|
21131
21326
|
});
|
|
21132
21327
|
return {
|
|
@@ -21143,8 +21338,10 @@ ${formatContent(result)}`
|
|
|
21143
21338
|
doc_type: input.doc_type,
|
|
21144
21339
|
is_personal: input.is_personal
|
|
21145
21340
|
});
|
|
21341
|
+
const docs = docsResult?.data?.docs || docsResult?.docs || docsResult?.data?.items || docsResult?.items || [];
|
|
21342
|
+
const docsWithHint = Array.isArray(docs) && docs.length === 0 ? { ...docsResult, hint: getEmptyStateHint("list_docs") } : docsResult;
|
|
21146
21343
|
return {
|
|
21147
|
-
content: [{ type: "text", text: formatContent(
|
|
21344
|
+
content: [{ type: "text", text: formatContent(docsWithHint) }]
|
|
21148
21345
|
};
|
|
21149
21346
|
}
|
|
21150
21347
|
case "get_doc": {
|
|
@@ -23042,14 +23239,14 @@ Content ID: ${input.content_id}`
|
|
|
23042
23239
|
// For editor_rules
|
|
23043
23240
|
folder_path: external_exports.string().optional(),
|
|
23044
23241
|
editors: external_exports.array(external_exports.string()).optional(),
|
|
23045
|
-
mode: external_exports.enum(["minimal", "full"]).optional(),
|
|
23242
|
+
mode: external_exports.enum(["minimal", "full", "bootstrap"]).optional(),
|
|
23046
23243
|
dry_run: external_exports.boolean().optional(),
|
|
23047
23244
|
workspace_id: external_exports.string().uuid().optional(),
|
|
23048
23245
|
workspace_name: external_exports.string().optional(),
|
|
23049
23246
|
project_name: external_exports.string().optional(),
|
|
23050
23247
|
additional_rules: external_exports.string().optional(),
|
|
23051
23248
|
install_hooks: external_exports.boolean().optional().describe("Install Claude Code hooks (PreToolUse, UserPromptSubmit, PostToolUse). Default: true for Claude users."),
|
|
23052
|
-
include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for auto-saving state before compaction. Default:
|
|
23249
|
+
include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for auto-saving state before compaction. Default: true."),
|
|
23053
23250
|
include_post_write: external_exports.boolean().optional().describe("Include PostToolUse hook for real-time file indexing after Edit/Write operations. Default: true."),
|
|
23054
23251
|
// For enable_bundle
|
|
23055
23252
|
bundle: external_exports.enum([
|
|
@@ -23106,7 +23303,7 @@ Each domain tool has an 'action' parameter for specific operations.` : "";
|
|
|
23106
23303
|
scope: input.folder_path ? "both" : "user",
|
|
23107
23304
|
projectPath: input.folder_path,
|
|
23108
23305
|
dryRun: input.dry_run,
|
|
23109
|
-
includePreCompact: input.include_pre_compact,
|
|
23306
|
+
includePreCompact: input.include_pre_compact !== false,
|
|
23110
23307
|
includePostWrite: input.include_post_write
|
|
23111
23308
|
});
|
|
23112
23309
|
} catch (err) {
|
|
@@ -23207,7 +23404,7 @@ function registerLimitedTools(server) {
|
|
|
23207
23404
|
text: `ContextStream: API key not configured.
|
|
23208
23405
|
|
|
23209
23406
|
To set up (creates key + configures your editor):
|
|
23210
|
-
npx -y @contextstream/mcp-server setup
|
|
23407
|
+
npx --prefer-online -y @contextstream/mcp-server@latest setup
|
|
23211
23408
|
|
|
23212
23409
|
This will:
|
|
23213
23410
|
- Start a 5-day Pro trial
|
|
@@ -23215,7 +23412,7 @@ This will:
|
|
|
23215
23412
|
- Write rules files for better AI assistance
|
|
23216
23413
|
|
|
23217
23414
|
Preview first:
|
|
23218
|
-
npx -y @contextstream/mcp-server setup --dry-run
|
|
23415
|
+
npx --prefer-online -y @contextstream/mcp-server@latest setup --dry-run
|
|
23219
23416
|
|
|
23220
23417
|
After setup, restart your editor to enable all ContextStream tools.`
|
|
23221
23418
|
}
|
|
@@ -25354,13 +25551,13 @@ function buildContextStreamMcpServer(params) {
|
|
|
25354
25551
|
if (IS_WINDOWS) {
|
|
25355
25552
|
return {
|
|
25356
25553
|
command: "cmd",
|
|
25357
|
-
args: ["/c", "npx", "-y", "@contextstream/mcp-server"],
|
|
25554
|
+
args: ["/c", "npx", "--prefer-online", "-y", "@contextstream/mcp-server@latest"],
|
|
25358
25555
|
env
|
|
25359
25556
|
};
|
|
25360
25557
|
}
|
|
25361
25558
|
return {
|
|
25362
25559
|
command: "npx",
|
|
25363
|
-
args: ["-y", "@contextstream/mcp-server"],
|
|
25560
|
+
args: ["--prefer-online", "-y", "@contextstream/mcp-server@latest"],
|
|
25364
25561
|
env
|
|
25365
25562
|
};
|
|
25366
25563
|
}
|
|
@@ -25383,14 +25580,14 @@ function buildContextStreamVsCodeServer(params) {
|
|
|
25383
25580
|
return {
|
|
25384
25581
|
type: "stdio",
|
|
25385
25582
|
command: "cmd",
|
|
25386
|
-
args: ["/c", "npx", "-y", "@contextstream/mcp-server"],
|
|
25583
|
+
args: ["/c", "npx", "--prefer-online", "-y", "@contextstream/mcp-server@latest"],
|
|
25387
25584
|
env
|
|
25388
25585
|
};
|
|
25389
25586
|
}
|
|
25390
25587
|
return {
|
|
25391
25588
|
type: "stdio",
|
|
25392
25589
|
command: "npx",
|
|
25393
|
-
args: ["-y", "@contextstream/mcp-server"],
|
|
25590
|
+
args: ["--prefer-online", "-y", "@contextstream/mcp-server@latest"],
|
|
25394
25591
|
env
|
|
25395
25592
|
};
|
|
25396
25593
|
}
|
|
@@ -25484,9 +25681,9 @@ async function upsertCodexTomlConfig(filePath, params) {
|
|
|
25484
25681
|
const showTimingLine = params.showTiming ? `CONTEXTSTREAM_SHOW_TIMING = "true"
|
|
25485
25682
|
` : "";
|
|
25486
25683
|
const commandLine = IS_WINDOWS ? `command = "cmd"
|
|
25487
|
-
args = ["/c", "npx", "-y", "@contextstream/mcp-server"]
|
|
25684
|
+
args = ["/c", "npx", "--prefer-online", "-y", "@contextstream/mcp-server@latest"]
|
|
25488
25685
|
` : `command = "npx"
|
|
25489
|
-
args = ["-y", "@contextstream/mcp-server"]
|
|
25686
|
+
args = ["--prefer-online", "-y", "@contextstream/mcp-server@latest"]
|
|
25490
25687
|
`;
|
|
25491
25688
|
const block = `
|
|
25492
25689
|
|
|
@@ -25634,7 +25831,7 @@ async function runSetupWizard(args) {
|
|
|
25634
25831
|
console.log(` Latest version is v${versionNotice.latest}`);
|
|
25635
25832
|
console.log("");
|
|
25636
25833
|
console.log(" To use the latest version, exit and run:");
|
|
25637
|
-
console.log(" npx -y @contextstream/mcp-server@latest setup");
|
|
25834
|
+
console.log(" npx --prefer-online -y @contextstream/mcp-server@latest setup");
|
|
25638
25835
|
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
25639
25836
|
console.log("");
|
|
25640
25837
|
const continueAnyway = normalizeInput(
|
|
@@ -25839,7 +26036,7 @@ Code: ${device.user_code}`);
|
|
|
25839
26036
|
}
|
|
25840
26037
|
}
|
|
25841
26038
|
}
|
|
25842
|
-
const mode = "
|
|
26039
|
+
const mode = "full";
|
|
25843
26040
|
const detectedPlanName = await client.getPlanName();
|
|
25844
26041
|
const detectedGraphTier = await client.getGraphTier();
|
|
25845
26042
|
const graphTierLabel = detectedGraphTier === "full" ? "full graph" : detectedGraphTier === "lite" ? "graph-lite" : "none";
|
|
@@ -25989,10 +26186,10 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
25989
26186
|
const envHint = toolset === "router" ? " --env CONTEXTSTREAM_PROGRESSIVE_MODE=true" : "";
|
|
25990
26187
|
const packHint = contextPackEnabled === false ? " --env CONTEXTSTREAM_CONTEXT_PACK=false" : " --env CONTEXTSTREAM_CONTEXT_PACK=true";
|
|
25991
26188
|
console.log(
|
|
25992
|
-
` macOS/Linux: claude mcp add --transport stdio contextstream --scope user --env CONTEXTSTREAM_API_URL=... --env CONTEXTSTREAM_API_KEY=...${envHint}${packHint} -- npx -y @contextstream/mcp-server`
|
|
26189
|
+
` macOS/Linux: claude mcp add --transport stdio contextstream --scope user --env CONTEXTSTREAM_API_URL=... --env CONTEXTSTREAM_API_KEY=...${envHint}${packHint} -- npx --prefer-online -y @contextstream/mcp-server@latest`
|
|
25993
26190
|
);
|
|
25994
26191
|
console.log(
|
|
25995
|
-
" Windows (native): use `cmd /c npx -y @contextstream/mcp-server` after `--` if `npx` is not found."
|
|
26192
|
+
" Windows (native): use `cmd /c npx --prefer-online -y @contextstream/mcp-server@latest` after `--` if `npx` is not found."
|
|
25996
26193
|
);
|
|
25997
26194
|
continue;
|
|
25998
26195
|
}
|
|
@@ -26327,7 +26524,7 @@ function printHelp() {
|
|
|
26327
26524
|
console.log(`ContextStream MCP Server (contextstream-mcp) v${VERSION}
|
|
26328
26525
|
|
|
26329
26526
|
Usage:
|
|
26330
|
-
npx -y @contextstream/mcp-server
|
|
26527
|
+
npx --prefer-online -y @contextstream/mcp-server@latest
|
|
26331
26528
|
contextstream-mcp
|
|
26332
26529
|
contextstream-mcp setup
|
|
26333
26530
|
contextstream-mcp http
|
|
@@ -26374,10 +26571,10 @@ Environment variables:
|
|
|
26374
26571
|
Examples:
|
|
26375
26572
|
CONTEXTSTREAM_API_URL="https://api.contextstream.io" \\
|
|
26376
26573
|
CONTEXTSTREAM_API_KEY="your_api_key" \\
|
|
26377
|
-
npx -y @contextstream/mcp-server
|
|
26574
|
+
npx --prefer-online -y @contextstream/mcp-server@latest
|
|
26378
26575
|
|
|
26379
26576
|
Setup wizard:
|
|
26380
|
-
npx -y @contextstream/mcp-server setup
|
|
26577
|
+
npx --prefer-online -y @contextstream/mcp-server@latest setup
|
|
26381
26578
|
|
|
26382
26579
|
Notes:
|
|
26383
26580
|
- When used from an MCP client (e.g. Codex, Cursor, VS Code),
|
|
@@ -26391,7 +26588,7 @@ async function runLimitedModeServer() {
|
|
|
26391
26588
|
});
|
|
26392
26589
|
registerLimitedTools(server);
|
|
26393
26590
|
console.error(`ContextStream MCP server v${VERSION} (limited mode)`);
|
|
26394
|
-
console.error('Run "npx -y @contextstream/mcp-server setup" to enable all tools.');
|
|
26591
|
+
console.error('Run "npx --prefer-online -y @contextstream/mcp-server@latest setup" to enable all tools.');
|
|
26395
26592
|
const transport = new StdioServerTransport();
|
|
26396
26593
|
await server.connect(transport);
|
|
26397
26594
|
console.error("ContextStream MCP server connected (limited mode - setup required)");
|
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.49",
|
|
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",
|