🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@contextstream/mcp-server

Package Overview
Dependencies
Maintainers
1
Versions
148
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@contextstream/mcp-server - npm Package Compare versions

Comparing version
0.4.74
to
0.4.80
+45
scripts/registration-smoke.mts
process.env.CONTEXTSTREAM_API_KEY ||= "cs_test_dummy";
process.env.CONTEXTSTREAM_API_URL ||= "https://api.contextstream.io";
process.env.CONTEXTSTREAM_LOG_LEVEL = "quiet";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const { loadConfig } = await import("../src/config.js");
const { ContextStreamClient } = await import("../src/client.js");
const { registerTools } = await import("../src/tools.js");
const { SessionManager } = await import("../src/session-manager.js");
const config = loadConfig();
const client = new ContextStreamClient(config);
const server = new McpServer({ name: "smoke", version: "0.0.0" });
const sessionManager = new SessionManager(server, client);
registerTools(server, client, sessionManager, { toolSurfaceProfile: config.toolSurfaceProfile });
const registered = (server as any)._registeredTools;
const names = registered ? Object.keys(registered).sort() : [];
console.log(`TOOL_COUNT=${names.length}`);
console.log(names.join("\n"));
const mustHave = [
"qa",
"capture_plan",
"session_capture",
"session_capture_lesson",
"session_remember",
"memory_create_doc",
"memory_update_doc",
"memory_delete_doc",
"memory_create_task",
"memory_update_task",
"memory_create_todo",
"memory_complete_todo",
"memory_create_event",
];
const mustNotHave = ["ram", "mem", "chart", "async_job", "atlas_chart", "atlas_job"];
const missing = mustHave.filter((n) => !names.includes(n));
const forbidden = mustNotHave.filter((n) => names.includes(n));
if (missing.length || forbidden.length) {
console.error(`SMOKE_FAIL missing=[${missing.join(",")}] forbidden=[${forbidden.join(",")}]`);
process.exit(1);
}
console.log("SMOKE_PASS");
+8
-83

@@ -154,40 +154,2 @@ #!/usr/bin/env node

}
function startIndexWaitWindow(cwd, waitSeconds) {
if (!cwd.trim() || waitSeconds <= 0) return;
const state = readState();
const target = getOrCreateEntry(state, cwd);
if (!target) return;
const now = Date.now();
const existingUntil = target.entry.index_wait_until ? new Date(target.entry.index_wait_until).getTime() : NaN;
if (!Number.isNaN(existingUntil) && existingUntil > now) {
target.entry.updated_at = nowIso();
writeState(state);
return;
}
target.entry.index_wait_started_at = new Date(now).toISOString();
target.entry.index_wait_until = new Date(now + waitSeconds * 1e3).toISOString();
target.entry.updated_at = nowIso();
writeState(state);
}
function clearIndexWaitWindow(cwd) {
if (!cwd.trim()) return;
const state = readState();
const target = getOrCreateEntry(state, cwd);
if (!target) return;
target.entry.index_wait_started_at = void 0;
target.entry.index_wait_until = void 0;
target.entry.updated_at = nowIso();
writeState(state);
}
function indexWaitRemainingSeconds(cwd) {
if (!cwd.trim()) return null;
const state = readState();
const target = getOrCreateEntry(state, cwd);
if (!target?.entry.index_wait_until) return null;
const until = new Date(target.entry.index_wait_until).getTime();
if (Number.isNaN(until)) return null;
const remainingMs = until - Date.now();
if (remainingMs <= 0) return null;
return Math.ceil(remainingMs / 1e3);
}

@@ -200,5 +162,2 @@ // src/hooks/pre-tool-use.ts

var CONTEXT_FRESHNESS_SECONDS = 120;
var DEFAULT_INDEX_WAIT_SECONDS = 20;
var MIN_INDEX_WAIT_SECONDS = 15;
var MAX_INDEX_WAIT_SECONDS = 20;
var DISCOVERY_PATTERNS = ["**/*", "**/", "src/**", "lib/**", "app/**", "components/**"];

