@contextstream/mcp-server 0.3.22 → 0.3.24

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.
Files changed (2) hide show
  1. package/dist/index.js +95 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4629,6 +4629,14 @@ var globalCache = new MemoryCache();
4629
4629
 
4630
4630
  // src/client.ts
4631
4631
  var uuidSchema = external_exports.string().uuid();
4632
+ function unwrapApiResponse(result) {
4633
+ if (!result || typeof result !== "object") return result;
4634
+ const maybe = result;
4635
+ if (typeof maybe.success === "boolean" && "data" in maybe) {
4636
+ return maybe.data;
4637
+ }
4638
+ return result;
4639
+ }
4632
4640
  var ContextStreamClient = class {
4633
4641
  constructor(config) {
4634
4642
  this.config = config;
@@ -4696,8 +4704,9 @@ var ContextStreamClient = class {
4696
4704
  const suffix = query.toString() ? `?${query.toString()}` : "";
4697
4705
  return request(this.config, `/workspaces${suffix}`);
4698
4706
  }
4699
- createWorkspace(input) {
4700
- return request(this.config, "/workspaces", { body: input });
4707
+ async createWorkspace(input) {
4708
+ const result = await request(this.config, "/workspaces", { body: input });
4709
+ return unwrapApiResponse(result);
4701
4710
  }
4702
4711
  updateWorkspace(workspaceId, input) {
4703
4712
  uuidSchema.parse(workspaceId);
@@ -4716,9 +4725,10 @@ var ContextStreamClient = class {
4716
4725
  const suffix = query.toString() ? `?${query.toString()}` : "";
4717
4726
  return request(this.config, `/projects${suffix}`);
4718
4727
  }
4719
- createProject(input) {
4728
+ async createProject(input) {
4720
4729
  const payload = this.withDefaults(input);
4721
- return request(this.config, "/projects", { body: payload });
4730
+ const result = await request(this.config, "/projects", { body: payload });
4731
+ return unwrapApiResponse(result);
4722
4732
  }
4723
4733
  updateProject(projectId, input) {
4724
4734
  uuidSchema.parse(projectId);
@@ -5102,6 +5112,38 @@ var ContextStreamClient = class {
5102
5112
  context.workspace_error = String(e);
5103
5113
  }
5104
5114
  }
5115
+ if (!workspaceId && !params.allow_no_workspace) {
5116
+ const folderDisplayName = rootPath?.split("/").pop() || "this folder";
5117
+ context.ide_roots = ideRoots;
5118
+ context.folder_name = folderDisplayName;
5119
+ if (rootPath) {
5120
+ context.folder_path = rootPath;
5121
+ }
5122
+ context.suggested_project_name = folderDisplayName;
5123
+ try {
5124
+ const workspaces = await this.listWorkspaces({ page_size: 50 });
5125
+ const items = Array.isArray(workspaces.items) ? workspaces.items : [];
5126
+ if (items.length > 0) {
5127
+ context.status = "requires_workspace_selection";
5128
+ context.workspace_candidates = items.map((w) => ({
5129
+ id: w.id,
5130
+ name: w.name,
5131
+ description: w.description
5132
+ }));
5133
+ context.message = `This folder is not associated with a workspace yet. Please select which workspace to use, or create a new one.`;
5134
+ return context;
5135
+ }
5136
+ context.status = "requires_workspace_name";
5137
+ context.workspace_source = "none_found";
5138
+ context.message = `No workspaces found for this account. Ask the user for a name for a new workspace, then create a project for "${folderDisplayName}".`;
5139
+ return context;
5140
+ } catch (e) {
5141
+ context.status = "requires_workspace_selection";
5142
+ context.workspace_error = String(e);
5143
+ context.message = `Unable to resolve a workspace automatically (${String(e)}). Please provide workspace_id, or create one with workspace_bootstrap.`;
5144
+ return context;
5145
+ }
5146
+ }
5105
5147
  if (!projectId && workspaceId && rootPath && params.auto_index !== false) {
5106
5148
  const projectName = rootPath.split("/").pop() || "My Project";
5107
5149
  try {
@@ -5171,6 +5213,9 @@ var ContextStreamClient = class {
5171
5213
  context.workspace_name = workspaceName;
5172
5214
  context.project_id = projectId;
5173
5215
  context.ide_roots = ideRoots;
5216
+ if (!workspaceId) {
5217
+ context.workspace_warning = "No workspace was resolved for this session. Workspace-level tools (memory/search/graph) may not work until you associate this folder with a workspace.";
5218
+ }
5174
5219
  if (workspaceId) {
5175
5220
  try {
5176
5221
  const batchedContext = await this._fetchSessionContextBatched({
@@ -6548,8 +6593,11 @@ Access: ${accessLabel}${accessLabel === "PRO" ? ` (upgrade: ${upgradeUrl2})` : "
6548
6593
  const errorMessage = error?.message || String(error);
6549
6594
  const errorDetails = error?.body || error?.details || null;
6550
6595
  const errorCode = error?.code || error?.status || "UNKNOWN_ERROR";
6596
+ const isPlanLimit = String(errorCode).toUpperCase() === "FORBIDDEN" && String(errorMessage).toLowerCase().includes("plan limit reached");
6597
+ const upgradeHint = isPlanLimit ? `
6598
+ Upgrade: ${upgradeUrl2}` : "";
6551
6599
  const serializedError = new Error(
6552
- `[${errorCode}] ${errorMessage}${errorDetails ? `: ${JSON.stringify(errorDetails)}` : ""}`
6600
+ `[${errorCode}] ${errorMessage}${upgradeHint}${errorDetails ? `: ${JSON.stringify(errorDetails)}` : ""}`
6553
6601
  );
6554
6602
  throw serializedError;
6555
6603
  }
@@ -7482,7 +7530,8 @@ This does semantic search on the first message. You only need context_smart on s
7482
7530
  context_hint: external_exports.string().optional().describe("RECOMMENDED: Pass the user's first message here for semantic search. This finds relevant context from ANY time, not just recent items."),
7483
7531
  include_recent_memory: external_exports.boolean().optional().describe("Include recent memory events (default: true)"),
7484
7532
  include_decisions: external_exports.boolean().optional().describe("Include recent decisions (default: true)"),
7485
- auto_index: external_exports.boolean().optional().describe("Automatically create and index project from IDE workspace (default: true)")
7533
+ auto_index: external_exports.boolean().optional().describe("Automatically create and index project from IDE workspace (default: true)"),
7534
+ allow_no_workspace: external_exports.boolean().optional().describe("If true, allow session_init to return connected even if no workspace is resolved (workspace-level tools may not work).")
7486
7535
  })
7487
7536
  },
7488
7537
  async (input) => {
@@ -7501,7 +7550,46 @@ This does semantic search on the first message. You only need context_smart on s
7501
7550
  if (sessionManager) {
7502
7551
  sessionManager.markInitialized(result);
7503
7552
  }
7504
- return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7553
+ const status = typeof result.status === "string" ? result.status : "";
7554
+ const workspaceWarning = typeof result.workspace_warning === "string" ? result.workspace_warning : "";
7555
+ let text = formatContent(result);
7556
+ if (status === "requires_workspace_name") {
7557
+ const folderPath = typeof result.folder_path === "string" ? result.folder_path : typeof input.folder_path === "string" ? input.folder_path : "";
7558
+ text = [
7559
+ "Action required: no workspaces found for this account.",
7560
+ "Ask the user for a name for the new workspace, then run `workspace_bootstrap`.",
7561
+ folderPath ? `Recommended: workspace_bootstrap(workspace_name: "<name>", folder_path: "${folderPath}")` : 'Recommended: workspace_bootstrap(workspace_name: "<name>", folder_path: "<your repo folder>")',
7562
+ "",
7563
+ "--- Raw Response ---",
7564
+ "",
7565
+ formatContent(result)
7566
+ ].join("\n");
7567
+ } else if (status === "requires_workspace_selection") {
7568
+ const folderName = typeof result.folder_name === "string" ? result.folder_name : typeof input.folder_path === "string" ? input.folder_path.split("/").pop() || "this folder" : "this folder";
7569
+ const candidates = Array.isArray(result.workspace_candidates) ? result.workspace_candidates : [];
7570
+ const lines = [];
7571
+ lines.push(`Action required: select a workspace for "${folderName}" (or create a new one).`);
7572
+ if (candidates.length > 0) {
7573
+ lines.push("");
7574
+ lines.push("Available workspaces:");
7575
+ candidates.slice(0, 25).forEach((w, i) => {
7576
+ const name = w.name || "Untitled";
7577
+ const id = w.id ? ` (${w.id})` : "";
7578
+ const desc = w.description ? ` - ${w.description}` : "";
7579
+ lines.push(` ${i + 1}. ${name}${id}${desc}`);
7580
+ });
7581
+ }
7582
+ lines.push("");
7583
+ lines.push("Then run `workspace_associate` with the selected workspace_id and your folder_path.");
7584
+ lines.push("");
7585
+ lines.push("--- Raw Response ---");
7586
+ lines.push("");
7587
+ lines.push(formatContent(result));
7588
+ text = lines.join("\n");
7589
+ } else if (workspaceWarning) {
7590
+ text = [`Warning: ${workspaceWarning}`, "", formatContent(result)].join("\n");
7591
+ }
7592
+ return { content: [{ type: "text", text }], structuredContent: toStructured(result) };
7505
7593
  }
7506
7594
  );
7507
7595
  registerTool(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contextstream/mcp-server",
3
- "version": "0.3.22",
3
+ "version": "0.3.24",
4
4
  "description": "MCP server exposing ContextStream public API - code context, memory, search, and AI tools for developers",
5
5
  "type": "module",
6
6
  "license": "MIT",