@intangle/mcp-server 2.5.1 → 2.5.3

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/README.md CHANGED
@@ -20,6 +20,12 @@ Claude code by running the command below (recommend "-s" user for global across
20
20
  claude mcp add intangle -s user --env MCP_API_KEY=<your-api-key-here> --env NEXT_APP_URL=https://intangle.app -- npx -y @intangle/mcp-server
21
21
  ```
22
22
 
23
+ If your deployment is behind Vercel Deployment Protection (for example staging), add:
24
+
25
+ ```bash
26
+ --env VERCEL_BYPASS_TOKEN=<your-vercel-bypass-token>
27
+ ```
28
+
23
29
  Standard MCP (Claude desktop, Cursor): by adding to your `claude_desktop_config.json` or `mcp.json`:
24
30
 
25
31
  ```json
@@ -30,7 +36,8 @@ Standard MCP (Claude desktop, Cursor): by adding to your `claude_desktop_config.
30
36
  "args": ["@intangle/mcp-server"],
31
37
  "env": {
32
38
  "MCP_API_KEY": "your-api-key-here",
33
- "NEXT_APP_URL": "https://intangle.app"
39
+ "NEXT_APP_URL": "https://intangle.app",
40
+ "VERCEL_BYPASS_TOKEN": "optional-vercel-bypass-token-for-protected-deployments"
34
41
  }
35
42
  }
36
43
  }
@@ -91,4 +98,4 @@ If Claude can't access your context:
91
98
 
92
99
  ## License
93
100
 
94
- MIT
101
+ MIT
package/dist/index.js CHANGED
@@ -32,8 +32,10 @@ try {
32
32
  // Base URL for API calls to Next.js app
33
33
  const API_BASE_URL = process.env.NEXT_APP_URL || "https://intangle.app";
34
34
  const MCP_API_KEY = process.env.MCP_API_KEY;
35
+ const VERCEL_BYPASS_TOKEN = process.env.VERCEL_BYPASS_TOKEN || process.env.VERCEL_PROTECTION_BYPASS;
35
36
  log(`CWD: ${process.cwd()}`);
36
37
  log(`Has API Key: ${!!MCP_API_KEY}`);
38
+ log(`Has Vercel Bypass Token: ${!!VERCEL_BYPASS_TOKEN}`);
37
39
  log(`Node Version: ${process.version}`);
38
40
  if (!MCP_API_KEY) {
39
41
  log("Error: MCP_API_KEY environment variable is required");
@@ -92,6 +94,13 @@ try {
92
94
  }
93
95
  // Default timeout for API calls (90 seconds)
94
96
  const API_TIMEOUT_MS = 90_000;
97
+ function buildApiUrl(endpoint) {
98
+ const url = new URL(`/api/mcp/${endpoint}`, API_BASE_URL);
99
+ if (VERCEL_BYPASS_TOKEN) {
100
+ url.searchParams.set("x-vercel-protection-bypass", VERCEL_BYPASS_TOKEN);
101
+ }
102
+ return url.toString();
103
+ }
95
104
  async function makeApiCall(endpoint, data, timeoutMs) {
96
105
  // Ensure we have client info before making requests
97
106
  ensureClientInfo();
@@ -110,21 +119,36 @@ try {
110
119
  if (mcpClientVersion) {
111
120
  headers["X-MCP-Client-Version"] = mcpClientVersion;
112
121
  }
122
+ if (VERCEL_BYPASS_TOKEN) {
123
+ headers["x-vercel-protection-bypass"] = VERCEL_BYPASS_TOKEN;
124
+ }
113
125
  // Apply timeout to prevent hanging requests
114
126
  const controller = new AbortController();
115
127
  const effectiveTimeout = timeoutMs || API_TIMEOUT_MS;
116
128
  const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
117
129
  try {
118
- const response = await fetch(`${API_BASE_URL}/api/mcp/${endpoint}`, {
130
+ const response = await fetch(buildApiUrl(endpoint), {
119
131
  method: "POST",
120
132
  headers,
121
133
  body: JSON.stringify(data),
122
134
  signal: controller.signal,
123
135
  });
136
+ const contentType = response.headers.get("content-type") || "";
137
+ const responseBody = await response.text();
124
138
  if (!response.ok) {
139
+ if (response.status === 401 &&
140
+ contentType.includes("text/html") &&
141
+ responseBody.includes("Vercel Authentication")) {
142
+ throw new Error(VERCEL_BYPASS_TOKEN
143
+ ? "API call blocked by Vercel deployment protection despite bypass token. Check token validity and deployment protection settings."
144
+ : "API call blocked by Vercel deployment protection. Set VERCEL_BYPASS_TOKEN in MCP server env.");
145
+ }
125
146
  throw new Error(`API call failed: ${response.status} ${response.statusText}`);
126
147
  }
127
- return response.json();
148
+ if (responseBody.trim() === "") {
149
+ return {};
150
+ }
151
+ return JSON.parse(responseBody);
128
152
  }
129
153
  catch (error) {
130
154
  if (error instanceof Error && error.name === "AbortError") {
@@ -139,8 +163,12 @@ try {
139
163
  const server = new Server({
140
164
  name: "intangle-context",
141
165
  version: "1.0.0",
142
- vendor: "Intangle",
143
- icon: "https://intangle.tools/icon.png",
166
+ icons: [
167
+ {
168
+ src: "https://intangle.tools/icon.png",
169
+ mimeType: "image/png",
170
+ },
171
+ ],
144
172
  }, {
145
173
  capabilities: {
146
174
  tools: {},
@@ -200,7 +228,7 @@ try {
200
228
  if (!args.space_id) {
201
229
  throw new Error("space_id is required. Use view_spaces to see available options.");
202
230
  }
203
- if (!args.add && !args.update && !args.delete && !args.link && !args.unlink) {
231
+ if (!args.add && !args.update && !args.delete) {
204
232
  throw new Error("At least one operation must be provided");
205
233
  }
206
234
  // Ensure all add items have a type field to prevent classification timeout
@@ -220,8 +248,6 @@ try {
220
248
  add,
221
249
  update: args.update,
222
250
  delete: args.delete,
223
- link: args.link,
224
- unlink: args.unlink,
225
251
  });
226
252
  }
227
253
  async function handleMessage(args) {
@@ -252,12 +278,13 @@ try {
252
278
  case "view_spaces":
253
279
  result = await handleViewSpaces();
254
280
  break;
255
- case "view_projects":
256
- result = await handleViewProjects(args);
257
- break;
258
- case "view_project":
259
- result = await handleViewProject(args);
260
- break;
281
+ // PROJECTS DISABLED - Projects have been disabled. May be re-enabled later.
282
+ // case "view_projects":
283
+ // result = await handleViewProjects(args)
284
+ // break
285
+ // case "view_project":
286
+ // result = await handleViewProject(args)
287
+ // break
261
288
  case "create_space":
262
289
  result = await handleCreateSpace(args);
263
290
  break;
@@ -267,6 +294,7 @@ try {
267
294
  case "start":
268
295
  result = await handleStart(args);
269
296
  break;
297
+ case "update_memory":
270
298
  case "update_space":
271
299
  result = await handleUpdateSpace(args);
272
300
  break;
@@ -43,43 +43,50 @@ export const TOOLS = [
43
43
  }
44
44
  }
45
45
  },
46
- {
47
- name: "view_projects",
48
- title: "View Projects",
49
- description: "List all projects in a space. Projects are user-created canvases that organize context, tasks, documents, and skills. Use this to discover available projects before viewing their contents.",
50
- inputSchema: {
51
- type: "object",
52
- properties: {
53
- space_id: {
54
- type: "string",
55
- description: "REQUIRED: Space to list projects from (use view_spaces to see available options)"
56
- }
57
- },
58
- required: ["space_id"]
59
- }
60
- },
61
- {
62
- name: "view_project",
63
- title: "View Project",
64
- description: "View a specific project with all its items (context, tasks, documents, skills). Returns item metadata (IDs, titles, types, status) for each item in the project. Use fetch_items to get full content of specific items.",
65
- inputSchema: {
66
- type: "object",
67
- properties: {
68
- project_id: {
69
- type: "string",
70
- description: "Project ID to view (e.g., 'proj_123...'). Get project IDs from view_projects."
71
- },
72
- space_id: {
73
- type: "string",
74
- description: "Optional: Space ID (required if using slug instead of project_id)"
75
- },
76
- slug: {
77
- type: "string",
78
- description: "Optional: Project slug (URL-friendly name). Requires space_id if used."
79
- }
80
- }
81
- }
82
- },
46
+ // PROJECTS DISABLED - Projects have been disabled. May be re-enabled later.
47
+ // {
48
+ // name: "view_projects",
49
+ // title: "View Projects",
50
+ // description:
51
+ // "List all projects in a space. Projects are user-created canvases that organize context, tasks, documents, and skills. Use this to discover available projects before viewing their contents.",
52
+ // inputSchema: {
53
+ // type: "object",
54
+ // properties: {
55
+ // space_id: {
56
+ // type: "string",
57
+ // description:
58
+ // "REQUIRED: Space to list projects from (use view_spaces to see available options)"
59
+ // }
60
+ // },
61
+ // required: ["space_id"]
62
+ // }
63
+ // },
64
+ // {
65
+ // name: "view_project",
66
+ // title: "View Project",
67
+ // description:
68
+ // "View a specific project with all its items (context, tasks, documents, skills). Returns item metadata (IDs, titles, types, status) for each item in the project. Use fetch_items to get full content of specific items.",
69
+ // inputSchema: {
70
+ // type: "object",
71
+ // properties: {
72
+ // project_id: {
73
+ // type: "string",
74
+ // description:
75
+ // "Project ID to view (e.g., 'proj_123...'). Get project IDs from view_projects."
76
+ // },
77
+ // space_id: {
78
+ // type: "string",
79
+ // description:
80
+ // "Optional: Space ID (required if using slug instead of project_id)"
81
+ // },
82
+ // slug: {
83
+ // type: "string",
84
+ // description:
85
+ // "Optional: Project slug (URL-friendly name). Requires space_id if used."
86
+ // }
87
+ // }
88
+ // }
89
+ // },
83
90
  {
84
91
  name: "start",
85
92
  title: "Start Space Session",
@@ -148,8 +155,8 @@ export const TOOLS = [
148
155
  }
149
156
  },
150
157
  {
151
- name: "update_space",
152
- title: "Update Space",
158
+ name: "update_memory",
159
+ title: "Update Memory",
153
160
  description: "Add, update, or delete items in a space. Supports any combination of operations in a single call.\n\nTIPS FOR RICH MEMORY: The more context you provide, the smarter the system becomes:\n- Include WHY something matters, not just WHAT it is\n- Note user preferences, patterns, and approaches you observe\n- Describe repeatable workflows as skills (step-by-step procedures)\n- Link related items using parent_id or linkedItemIds\n- Use descriptive titles that capture the essence\n- Add context about decisions, reasoning, and outcomes\n\nThe system learns from patterns - sharing how the user works helps it anticipate their needs.",
154
161
  inputSchema: {
155
162
  type: "object",
package/index.ts CHANGED
@@ -44,9 +44,12 @@ try {
44
44
  // Base URL for API calls to Next.js app
45
45
  const API_BASE_URL = process.env.NEXT_APP_URL || "https://intangle.app"
46
46
  const MCP_API_KEY = process.env.MCP_API_KEY
47
+ const VERCEL_BYPASS_TOKEN =
48
+ process.env.VERCEL_BYPASS_TOKEN || process.env.VERCEL_PROTECTION_BYPASS
47
49
 
48
50
  log(`CWD: ${process.cwd()}`)
49
51
  log(`Has API Key: ${!!MCP_API_KEY}`)
52
+ log(`Has Vercel Bypass Token: ${!!VERCEL_BYPASS_TOKEN}`)
50
53
  log(`Node Version: ${process.version}`)
51
54
 
52
55
  if (!MCP_API_KEY) {
@@ -121,6 +124,16 @@ try {
121
124
  // Default timeout for API calls (90 seconds)
122
125
  const API_TIMEOUT_MS = 90_000
123
126
 
127
+ function buildApiUrl(endpoint: string) {
128
+ const url = new URL(`/api/mcp/${endpoint}`, API_BASE_URL)
129
+
130
+ if (VERCEL_BYPASS_TOKEN) {
131
+ url.searchParams.set("x-vercel-protection-bypass", VERCEL_BYPASS_TOKEN)
132
+ }
133
+
134
+ return url.toString()
135
+ }
136
+
124
137
  async function makeApiCall(endpoint: string, data: any, timeoutMs?: number) {
125
138
  // Ensure we have client info before making requests
126
139
  ensureClientInfo()
@@ -141,6 +154,9 @@ try {
141
154
  if (mcpClientVersion) {
142
155
  headers["X-MCP-Client-Version"] = mcpClientVersion
143
156
  }
157
+ if (VERCEL_BYPASS_TOKEN) {
158
+ headers["x-vercel-protection-bypass"] = VERCEL_BYPASS_TOKEN
159
+ }
144
160
 
145
161
  // Apply timeout to prevent hanging requests
146
162
  const controller = new AbortController()
@@ -148,20 +164,37 @@ try {
148
164
  const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout)
149
165
 
150
166
  try {
151
- const response = await fetch(`${API_BASE_URL}/api/mcp/${endpoint}`, {
167
+ const response = await fetch(buildApiUrl(endpoint), {
152
168
  method: "POST",
153
169
  headers,
154
170
  body: JSON.stringify(data),
155
171
  signal: controller.signal as AbortSignal,
156
172
  })
157
173
 
174
+ const contentType = response.headers.get("content-type") || ""
175
+ const responseBody = await response.text()
176
+
158
177
  if (!response.ok) {
159
- throw new Error(
160
- `API call failed: ${response.status} ${response.statusText}`
161
- )
178
+ if (
179
+ response.status === 401 &&
180
+ contentType.includes("text/html") &&
181
+ responseBody.includes("Vercel Authentication")
182
+ ) {
183
+ throw new Error(
184
+ VERCEL_BYPASS_TOKEN
185
+ ? "API call blocked by Vercel deployment protection despite bypass token. Check token validity and deployment protection settings."
186
+ : "API call blocked by Vercel deployment protection. Set VERCEL_BYPASS_TOKEN in MCP server env."
187
+ )
188
+ }
189
+
190
+ throw new Error(`API call failed: ${response.status} ${response.statusText}`)
162
191
  }
163
192
 
164
- return response.json()
193
+ if (responseBody.trim() === "") {
194
+ return {}
195
+ }
196
+
197
+ return JSON.parse(responseBody)
165
198
  } catch (error: unknown) {
166
199
  if (error instanceof Error && error.name === "AbortError") {
167
200
  throw new Error(
@@ -178,8 +211,12 @@ try {
178
211
  {
179
212
  name: "intangle-context",
180
213
  version: "1.0.0",
181
- vendor: "Intangle",
182
- icon: "https://intangle.tools/icon.png",
214
+ icons: [
215
+ {
216
+ src: "https://intangle.tools/icon.png",
217
+ mimeType: "image/png",
218
+ },
219
+ ],
183
220
  },
184
221
  {
185
222
  capabilities: {
@@ -272,7 +309,7 @@ try {
272
309
  )
273
310
  }
274
311
 
275
- if (!args.add && !args.update && !args.delete && !args.link && !args.unlink) {
312
+ if (!args.add && !args.update && !args.delete) {
276
313
  throw new Error(
277
314
  "At least one operation must be provided"
278
315
  )
@@ -296,8 +333,6 @@ try {
296
333
  add,
297
334
  update: args.update,
298
335
  delete: args.delete,
299
- link: args.link,
300
- unlink: args.unlink,
301
336
  })
302
337
  }
303
338
 
@@ -336,12 +371,13 @@ try {
336
371
  case "view_spaces":
337
372
  result = await handleViewSpaces()
338
373
  break
339
- case "view_projects":
340
- result = await handleViewProjects(args)
341
- break
342
- case "view_project":
343
- result = await handleViewProject(args)
344
- break
374
+ // PROJECTS DISABLED - Projects have been disabled. May be re-enabled later.
375
+ // case "view_projects":
376
+ // result = await handleViewProjects(args)
377
+ // break
378
+ // case "view_project":
379
+ // result = await handleViewProject(args)
380
+ // break
345
381
  case "create_space":
346
382
  result = await handleCreateSpace(args)
347
383
  break
@@ -351,6 +387,7 @@ try {
351
387
  case "start":
352
388
  result = await handleStart(args)
353
389
  break
390
+ case "update_memory":
354
391
  case "update_space":
355
392
  result = await handleUpdateSpace(args)
356
393
  break
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intangle/mcp-server",
3
- "version": "2.5.1",
3
+ "version": "2.5.3",
4
4
  "description": "Model Context Protocol server for Intangle - AI context that persists across conversations",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -49,49 +49,50 @@ export const TOOLS = [
49
49
  }
50
50
  }
51
51
  },
52
- {
53
- name: "view_projects",
54
- title: "View Projects",
55
- description:
56
- "List all projects in a space. Projects are user-created canvases that organize context, tasks, documents, and skills. Use this to discover available projects before viewing their contents.",
57
- inputSchema: {
58
- type: "object",
59
- properties: {
60
- space_id: {
61
- type: "string",
62
- description:
63
- "REQUIRED: Space to list projects from (use view_spaces to see available options)"
64
- }
65
- },
66
- required: ["space_id"]
67
- }
68
- },
69
- {
70
- name: "view_project",
71
- title: "View Project",
72
- description:
73
- "View a specific project with all its items (context, tasks, documents, skills). Returns item metadata (IDs, titles, types, status) for each item in the project. Use fetch_items to get full content of specific items.",
74
- inputSchema: {
75
- type: "object",
76
- properties: {
77
- project_id: {
78
- type: "string",
79
- description:
80
- "Project ID to view (e.g., 'proj_123...'). Get project IDs from view_projects."
81
- },
82
- space_id: {
83
- type: "string",
84
- description:
85
- "Optional: Space ID (required if using slug instead of project_id)"
86
- },
87
- slug: {
88
- type: "string",
89
- description:
90
- "Optional: Project slug (URL-friendly name). Requires space_id if used."
91
- }
92
- }
93
- }
94
- },
52
+ // PROJECTS DISABLED - Projects have been disabled. May be re-enabled later.
53
+ // {
54
+ // name: "view_projects",
55
+ // title: "View Projects",
56
+ // description:
57
+ // "List all projects in a space. Projects are user-created canvases that organize context, tasks, documents, and skills. Use this to discover available projects before viewing their contents.",
58
+ // inputSchema: {
59
+ // type: "object",
60
+ // properties: {
61
+ // space_id: {
62
+ // type: "string",
63
+ // description:
64
+ // "REQUIRED: Space to list projects from (use view_spaces to see available options)"
65
+ // }
66
+ // },
67
+ // required: ["space_id"]
68
+ // }
69
+ // },
70
+ // {
71
+ // name: "view_project",
72
+ // title: "View Project",
73
+ // description:
74
+ // "View a specific project with all its items (context, tasks, documents, skills). Returns item metadata (IDs, titles, types, status) for each item in the project. Use fetch_items to get full content of specific items.",
75
+ // inputSchema: {
76
+ // type: "object",
77
+ // properties: {
78
+ // project_id: {
79
+ // type: "string",
80
+ // description:
81
+ // "Project ID to view (e.g., 'proj_123...'). Get project IDs from view_projects."
82
+ // },
83
+ // space_id: {
84
+ // type: "string",
85
+ // description:
86
+ // "Optional: Space ID (required if using slug instead of project_id)"
87
+ // },
88
+ // slug: {
89
+ // type: "string",
90
+ // description:
91
+ // "Optional: Project slug (URL-friendly name). Requires space_id if used."
92
+ // }
93
+ // }
94
+ // }
95
+ // },
95
96
  {
96
97
  name: "start",
97
98
  title: "Start Space Session",
@@ -167,8 +168,8 @@ export const TOOLS = [
167
168
  }
168
169
  },
169
170
  {
170
- name: "update_space",
171
- title: "Update Space",
171
+ name: "update_memory",
172
+ title: "Update Memory",
172
173
  description:
173
174
  "Add, update, or delete items in a space. Supports any combination of operations in a single call.\n\nTIPS FOR RICH MEMORY: The more context you provide, the smarter the system becomes:\n- Include WHY something matters, not just WHAT it is\n- Note user preferences, patterns, and approaches you observe\n- Describe repeatable workflows as skills (step-by-step procedures)\n- Link related items using parent_id or linkedItemIds\n- Use descriptive titles that capture the essence\n- Add context about decisions, reasoning, and outcomes\n\nThe system learns from patterns - sharing how the user works helps it anticipate their needs.",
174
175
  inputSchema: {