@contextstream/mcp-server 0.4.34 → 0.4.36
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 +330 -147
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4297,7 +4297,7 @@ var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504])
|
|
|
4297
4297
|
var MAX_RETRIES = 3;
|
|
4298
4298
|
var BASE_DELAY = 1e3;
|
|
4299
4299
|
async function sleep(ms) {
|
|
4300
|
-
return new Promise((
|
|
4300
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
4301
4301
|
}
|
|
4302
4302
|
async function request(config, path8, options = {}) {
|
|
4303
4303
|
const { apiUrl, userAgent } = config;
|
|
@@ -4571,10 +4571,16 @@ var IGNORE_FILES = /* @__PURE__ */ new Set([
|
|
|
4571
4571
|
"composer.lock"
|
|
4572
4572
|
]);
|
|
4573
4573
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
4574
|
+
var MAX_BATCH_BYTES = 10 * 1024 * 1024;
|
|
4575
|
+
var LARGE_FILE_THRESHOLD = 2 * 1024 * 1024;
|
|
4576
|
+
var MAX_FILES_PER_BATCH = 200;
|
|
4574
4577
|
async function* readAllFilesInBatches(rootPath, options = {}) {
|
|
4575
|
-
const
|
|
4578
|
+
const maxBatchBytes = options.maxBatchBytes ?? MAX_BATCH_BYTES;
|
|
4579
|
+
const largeFileThreshold = options.largeFileThreshold ?? LARGE_FILE_THRESHOLD;
|
|
4580
|
+
const maxFilesPerBatch = options.maxFilesPerBatch ?? MAX_FILES_PER_BATCH;
|
|
4576
4581
|
const maxFileSize = options.maxFileSize ?? MAX_FILE_SIZE;
|
|
4577
4582
|
let batch = [];
|
|
4583
|
+
let currentBatchBytes = 0;
|
|
4578
4584
|
async function* walkDir(dir, relativePath = "") {
|
|
4579
4585
|
let entries;
|
|
4580
4586
|
try {
|
|
@@ -4596,28 +4602,46 @@ async function* readAllFilesInBatches(rootPath, options = {}) {
|
|
|
4596
4602
|
const stat2 = await fs.promises.stat(fullPath);
|
|
4597
4603
|
if (stat2.size > maxFileSize) continue;
|
|
4598
4604
|
const content = await fs.promises.readFile(fullPath, "utf-8");
|
|
4599
|
-
yield { path: relPath, content };
|
|
4605
|
+
yield { path: relPath, content, sizeBytes: stat2.size };
|
|
4600
4606
|
} catch {
|
|
4601
4607
|
}
|
|
4602
4608
|
}
|
|
4603
4609
|
}
|
|
4604
4610
|
}
|
|
4605
4611
|
for await (const file of walkDir(rootPath)) {
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4612
|
+
if (file.sizeBytes > largeFileThreshold) {
|
|
4613
|
+
if (batch.length > 0) {
|
|
4614
|
+
yield batch.map(({ sizeBytes, ...rest }) => rest);
|
|
4615
|
+
batch = [];
|
|
4616
|
+
currentBatchBytes = 0;
|
|
4617
|
+
}
|
|
4618
|
+
yield [{ path: file.path, content: file.content }];
|
|
4619
|
+
continue;
|
|
4610
4620
|
}
|
|
4621
|
+
const wouldExceedBytes = currentBatchBytes + file.sizeBytes > maxBatchBytes;
|
|
4622
|
+
const wouldExceedFiles = batch.length >= maxFilesPerBatch;
|
|
4623
|
+
if (wouldExceedBytes || wouldExceedFiles) {
|
|
4624
|
+
if (batch.length > 0) {
|
|
4625
|
+
yield batch.map(({ sizeBytes, ...rest }) => rest);
|
|
4626
|
+
batch = [];
|
|
4627
|
+
currentBatchBytes = 0;
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
batch.push(file);
|
|
4631
|
+
currentBatchBytes += file.sizeBytes;
|
|
4611
4632
|
}
|
|
4612
4633
|
if (batch.length > 0) {
|
|
4613
|
-
yield batch;
|
|
4634
|
+
yield batch.map(({ sizeBytes, ...rest }) => rest);
|
|
4614
4635
|
}
|
|
4615
4636
|
}
|
|
4616
4637
|
async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}) {
|
|
4617
|
-
const
|
|
4638
|
+
const maxBatchBytes = options.maxBatchBytes ?? MAX_BATCH_BYTES;
|
|
4639
|
+
const largeFileThreshold = options.largeFileThreshold ?? LARGE_FILE_THRESHOLD;
|
|
4640
|
+
const maxFilesPerBatch = options.maxFilesPerBatch ?? MAX_FILES_PER_BATCH;
|
|
4618
4641
|
const maxFileSize = options.maxFileSize ?? MAX_FILE_SIZE;
|
|
4619
4642
|
const sinceMs = sinceTimestamp.getTime();
|
|
4620
4643
|
let batch = [];
|
|
4644
|
+
let currentBatchBytes = 0;
|
|
4621
4645
|
let filesScanned = 0;
|
|
4622
4646
|
let filesChanged = 0;
|
|
4623
4647
|
async function* walkDir(dir, relativePath = "") {
|
|
@@ -4644,21 +4668,36 @@ async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}
|
|
|
4644
4668
|
if (stat2.size > maxFileSize) continue;
|
|
4645
4669
|
const content = await fs.promises.readFile(fullPath, "utf-8");
|
|
4646
4670
|
filesChanged++;
|
|
4647
|
-
yield { path: relPath, content };
|
|
4671
|
+
yield { path: relPath, content, sizeBytes: stat2.size };
|
|
4648
4672
|
} catch {
|
|
4649
4673
|
}
|
|
4650
4674
|
}
|
|
4651
4675
|
}
|
|
4652
4676
|
}
|
|
4653
4677
|
for await (const file of walkDir(rootPath)) {
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4678
|
+
if (file.sizeBytes > largeFileThreshold) {
|
|
4679
|
+
if (batch.length > 0) {
|
|
4680
|
+
yield batch.map(({ sizeBytes, ...rest }) => rest);
|
|
4681
|
+
batch = [];
|
|
4682
|
+
currentBatchBytes = 0;
|
|
4683
|
+
}
|
|
4684
|
+
yield [{ path: file.path, content: file.content }];
|
|
4685
|
+
continue;
|
|
4686
|
+
}
|
|
4687
|
+
const wouldExceedBytes = currentBatchBytes + file.sizeBytes > maxBatchBytes;
|
|
4688
|
+
const wouldExceedFiles = batch.length >= maxFilesPerBatch;
|
|
4689
|
+
if (wouldExceedBytes || wouldExceedFiles) {
|
|
4690
|
+
if (batch.length > 0) {
|
|
4691
|
+
yield batch.map(({ sizeBytes, ...rest }) => rest);
|
|
4692
|
+
batch = [];
|
|
4693
|
+
currentBatchBytes = 0;
|
|
4694
|
+
}
|
|
4658
4695
|
}
|
|
4696
|
+
batch.push(file);
|
|
4697
|
+
currentBatchBytes += file.sizeBytes;
|
|
4659
4698
|
}
|
|
4660
4699
|
if (batch.length > 0) {
|
|
4661
|
-
yield batch;
|
|
4700
|
+
yield batch.map(({ sizeBytes, ...rest }) => rest);
|
|
4662
4701
|
}
|
|
4663
4702
|
console.error(
|
|
4664
4703
|
`[ContextStream] Incremental scan: ${filesChanged} changed files out of ${filesScanned} scanned (since ${sinceTimestamp.toISOString()})`
|
|
@@ -5078,7 +5117,7 @@ var ContextStreamClient = class {
|
|
|
5078
5117
|
return "full";
|
|
5079
5118
|
}
|
|
5080
5119
|
if (planName.includes("pro")) return "lite";
|
|
5081
|
-
if (planName.includes("free")) return "
|
|
5120
|
+
if (planName.includes("free")) return "lite";
|
|
5082
5121
|
return "lite";
|
|
5083
5122
|
} catch {
|
|
5084
5123
|
return "none";
|
|
@@ -6610,19 +6649,6 @@ var ContextStreamClient = class {
|
|
|
6610
6649
|
used += next.length;
|
|
6611
6650
|
}
|
|
6612
6651
|
const summary = finalLines.join("\n");
|
|
6613
|
-
this.trackTokenSavings({
|
|
6614
|
-
tool: "session_summary",
|
|
6615
|
-
workspace_id: withDefaults.workspace_id,
|
|
6616
|
-
project_id: withDefaults.project_id,
|
|
6617
|
-
candidate_chars: candidateSummary.length,
|
|
6618
|
-
context_chars: summary.length,
|
|
6619
|
-
max_tokens: maxTokens,
|
|
6620
|
-
metadata: {
|
|
6621
|
-
decision_count: decisionCount,
|
|
6622
|
-
memory_count: memoryCount
|
|
6623
|
-
}
|
|
6624
|
-
}).catch(() => {
|
|
6625
|
-
});
|
|
6626
6652
|
return {
|
|
6627
6653
|
summary,
|
|
6628
6654
|
workspace_name: workspaceName,
|
|
@@ -6864,21 +6890,6 @@ var ContextStreamClient = class {
|
|
|
6864
6890
|
const context = parts.join("");
|
|
6865
6891
|
const candidateContext = candidateParts.join("");
|
|
6866
6892
|
const tokenEstimate = Math.ceil(context.length / charsPerToken);
|
|
6867
|
-
this.trackTokenSavings({
|
|
6868
|
-
tool: "ai_context_budget",
|
|
6869
|
-
workspace_id: withDefaults.workspace_id,
|
|
6870
|
-
project_id: withDefaults.project_id,
|
|
6871
|
-
candidate_chars: candidateContext.length,
|
|
6872
|
-
context_chars: context.length,
|
|
6873
|
-
max_tokens: maxTokens,
|
|
6874
|
-
metadata: {
|
|
6875
|
-
include_decisions: params.include_decisions !== false,
|
|
6876
|
-
include_memory: params.include_memory !== false,
|
|
6877
|
-
include_code: !!params.include_code,
|
|
6878
|
-
sources: sources.length
|
|
6879
|
-
}
|
|
6880
|
-
}).catch(() => {
|
|
6881
|
-
});
|
|
6882
6893
|
return {
|
|
6883
6894
|
context,
|
|
6884
6895
|
token_estimate: tokenEstimate,
|
|
@@ -7222,21 +7233,6 @@ W:${wsHint}
|
|
|
7222
7233
|
versionNotice = await getUpdateNotice();
|
|
7223
7234
|
} catch {
|
|
7224
7235
|
}
|
|
7225
|
-
this.trackTokenSavings({
|
|
7226
|
-
tool: "context_smart",
|
|
7227
|
-
workspace_id: withDefaults.workspace_id,
|
|
7228
|
-
project_id: withDefaults.project_id,
|
|
7229
|
-
candidate_chars: candidateContext.length,
|
|
7230
|
-
context_chars: context.length,
|
|
7231
|
-
max_tokens: maxTokens,
|
|
7232
|
-
metadata: {
|
|
7233
|
-
format,
|
|
7234
|
-
items: items.length,
|
|
7235
|
-
keywords: keywords.slice(0, 10),
|
|
7236
|
-
errors: errors.length
|
|
7237
|
-
}
|
|
7238
|
-
}).catch(() => {
|
|
7239
|
-
});
|
|
7240
7236
|
return {
|
|
7241
7237
|
context,
|
|
7242
7238
|
token_estimate: Math.ceil(context.length / 4),
|
|
@@ -7885,6 +7881,29 @@ W:${wsHint}
|
|
|
7885
7881
|
{ method: "GET" }
|
|
7886
7882
|
);
|
|
7887
7883
|
}
|
|
7884
|
+
/**
|
|
7885
|
+
* Create a new Notion database
|
|
7886
|
+
*/
|
|
7887
|
+
async notionCreateDatabase(params) {
|
|
7888
|
+
const withDefaults = this.withDefaults(params || {});
|
|
7889
|
+
if (!withDefaults.workspace_id) {
|
|
7890
|
+
throw new Error("workspace_id is required for creating Notion database");
|
|
7891
|
+
}
|
|
7892
|
+
const query = new URLSearchParams();
|
|
7893
|
+
query.set("workspace_id", withDefaults.workspace_id);
|
|
7894
|
+
return request(
|
|
7895
|
+
this.config,
|
|
7896
|
+
`/integrations/notion/databases?${query.toString()}`,
|
|
7897
|
+
{
|
|
7898
|
+
method: "POST",
|
|
7899
|
+
body: {
|
|
7900
|
+
title: params.title,
|
|
7901
|
+
parent_page_id: params.parent_page_id,
|
|
7902
|
+
description: params.description
|
|
7903
|
+
}
|
|
7904
|
+
}
|
|
7905
|
+
);
|
|
7906
|
+
}
|
|
7888
7907
|
/**
|
|
7889
7908
|
* Search/list pages in Notion with smart type detection filtering
|
|
7890
7909
|
*/
|
|
@@ -8925,13 +8944,21 @@ var PRETOOLUSE_HOOK_SCRIPT = `#!/usr/bin/env python3
|
|
|
8925
8944
|
"""
|
|
8926
8945
|
ContextStream PreToolUse Hook for Claude Code
|
|
8927
8946
|
Blocks Grep/Glob/Search/Task(Explore)/EnterPlanMode and redirects to ContextStream.
|
|
8947
|
+
|
|
8948
|
+
Only blocks if the current project is indexed in ContextStream.
|
|
8949
|
+
If not indexed, allows local tools through with a suggestion to index.
|
|
8928
8950
|
"""
|
|
8929
8951
|
|
|
8930
8952
|
import json
|
|
8931
8953
|
import sys
|
|
8932
8954
|
import os
|
|
8955
|
+
from pathlib import Path
|
|
8956
|
+
from datetime import datetime, timedelta
|
|
8933
8957
|
|
|
8934
8958
|
ENABLED = os.environ.get("CONTEXTSTREAM_HOOK_ENABLED", "true").lower() == "true"
|
|
8959
|
+
INDEX_STATUS_FILE = Path.home() / ".contextstream" / "indexed-projects.json"
|
|
8960
|
+
# Consider index stale after 7 days
|
|
8961
|
+
STALE_THRESHOLD_DAYS = 7
|
|
8935
8962
|
|
|
8936
8963
|
DISCOVERY_PATTERNS = ["**/*", "**/", "src/**", "lib/**", "app/**", "components/**"]
|
|
8937
8964
|
|
|
@@ -8953,6 +8980,44 @@ def is_discovery_grep(file_path):
|
|
|
8953
8980
|
return True
|
|
8954
8981
|
return False
|
|
8955
8982
|
|
|
8983
|
+
def is_project_indexed(cwd: str) -> tuple[bool, bool]:
|
|
8984
|
+
"""
|
|
8985
|
+
Check if the current directory is in an indexed project.
|
|
8986
|
+
Returns (is_indexed, is_stale).
|
|
8987
|
+
"""
|
|
8988
|
+
if not INDEX_STATUS_FILE.exists():
|
|
8989
|
+
return False, False
|
|
8990
|
+
|
|
8991
|
+
try:
|
|
8992
|
+
with open(INDEX_STATUS_FILE, "r") as f:
|
|
8993
|
+
data = json.load(f)
|
|
8994
|
+
except:
|
|
8995
|
+
return False, False
|
|
8996
|
+
|
|
8997
|
+
projects = data.get("projects", {})
|
|
8998
|
+
cwd_path = Path(cwd).resolve()
|
|
8999
|
+
|
|
9000
|
+
# Check if cwd is within any indexed project
|
|
9001
|
+
for project_path, info in projects.items():
|
|
9002
|
+
try:
|
|
9003
|
+
indexed_path = Path(project_path).resolve()
|
|
9004
|
+
# Check if cwd is the project or a subdirectory
|
|
9005
|
+
if cwd_path == indexed_path or indexed_path in cwd_path.parents:
|
|
9006
|
+
# Check if stale
|
|
9007
|
+
indexed_at = info.get("indexed_at")
|
|
9008
|
+
if indexed_at:
|
|
9009
|
+
try:
|
|
9010
|
+
indexed_time = datetime.fromisoformat(indexed_at.replace("Z", "+00:00"))
|
|
9011
|
+
if datetime.now(indexed_time.tzinfo) - indexed_time > timedelta(days=STALE_THRESHOLD_DAYS):
|
|
9012
|
+
return True, True # Indexed but stale
|
|
9013
|
+
except:
|
|
9014
|
+
pass
|
|
9015
|
+
return True, False # Indexed and fresh
|
|
9016
|
+
except:
|
|
9017
|
+
continue
|
|
9018
|
+
|
|
9019
|
+
return False, False
|
|
9020
|
+
|
|
8956
9021
|
def main():
|
|
8957
9022
|
if not ENABLED:
|
|
8958
9023
|
sys.exit(0)
|
|
@@ -8964,6 +9029,20 @@ def main():
|
|
|
8964
9029
|
|
|
8965
9030
|
tool = data.get("tool_name", "")
|
|
8966
9031
|
inp = data.get("tool_input", {})
|
|
9032
|
+
cwd = data.get("cwd", os.getcwd())
|
|
9033
|
+
|
|
9034
|
+
# Check if project is indexed
|
|
9035
|
+
is_indexed, is_stale = is_project_indexed(cwd)
|
|
9036
|
+
|
|
9037
|
+
if not is_indexed:
|
|
9038
|
+
# Project not indexed - allow local tools but suggest indexing
|
|
9039
|
+
# Don't block, just exit successfully
|
|
9040
|
+
sys.exit(0)
|
|
9041
|
+
|
|
9042
|
+
if is_stale:
|
|
9043
|
+
# Index is stale - allow with warning (printed but not blocking)
|
|
9044
|
+
# Still allow the tool but remind about re-indexing
|
|
9045
|
+
pass # Continue to blocking logic but could add warning
|
|
8967
9046
|
|
|
8968
9047
|
if tool == "Glob":
|
|
8969
9048
|
pattern = inp.get("pattern", "")
|
|
@@ -8971,18 +9050,16 @@ def main():
|
|
|
8971
9050
|
print(f"STOP: Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of Glob.", file=sys.stderr)
|
|
8972
9051
|
sys.exit(2)
|
|
8973
9052
|
|
|
8974
|
-
elif tool == "Grep":
|
|
9053
|
+
elif tool == "Grep" or tool == "Search":
|
|
9054
|
+
# Block ALL Grep/Search operations - use ContextStream search or Read for specific files
|
|
8975
9055
|
pattern = inp.get("pattern", "")
|
|
8976
9056
|
path = inp.get("path", "")
|
|
8977
|
-
if
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
query = inp.get("pattern", "") or inp.get("query", "")
|
|
8984
|
-
if query:
|
|
8985
|
-
print(f"STOP: Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{query}\\") instead of Search.", file=sys.stderr)
|
|
9057
|
+
if pattern:
|
|
9058
|
+
if path and not is_discovery_grep(path):
|
|
9059
|
+
# Specific file - suggest Read instead
|
|
9060
|
+
print(f"STOP: Use Read(\\"{path}\\") to view file content, or mcp__contextstream__search(mode=\\"keyword\\", query=\\"{pattern}\\") for codebase search.", file=sys.stderr)
|
|
9061
|
+
else:
|
|
9062
|
+
print(f"STOP: Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of {tool}.", file=sys.stderr)
|
|
8986
9063
|
sys.exit(2)
|
|
8987
9064
|
|
|
8988
9065
|
elif tool == "Task":
|
|
@@ -9148,6 +9225,97 @@ async function installClaudeCodeHooks(options) {
|
|
|
9148
9225
|
}
|
|
9149
9226
|
return result;
|
|
9150
9227
|
}
|
|
9228
|
+
function getIndexStatusPath() {
|
|
9229
|
+
return path4.join(homedir2(), ".contextstream", "indexed-projects.json");
|
|
9230
|
+
}
|
|
9231
|
+
async function readIndexStatus() {
|
|
9232
|
+
const statusPath = getIndexStatusPath();
|
|
9233
|
+
try {
|
|
9234
|
+
const content = await fs3.readFile(statusPath, "utf-8");
|
|
9235
|
+
return JSON.parse(content);
|
|
9236
|
+
} catch {
|
|
9237
|
+
return { version: 1, projects: {} };
|
|
9238
|
+
}
|
|
9239
|
+
}
|
|
9240
|
+
async function writeIndexStatus(status) {
|
|
9241
|
+
const statusPath = getIndexStatusPath();
|
|
9242
|
+
const dir = path4.dirname(statusPath);
|
|
9243
|
+
await fs3.mkdir(dir, { recursive: true });
|
|
9244
|
+
await fs3.writeFile(statusPath, JSON.stringify(status, null, 2));
|
|
9245
|
+
}
|
|
9246
|
+
async function markProjectIndexed(projectPath, options) {
|
|
9247
|
+
const status = await readIndexStatus();
|
|
9248
|
+
const resolvedPath = path4.resolve(projectPath);
|
|
9249
|
+
status.projects[resolvedPath] = {
|
|
9250
|
+
indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9251
|
+
project_id: options?.project_id,
|
|
9252
|
+
project_name: options?.project_name
|
|
9253
|
+
};
|
|
9254
|
+
await writeIndexStatus(status);
|
|
9255
|
+
}
|
|
9256
|
+
|
|
9257
|
+
// src/token-savings.ts
|
|
9258
|
+
var TOKEN_SAVINGS_FORMULA_VERSION = 1;
|
|
9259
|
+
var MAX_CHARS_PER_EVENT = 2e7;
|
|
9260
|
+
var BASE_OVERHEAD_CHARS = 500;
|
|
9261
|
+
var CANDIDATE_MULTIPLIERS = {
|
|
9262
|
+
// context_smart: Replaces reading multiple files to gather context
|
|
9263
|
+
context_smart: 5,
|
|
9264
|
+
ai_context_budget: 5,
|
|
9265
|
+
// search: Semantic search replaces iterative Glob/Grep/Read cycles
|
|
9266
|
+
search_semantic: 4.5,
|
|
9267
|
+
search_hybrid: 4,
|
|
9268
|
+
search_keyword: 2.5,
|
|
9269
|
+
search_pattern: 3,
|
|
9270
|
+
search_exhaustive: 3.5,
|
|
9271
|
+
search_refactor: 3,
|
|
9272
|
+
// session: Recall/search replaces reading through history
|
|
9273
|
+
session_recall: 5,
|
|
9274
|
+
session_smart_search: 4,
|
|
9275
|
+
session_user_context: 3,
|
|
9276
|
+
session_summary: 4,
|
|
9277
|
+
// graph: Would require extensive file traversal
|
|
9278
|
+
graph_dependencies: 8,
|
|
9279
|
+
graph_impact: 10,
|
|
9280
|
+
graph_call_path: 8,
|
|
9281
|
+
graph_related: 6,
|
|
9282
|
+
// memory: Context retrieval
|
|
9283
|
+
memory_search: 3.5,
|
|
9284
|
+
memory_decisions: 3,
|
|
9285
|
+
memory_timeline: 3,
|
|
9286
|
+
memory_summary: 4
|
|
9287
|
+
};
|
|
9288
|
+
function clampCharCount(value) {
|
|
9289
|
+
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
9290
|
+
return Math.min(MAX_CHARS_PER_EVENT, Math.floor(value));
|
|
9291
|
+
}
|
|
9292
|
+
function trackToolTokenSavings(client, tool, contextText, params, extraMetadata) {
|
|
9293
|
+
try {
|
|
9294
|
+
const contextChars = clampCharCount(contextText.length);
|
|
9295
|
+
const multiplier = CANDIDATE_MULTIPLIERS[tool] ?? 3;
|
|
9296
|
+
const baseOverhead = contextChars > 0 ? BASE_OVERHEAD_CHARS : 0;
|
|
9297
|
+
const estimatedCandidate = Math.round(contextChars * multiplier + baseOverhead);
|
|
9298
|
+
const candidateChars = Math.max(contextChars, clampCharCount(estimatedCandidate));
|
|
9299
|
+
client.trackTokenSavings({
|
|
9300
|
+
tool,
|
|
9301
|
+
workspace_id: params?.workspace_id,
|
|
9302
|
+
project_id: params?.project_id,
|
|
9303
|
+
candidate_chars: candidateChars,
|
|
9304
|
+
context_chars: contextChars,
|
|
9305
|
+
max_tokens: params?.max_tokens,
|
|
9306
|
+
metadata: {
|
|
9307
|
+
method: "multiplier_estimate",
|
|
9308
|
+
formula_version: TOKEN_SAVINGS_FORMULA_VERSION,
|
|
9309
|
+
source: "mcp-server",
|
|
9310
|
+
multiplier,
|
|
9311
|
+
base_overhead_chars: baseOverhead,
|
|
9312
|
+
...extraMetadata ?? {}
|
|
9313
|
+
}
|
|
9314
|
+
}).catch(() => {
|
|
9315
|
+
});
|
|
9316
|
+
} catch {
|
|
9317
|
+
}
|
|
9318
|
+
}
|
|
9151
9319
|
|
|
9152
9320
|
// src/tools.ts
|
|
9153
9321
|
var LESSON_DEDUP_WINDOW_MS = 2 * 60 * 1e3;
|
|
@@ -10501,52 +10669,6 @@ function toStructured(data) {
|
|
|
10501
10669
|
}
|
|
10502
10670
|
return void 0;
|
|
10503
10671
|
}
|
|
10504
|
-
var CANDIDATE_MULTIPLIERS = {
|
|
10505
|
-
// context_smart: Replaces reading multiple files to gather context
|
|
10506
|
-
context_smart: 5,
|
|
10507
|
-
// search: Semantic search replaces iterative Glob/Grep/Read cycles
|
|
10508
|
-
search_semantic: 4.5,
|
|
10509
|
-
search_hybrid: 4,
|
|
10510
|
-
search_keyword: 2.5,
|
|
10511
|
-
search_pattern: 3,
|
|
10512
|
-
search_exhaustive: 3.5,
|
|
10513
|
-
search_refactor: 3,
|
|
10514
|
-
// session: Recall/search replaces reading through history
|
|
10515
|
-
session_recall: 5,
|
|
10516
|
-
session_smart_search: 4,
|
|
10517
|
-
session_user_context: 3,
|
|
10518
|
-
session_summary: 4,
|
|
10519
|
-
// graph: Would require extensive file traversal
|
|
10520
|
-
graph_dependencies: 8,
|
|
10521
|
-
graph_impact: 10,
|
|
10522
|
-
graph_call_path: 8,
|
|
10523
|
-
graph_related: 6,
|
|
10524
|
-
// memory: Context retrieval
|
|
10525
|
-
memory_search: 3.5,
|
|
10526
|
-
memory_decisions: 3,
|
|
10527
|
-
memory_timeline: 3,
|
|
10528
|
-
memory_summary: 4
|
|
10529
|
-
};
|
|
10530
|
-
function trackToolTokenSavings(client, tool, resultContent, params) {
|
|
10531
|
-
try {
|
|
10532
|
-
const contextStr = typeof resultContent === "string" ? resultContent : JSON.stringify(resultContent ?? {});
|
|
10533
|
-
const contextChars = contextStr.length;
|
|
10534
|
-
const multiplier = CANDIDATE_MULTIPLIERS[tool] ?? 3;
|
|
10535
|
-
const baseOverhead = 500;
|
|
10536
|
-
const candidateChars = Math.round(contextChars * multiplier + baseOverhead);
|
|
10537
|
-
client.trackTokenSavings({
|
|
10538
|
-
tool,
|
|
10539
|
-
workspace_id: params?.workspace_id,
|
|
10540
|
-
project_id: params?.project_id,
|
|
10541
|
-
candidate_chars: candidateChars,
|
|
10542
|
-
context_chars: contextChars,
|
|
10543
|
-
max_tokens: params?.max_tokens,
|
|
10544
|
-
metadata: { multiplier, source: "mcp-server" }
|
|
10545
|
-
}).catch(() => {
|
|
10546
|
-
});
|
|
10547
|
-
} catch {
|
|
10548
|
-
}
|
|
10549
|
-
}
|
|
10550
10672
|
function readStatNumber(payload, key) {
|
|
10551
10673
|
if (!payload || typeof payload !== "object") return void 0;
|
|
10552
10674
|
const direct = payload[key];
|
|
@@ -10790,7 +10912,8 @@ function registerTools(server, client, sessionManager) {
|
|
|
10790
10912
|
["graph_call_path", "full"],
|
|
10791
10913
|
["graph_circular_dependencies", "full"],
|
|
10792
10914
|
["graph_unused_code", "full"],
|
|
10793
|
-
["graph_ingest", "
|
|
10915
|
+
["graph_ingest", "lite"],
|
|
10916
|
+
// Pro can ingest (builds module-level graph), Elite gets full graph
|
|
10794
10917
|
["graph_contradictions", "full"]
|
|
10795
10918
|
]);
|
|
10796
10919
|
const graphLiteMaxDepth = 1;
|
|
@@ -11262,6 +11385,12 @@ Hint: Run session_init(folder_path="<your_project_path>") first to establish a s
|
|
|
11262
11385
|
console.error(
|
|
11263
11386
|
`[ContextStream] Completed background ingestion: ${totalIndexed} files in ${batchCount} batches`
|
|
11264
11387
|
);
|
|
11388
|
+
try {
|
|
11389
|
+
await markProjectIndexed(resolvedPath, { project_id: projectId });
|
|
11390
|
+
console.error(`[ContextStream] Marked project as indexed: ${resolvedPath}`);
|
|
11391
|
+
} catch (markError) {
|
|
11392
|
+
console.error(`[ContextStream] Failed to mark project as indexed:`, markError);
|
|
11393
|
+
}
|
|
11265
11394
|
} catch (error) {
|
|
11266
11395
|
console.error(`[ContextStream] Ingestion failed:`, error);
|
|
11267
11396
|
}
|
|
@@ -13007,6 +13136,12 @@ ${benefitsList}` : "",
|
|
|
13007
13136
|
noticeLines.push(
|
|
13008
13137
|
`[INGEST_STATUS] Background indexing started. Codebase will be searchable shortly.`
|
|
13009
13138
|
);
|
|
13139
|
+
} else if (folderPathForRules && !ingestRec?.recommended) {
|
|
13140
|
+
const projectId = typeof result.project_id === "string" ? result.project_id : void 0;
|
|
13141
|
+
const projectName = typeof result.project_name === "string" ? result.project_name : void 0;
|
|
13142
|
+
markProjectIndexed(folderPathForRules, { project_id: projectId, project_name: projectName }).catch(
|
|
13143
|
+
(err) => console.error("[ContextStream] Failed to mark project as indexed:", err)
|
|
13144
|
+
);
|
|
13010
13145
|
}
|
|
13011
13146
|
if (noticeLines.length > 0) {
|
|
13012
13147
|
text = `${text}
|
|
@@ -15274,12 +15409,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15274
15409
|
default:
|
|
15275
15410
|
toolType = "search_hybrid";
|
|
15276
15411
|
}
|
|
15277
|
-
|
|
15412
|
+
const outputText = formatContent(result);
|
|
15413
|
+
trackToolTokenSavings(client, toolType, outputText, {
|
|
15278
15414
|
workspace_id: params.workspace_id,
|
|
15279
15415
|
project_id: params.project_id
|
|
15280
15416
|
});
|
|
15281
15417
|
return {
|
|
15282
|
-
content: [{ type: "text", text:
|
|
15418
|
+
content: [{ type: "text", text: outputText }],
|
|
15283
15419
|
structuredContent: toStructured(result)
|
|
15284
15420
|
};
|
|
15285
15421
|
}
|
|
@@ -15490,12 +15626,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15490
15626
|
include_related: input.include_related,
|
|
15491
15627
|
include_decisions: input.include_decisions
|
|
15492
15628
|
});
|
|
15493
|
-
|
|
15629
|
+
const outputText = formatContent(result);
|
|
15630
|
+
trackToolTokenSavings(client, "session_recall", outputText, {
|
|
15494
15631
|
workspace_id: workspaceId,
|
|
15495
15632
|
project_id: projectId
|
|
15496
15633
|
});
|
|
15497
15634
|
return {
|
|
15498
|
-
content: [{ type: "text", text:
|
|
15635
|
+
content: [{ type: "text", text: outputText }],
|
|
15499
15636
|
structuredContent: toStructured(result)
|
|
15500
15637
|
};
|
|
15501
15638
|
}
|
|
@@ -15517,11 +15654,12 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15517
15654
|
}
|
|
15518
15655
|
case "user_context": {
|
|
15519
15656
|
const result = await client.getUserContext({ workspace_id: workspaceId });
|
|
15520
|
-
|
|
15657
|
+
const outputText = formatContent(result);
|
|
15658
|
+
trackToolTokenSavings(client, "session_user_context", outputText, {
|
|
15521
15659
|
workspace_id: workspaceId
|
|
15522
15660
|
});
|
|
15523
15661
|
return {
|
|
15524
|
-
content: [{ type: "text", text:
|
|
15662
|
+
content: [{ type: "text", text: outputText }],
|
|
15525
15663
|
structuredContent: toStructured(result)
|
|
15526
15664
|
};
|
|
15527
15665
|
}
|
|
@@ -15531,13 +15669,14 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15531
15669
|
project_id: projectId,
|
|
15532
15670
|
max_tokens: input.max_tokens
|
|
15533
15671
|
});
|
|
15534
|
-
|
|
15672
|
+
const outputText = formatContent(result);
|
|
15673
|
+
trackToolTokenSavings(client, "session_summary", outputText, {
|
|
15535
15674
|
workspace_id: workspaceId,
|
|
15536
15675
|
project_id: projectId,
|
|
15537
15676
|
max_tokens: input.max_tokens
|
|
15538
15677
|
});
|
|
15539
15678
|
return {
|
|
15540
|
-
content: [{ type: "text", text:
|
|
15679
|
+
content: [{ type: "text", text: outputText }],
|
|
15541
15680
|
structuredContent: toStructured(result)
|
|
15542
15681
|
};
|
|
15543
15682
|
}
|
|
@@ -15581,12 +15720,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15581
15720
|
include_decisions: input.include_decisions,
|
|
15582
15721
|
include_related: input.include_related
|
|
15583
15722
|
});
|
|
15584
|
-
|
|
15723
|
+
const outputText = formatContent(result);
|
|
15724
|
+
trackToolTokenSavings(client, "session_smart_search", outputText, {
|
|
15585
15725
|
workspace_id: workspaceId,
|
|
15586
15726
|
project_id: projectId
|
|
15587
15727
|
});
|
|
15588
15728
|
return {
|
|
15589
|
-
content: [{ type: "text", text:
|
|
15729
|
+
content: [{ type: "text", text: outputText }],
|
|
15590
15730
|
structuredContent: toStructured(result)
|
|
15591
15731
|
};
|
|
15592
15732
|
}
|
|
@@ -15933,12 +16073,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15933
16073
|
query: input.query,
|
|
15934
16074
|
limit: input.limit
|
|
15935
16075
|
});
|
|
15936
|
-
|
|
16076
|
+
const outputText = formatContent(result);
|
|
16077
|
+
trackToolTokenSavings(client, "memory_search", outputText, {
|
|
15937
16078
|
workspace_id: workspaceId,
|
|
15938
16079
|
project_id: projectId
|
|
15939
16080
|
});
|
|
15940
16081
|
return {
|
|
15941
|
-
content: [{ type: "text", text:
|
|
16082
|
+
content: [{ type: "text", text: outputText }],
|
|
15942
16083
|
structuredContent: toStructured(result)
|
|
15943
16084
|
};
|
|
15944
16085
|
}
|
|
@@ -15949,12 +16090,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15949
16090
|
category: input.category,
|
|
15950
16091
|
limit: input.limit
|
|
15951
16092
|
});
|
|
15952
|
-
|
|
16093
|
+
const outputText = formatContent(result);
|
|
16094
|
+
trackToolTokenSavings(client, "memory_decisions", outputText, {
|
|
15953
16095
|
workspace_id: workspaceId,
|
|
15954
16096
|
project_id: projectId
|
|
15955
16097
|
});
|
|
15956
16098
|
return {
|
|
15957
|
-
content: [{ type: "text", text:
|
|
16099
|
+
content: [{ type: "text", text: outputText }],
|
|
15958
16100
|
structuredContent: toStructured(result)
|
|
15959
16101
|
};
|
|
15960
16102
|
}
|
|
@@ -15963,11 +16105,12 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15963
16105
|
return errorResult("timeline requires workspace_id. Call session_init first.");
|
|
15964
16106
|
}
|
|
15965
16107
|
const result = await client.memoryTimeline(workspaceId);
|
|
15966
|
-
|
|
16108
|
+
const outputText = formatContent(result);
|
|
16109
|
+
trackToolTokenSavings(client, "memory_timeline", outputText, {
|
|
15967
16110
|
workspace_id: workspaceId
|
|
15968
16111
|
});
|
|
15969
16112
|
return {
|
|
15970
|
-
content: [{ type: "text", text:
|
|
16113
|
+
content: [{ type: "text", text: outputText }],
|
|
15971
16114
|
structuredContent: toStructured(result)
|
|
15972
16115
|
};
|
|
15973
16116
|
}
|
|
@@ -15976,11 +16119,12 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
15976
16119
|
return errorResult("summary requires workspace_id. Call session_init first.");
|
|
15977
16120
|
}
|
|
15978
16121
|
const result = await client.memorySummary(workspaceId);
|
|
15979
|
-
|
|
16122
|
+
const outputText = formatContent(result);
|
|
16123
|
+
trackToolTokenSavings(client, "memory_summary", outputText, {
|
|
15980
16124
|
workspace_id: workspaceId
|
|
15981
16125
|
});
|
|
15982
16126
|
return {
|
|
15983
|
-
content: [{ type: "text", text:
|
|
16127
|
+
content: [{ type: "text", text: outputText }],
|
|
15984
16128
|
structuredContent: toStructured(result)
|
|
15985
16129
|
};
|
|
15986
16130
|
}
|
|
@@ -16165,12 +16309,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
16165
16309
|
max_depth: input.max_depth,
|
|
16166
16310
|
include_transitive: input.include_transitive
|
|
16167
16311
|
});
|
|
16168
|
-
|
|
16312
|
+
const outputText = formatContent(result);
|
|
16313
|
+
trackToolTokenSavings(client, "graph_dependencies", outputText, {
|
|
16169
16314
|
workspace_id: workspaceId,
|
|
16170
16315
|
project_id: projectId
|
|
16171
16316
|
});
|
|
16172
16317
|
return {
|
|
16173
|
-
content: [{ type: "text", text:
|
|
16318
|
+
content: [{ type: "text", text: outputText }],
|
|
16174
16319
|
structuredContent: toStructured(result)
|
|
16175
16320
|
};
|
|
16176
16321
|
}
|
|
@@ -16182,12 +16327,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
16182
16327
|
target: input.target,
|
|
16183
16328
|
max_depth: input.max_depth
|
|
16184
16329
|
});
|
|
16185
|
-
|
|
16330
|
+
const outputText = formatContent(result);
|
|
16331
|
+
trackToolTokenSavings(client, "graph_impact", outputText, {
|
|
16186
16332
|
workspace_id: workspaceId,
|
|
16187
16333
|
project_id: projectId
|
|
16188
16334
|
});
|
|
16189
16335
|
return {
|
|
16190
|
-
content: [{ type: "text", text:
|
|
16336
|
+
content: [{ type: "text", text: outputText }],
|
|
16191
16337
|
structuredContent: toStructured(result)
|
|
16192
16338
|
};
|
|
16193
16339
|
}
|
|
@@ -16200,12 +16346,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
16200
16346
|
target: input.target,
|
|
16201
16347
|
max_depth: input.max_depth
|
|
16202
16348
|
});
|
|
16203
|
-
|
|
16349
|
+
const outputText = formatContent(result);
|
|
16350
|
+
trackToolTokenSavings(client, "graph_call_path", outputText, {
|
|
16204
16351
|
workspace_id: workspaceId,
|
|
16205
16352
|
project_id: projectId
|
|
16206
16353
|
});
|
|
16207
16354
|
return {
|
|
16208
|
-
content: [{ type: "text", text:
|
|
16355
|
+
content: [{ type: "text", text: outputText }],
|
|
16209
16356
|
structuredContent: toStructured(result)
|
|
16210
16357
|
};
|
|
16211
16358
|
}
|
|
@@ -16219,12 +16366,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
16219
16366
|
project_id: projectId,
|
|
16220
16367
|
limit: input.limit
|
|
16221
16368
|
});
|
|
16222
|
-
|
|
16369
|
+
const outputText = formatContent(result);
|
|
16370
|
+
trackToolTokenSavings(client, "graph_related", outputText, {
|
|
16223
16371
|
workspace_id: workspaceId,
|
|
16224
16372
|
project_id: projectId
|
|
16225
16373
|
});
|
|
16226
16374
|
return {
|
|
16227
|
-
content: [{ type: "text", text:
|
|
16375
|
+
content: [{ type: "text", text: outputText }],
|
|
16228
16376
|
structuredContent: toStructured(result)
|
|
16229
16377
|
};
|
|
16230
16378
|
}
|
|
@@ -16688,7 +16836,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
16688
16836
|
"integration",
|
|
16689
16837
|
{
|
|
16690
16838
|
title: "Integration",
|
|
16691
|
-
description: `Integration operations for Slack, GitHub, and Notion. Provider: slack, github, notion, all. Actions: status, search, stats, activity, contributors, knowledge, summary, channels (slack), discussions (slack), repos (github), issues (github), create_page (notion), list_databases (notion), search_pages (notion with smart type detection - filter by event_type, status, priority, has_due_date, tags), get_page (notion), query_database (notion), update_page (notion).`,
|
|
16839
|
+
description: `Integration operations for Slack, GitHub, and Notion. Provider: slack, github, notion, all. Actions: status, search, stats, activity, contributors, knowledge, summary, channels (slack), discussions (slack), repos (github), issues (github), create_page (notion), create_database (notion), list_databases (notion), search_pages (notion with smart type detection - filter by event_type, status, priority, has_due_date, tags), get_page (notion), query_database (notion), update_page (notion).`,
|
|
16692
16840
|
inputSchema: external_exports.object({
|
|
16693
16841
|
provider: external_exports.enum(["slack", "github", "notion", "all"]).describe("Integration provider"),
|
|
16694
16842
|
action: external_exports.enum([
|
|
@@ -16706,6 +16854,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
16706
16854
|
"issues",
|
|
16707
16855
|
// Notion-specific actions
|
|
16708
16856
|
"create_page",
|
|
16857
|
+
"create_database",
|
|
16709
16858
|
"list_databases",
|
|
16710
16859
|
"search_pages",
|
|
16711
16860
|
"get_page",
|
|
@@ -16719,10 +16868,11 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
16719
16868
|
since: external_exports.string().optional(),
|
|
16720
16869
|
until: external_exports.string().optional(),
|
|
16721
16870
|
// Notion-specific parameters
|
|
16722
|
-
title: external_exports.string().optional().describe("Page title (for Notion create_page/update_page)"),
|
|
16871
|
+
title: external_exports.string().optional().describe("Page/database title (for Notion create_page/update_page/create_database)"),
|
|
16723
16872
|
content: external_exports.string().optional().describe("Page content in Markdown (for Notion create_page/update_page)"),
|
|
16873
|
+
description: external_exports.string().optional().describe("Database description (for Notion create_database)"),
|
|
16724
16874
|
parent_database_id: external_exports.string().optional().describe("Parent database ID (for Notion create_page)"),
|
|
16725
|
-
parent_page_id: external_exports.string().optional().describe("Parent page ID (for Notion create_page)"),
|
|
16875
|
+
parent_page_id: external_exports.string().optional().describe("Parent page ID (for Notion create_page/create_database)"),
|
|
16726
16876
|
page_id: external_exports.string().optional().describe("Page ID (for Notion get_page/update_page)"),
|
|
16727
16877
|
database_id: external_exports.string().optional().describe("Database ID (for Notion query_database/search_pages/activity)"),
|
|
16728
16878
|
days: external_exports.number().optional().describe("Number of days for stats/summary (default: 7)"),
|
|
@@ -17014,6 +17164,39 @@ Created: ${result.created_time}`
|
|
|
17014
17164
|
structuredContent: toStructured(result)
|
|
17015
17165
|
};
|
|
17016
17166
|
}
|
|
17167
|
+
case "create_database": {
|
|
17168
|
+
if (input.provider !== "notion") {
|
|
17169
|
+
return errorResult("create_database is only available for notion provider");
|
|
17170
|
+
}
|
|
17171
|
+
if (!input.title) {
|
|
17172
|
+
return errorResult("title is required for create_database action");
|
|
17173
|
+
}
|
|
17174
|
+
if (!input.parent_page_id) {
|
|
17175
|
+
return errorResult("parent_page_id is required for create_database action");
|
|
17176
|
+
}
|
|
17177
|
+
if (!workspaceId) {
|
|
17178
|
+
return errorResult(
|
|
17179
|
+
"Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly."
|
|
17180
|
+
);
|
|
17181
|
+
}
|
|
17182
|
+
const newDatabase = await client.notionCreateDatabase({
|
|
17183
|
+
workspace_id: workspaceId,
|
|
17184
|
+
title: input.title,
|
|
17185
|
+
parent_page_id: input.parent_page_id,
|
|
17186
|
+
description: input.description
|
|
17187
|
+
});
|
|
17188
|
+
return {
|
|
17189
|
+
content: [
|
|
17190
|
+
{
|
|
17191
|
+
type: "text",
|
|
17192
|
+
text: `Created database "${newDatabase.title}"
|
|
17193
|
+
ID: ${newDatabase.id}
|
|
17194
|
+
URL: ${newDatabase.url}`
|
|
17195
|
+
}
|
|
17196
|
+
],
|
|
17197
|
+
structuredContent: toStructured(newDatabase)
|
|
17198
|
+
};
|
|
17199
|
+
}
|
|
17017
17200
|
case "list_databases": {
|
|
17018
17201
|
if (input.provider !== "notion") {
|
|
17019
17202
|
return errorResult("list_databases is only available for notion provider");
|
|
@@ -19569,10 +19752,10 @@ Code: ${device.user_code}`);
|
|
|
19569
19752
|
if (poll && poll.status === "pending") {
|
|
19570
19753
|
const intervalSeconds = typeof poll.interval === "number" ? poll.interval : 5;
|
|
19571
19754
|
const waitMs = Math.max(1, intervalSeconds) * 1e3;
|
|
19572
|
-
await new Promise((
|
|
19755
|
+
await new Promise((resolve4) => setTimeout(resolve4, waitMs));
|
|
19573
19756
|
continue;
|
|
19574
19757
|
}
|
|
19575
|
-
await new Promise((
|
|
19758
|
+
await new Promise((resolve4) => setTimeout(resolve4, 1e3));
|
|
19576
19759
|
}
|
|
19577
19760
|
if (!accessToken) {
|
|
19578
19761
|
throw new Error(
|
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.36",
|
|
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",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"test-server": "tsx src/test-server.ts",
|
|
21
21
|
"test-server:start": "node dist/test-server.js",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
|
23
|
-
"test": "vitest run",
|
|
24
|
-
"test:watch": "vitest",
|
|
23
|
+
"test": "vitest run --config vitest.config.cjs",
|
|
24
|
+
"test:watch": "vitest --config vitest.config.cjs",
|
|
25
25
|
"lint": "eslint src/",
|
|
26
26
|
"lint:fix": "eslint src/ --fix",
|
|
27
27
|
"format": "prettier --write src/",
|