@@ -229,29 +188,2 @@ function isDiscoveryGlob(pattern) {

}
function configuredIndexWaitSeconds() {
const parsed = Number.parseInt(process.env.CONTEXTSTREAM_INDEX_WAIT_SECONDS ?? "", 10);
if (Number.isNaN(parsed)) return DEFAULT_INDEX_WAIT_SECONDS;
return Math.min(MAX_INDEX_WAIT_SECONDS, Math.max(MIN_INDEX_WAIT_SECONDS, parsed));
}
function isLocalDiscoveryToolDuringIndexWait(tool, toolInput) {
if (tool === "Glob" || tool === "Explore" || tool === "SemanticSearch" || tool === "codebase_search") {
return true;
}
if (tool === "Task") {
const subagentTypeRaw = toolInput?.subagent_type || toolInput?.subagentType || "";
return subagentTypeRaw.toLowerCase().includes("explore");
}
if (tool === "Grep" || tool === "Search" || tool === "grep_search" || tool === "code_search") {
const filePath = toolInput?.path || "";
return isDiscoveryGrep(filePath);
}
if (tool === "Read" || tool === "ReadFile" || tool === "read_file") {
const filePath = toolInput?.file_path || toolInput?.path || toolInput?.file || toolInput?.target_file || "";
return isDiscoveryGrep(filePath);
}
if (tool === "list_files" || tool === "search_files" || tool === "search_files_content" || tool === "find_files" || tool === "find_by_name") {
const pattern = toolInput?.path || toolInput?.regex || toolInput?.pattern || toolInput?.query || "";
return !pattern || isDiscoveryGlob(pattern) || isDiscoveryGrep(pattern);
}
return false;
}
function isProjectIndexed(cwd) {

@@ -426,7 +358,9 @@ if (!fs2.existsSync(INDEX_STATUS_FILE)) {

function outputCursorBlock(reason) {
console.log(JSON.stringify({ decision: "deny", reason }));
console.log(
JSON.stringify({ permission: "deny", agent_message: reason, user_message: reason })
);
process.exit(0);
}
function outputCursorAllow() {
console.log(JSON.stringify({ decision: "allow" }));
console.log(JSON.stringify({ permission: "allow" }));
process.exit(0);

@@ -454,2 +388,5 @@ }

function detectEditorFormat(input) {
if (process.argv.includes("--editor=cursor")) {
return "cursor";
}
if (input.hookName !== void 0 || input.toolName !== void 0) {

@@ -523,15 +460,3 @@ return "cline";

`);
if (isIndexed && !isStale) {
clearIndexWaitWindow(cwd);
} else {
const waitSeconds = configuredIndexWaitSeconds();
if (isLocalDiscoveryToolDuringIndexWait(tool, toolInput)) {
startIndexWaitWindow(cwd, waitSeconds);
const remaining = indexWaitRemainingSeconds(cwd);
if (remaining && remaining > 0) {
const msg = `Index refresh grace window is active (${remaining}s remaining). Keep ContextStream search-first flow: mcp__contextstream__search(mode="auto", query="..."). Do not use local discovery tools yet for stale/not-indexed projects. Retry after refresh; local fallback is allowed only after ~${waitSeconds}s if index is still unavailable.`;
blockWithMessage(editorFormat, msg);
}
allowTool(editorFormat, cwd, recordStateChange);
}
if (!isIndexed || isStale) {
allowTool(editorFormat, cwd, recordStateChange);

@@ -538,0 +463,0 @@ }

@@ -301,10 +301,9 @@ #!/usr/bin/env node

2. FOR CODE SEARCH: Check index status, then search appropriately
\u26A0\uFE0F BEFORE searching: mcp__contextstream__project(action="index_status")
\u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="auto", query="...") BEFORE Glob/Grep/Read/Explore/Task/EnterPlanMode
\u2705 IF NOT indexed OR stale: wait for background refresh up to ~20s, retry mcp__contextstream__search(mode="auto", query="..."), then allow local tools only after the grace window
\u2705 IF search still returns 0 results after retry/window: fallback to local tools (Glob/Grep/Read)
\u2705 Use mcp__contextstream__search(mode="auto", query="...") BEFORE Glob/Grep/Read/Explore/Task/EnterPlanMode
\u2705 Run search even while the index is still building \u2014 keyword hits return immediately, results fill in as you work
\u2705 IF search itself returns 0 results/errors: retry once, THEN fall back to local tools (Glob/Grep/Read)
3. WHEN LOCAL TOOLS (Glob/Grep/Read) ARE OK:
\u2705 Stale/not-indexed grace window has elapsed (~20s default, configurable)
\u2705 ContextStream search still returns 0 results or errors after retry
\u2705 The file was just written this turn (known-new, not yet indexed)
\u2705 User explicitly requests local tools

@@ -732,4 +731,4 @@

**IF indexed=false OR last_indexed_at is stale (>7 days):**
\u2192 Wait up to ~20s for background refresh, retry \`search(mode="auto", query="...")\`
\u2192 After grace window: local tools are allowed if search still misses
\u2192 Run \`search(mode="auto", query="...")\` anyway \u2014 keyword hits return immediately while indexing builds
\u2192 Local tools only if search itself returns 0 results/errors on a retry

@@ -736,0 +735,0 @@ **IF search still returns 0 results or errors after retry/window:**

{
"name": "@contextstream/mcp-server",
"mcpName": "io.github.contextstreamio/mcp-server",
"version": "0.4.74",
"description": "ContextStream MCP server - v0.4.x with consolidated domain tools (~11 tools, ~75% token reduction). Code context, memory, search, and AI tools.",
"version": "0.4.80",
"description": "ContextStream MCP server - v0.4.x with consolidated domain tools plus per-action write surfaces (~75% token reduction vs individual tools). Code context, memory, search, Q&A, and AI tools.",
"type": "module",

@@ -52,3 +52,3 @@ "license": "MIT",

"typescript-eslint": "^8.52.0",
"vitest": "^4.0.16"
"vitest": "^4.1.9"
},

@@ -55,0 +55,0 @@ "engines": {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display