@intangle/mcp-server 2.5.1 → 2.5.2

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,14 @@ 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-set-bypass-cookie", "true");
101
+ url.searchParams.set("x-vercel-protection-bypass", VERCEL_BYPASS_TOKEN);
102
+ }
103
+ return url.toString();
104
+ }
95
105
  async function makeApiCall(endpoint, data, timeoutMs) {
96
106
  // Ensure we have client info before making requests
97
107
  ensureClientInfo();
@@ -110,21 +120,36 @@ try {
110
120
  if (mcpClientVersion) {
111
121
  headers["X-MCP-Client-Version"] = mcpClientVersion;
112
122
  }
123
+ if (VERCEL_BYPASS_TOKEN) {
124
+ headers["x-vercel-protection-bypass"] = VERCEL_BYPASS_TOKEN;
125
+ }
113
126
  // Apply timeout to prevent hanging requests
114
127
  const controller = new AbortController();
115
128
  const effectiveTimeout = timeoutMs || API_TIMEOUT_MS;
116
129
  const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
117
130
  try {
118
- const response = await fetch(`${API_BASE_URL}/api/mcp/${endpoint}`, {
131
+ const response = await fetch(buildApiUrl(endpoint), {
119
132
  method: "POST",
120
133
  headers,
121
134
  body: JSON.stringify(data),
122
135
  signal: controller.signal,
123
136
  });
137
+ const contentType = response.headers.get("content-type") || "";
138
+ const responseBody = await response.text();
124
139
  if (!response.ok) {
140
+ if (response.status === 401 &&
141
+ contentType.includes("text/html") &&
142
+ responseBody.includes("Vercel Authentication")) {
143
+ throw new Error(VERCEL_BYPASS_TOKEN
144
+ ? "API call blocked by Vercel deployment protection despite bypass token. Check token validity and deployment protection settings."
145
+ : "API call blocked by Vercel deployment protection. Set VERCEL_BYPASS_TOKEN in MCP server env.");
146
+ }
125
147
  throw new Error(`API call failed: ${response.status} ${response.statusText}`);
126
148
  }
127
- return response.json();
149
+ if (responseBody.trim() === "") {
150
+ return {};
151
+ }
152
+ return JSON.parse(responseBody);
128
153
  }
129
154
  catch (error) {
130
155
  if (error instanceof Error && error.name === "AbortError") {
@@ -139,8 +164,12 @@ try {
139
164
  const server = new Server({
140
165
  name: "intangle-context",
141
166
  version: "1.0.0",
142
- vendor: "Intangle",
143
- icon: "https://intangle.tools/icon.png",
167
+ icons: [
168
+ {
169
+ src: "https://intangle.tools/icon.png",
170
+ mimeType: "image/png",
171
+ },
172
+ ],
144
173
  }, {
145
174
  capabilities: {
146
175
  tools: {},
@@ -200,7 +229,7 @@ try {
200
229
  if (!args.space_id) {
201
230
  throw new Error("space_id is required. Use view_spaces to see available options.");
202
231
  }
203
- if (!args.add && !args.update && !args.delete && !args.link && !args.unlink) {
232
+ if (!args.add && !args.update && !args.delete) {
204
233
  throw new Error("At least one operation must be provided");
205
234
  }
206
235
  // Ensure all add items have a type field to prevent classification timeout
@@ -220,8 +249,6 @@ try {
220
249
  add,
221
250
  update: args.update,
222
251
  delete: args.delete,
223
- link: args.link,
224
- unlink: args.unlink,
225
252
  });
226
253
  }
227
254
  async function handleMessage(args) {
@@ -252,12 +279,13 @@ try {
252
279
  case "view_spaces":
253
280
  result = await handleViewSpaces();
254
281
  break;
255
- case "view_projects":
256
- result = await handleViewProjects(args);
257
- break;
258
- case "view_project":
259
- result = await handleViewProject(args);
260
- break;
282
+ // PROJECTS DISABLED - Projects have been disabled. May be re-enabled later.
283
+ // case "view_projects":
284
+ // result = await handleViewProjects(args)
285
+ // break
286
+ // case "view_project":
287
+ // result = await handleViewProject(args)
288
+ // break
261
289
  case "create_space":
262
290
  result = await handleCreateSpace(args);
263
291
  break;
@@ -267,6 +295,7 @@ try {
267
295
  case "start":
268
296
  result = await handleStart(args);
269
297
  break;
298
+ case "update_memory":
270
299
  case "update_space":
271
300
  result = await handleUpdateSpace(args);
272
301
  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,17 @@ 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-set-bypass-cookie", "true")
132
+ url.searchParams.set("x-vercel-protection-bypass", VERCEL_BYPASS_TOKEN)
133
+ }
134
+
135
+ return url.toString()
136
+ }
137
+
124
138
  async function makeApiCall(endpoint: string, data: any, timeoutMs?: number) {
125
139
  // Ensure we have client info before making requests
126
140
  ensureClientInfo()
@@ -141,6 +155,9 @@ try {
141
155
  if (mcpClientVersion) {
142
156
  headers["X-MCP-Client-Version"] = mcpClientVersion
143
157
  }
158
+ if (VERCEL_BYPASS_TOKEN) {
159
+ headers["x-vercel-protection-bypass"] = VERCEL_BYPASS_TOKEN
160
+ }
144
161
 
145
162
  // Apply timeout to prevent hanging requests
146
163
  const controller = new AbortController()
@@ -148,20 +165,37 @@ try {
148
165
  const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout)
149
166
 
150
167
  try {
151
- const response = await fetch(`${API_BASE_URL}/api/mcp/${endpoint}`, {
168
+ const response = await fetch(buildApiUrl(endpoint), {
152
169
  method: "POST",
153
170
  headers,
154
171
  body: JSON.stringify(data),
155
172
  signal: controller.signal as AbortSignal,
156
173
  })
157
174
 
175
+ const contentType = response.headers.get("content-type") || ""
176
+ const responseBody = await response.text()
177
+
158
178
  if (!response.ok) {
159
- throw new Error(
160
- `API call failed: ${response.status} ${response.statusText}`
161
- )
179
+ if (
180
+ response.status === 401 &&
181
+ contentType.includes("text/html") &&
182
+ responseBody.includes("Vercel Authentication")
183
+ ) {
184
+ throw new Error(
185
+ VERCEL_BYPASS_TOKEN
186
+ ? "API call blocked by Vercel deployment protection despite bypass token. Check token validity and deployment protection settings."
187
+ : "API call blocked by Vercel deployment protection. Set VERCEL_BYPASS_TOKEN in MCP server env."
188
+ )
189
+ }
190
+
191
+ throw new Error(`API call failed: ${response.status} ${response.statusText}`)
162
192
  }
163
193
 
164
- return response.json()
194
+ if (responseBody.trim() === "") {
195
+ return {}
196
+ }
197
+
198
+ return JSON.parse(responseBody)
165
199
  } catch (error: unknown) {
166
200
  if (error instanceof Error && error.name === "AbortError") {
167
201
  throw new Error(
@@ -178,8 +212,12 @@ try {
178
212
  {
179
213
  name: "intangle-context",
180
214
  version: "1.0.0",
181
- vendor: "Intangle",
182
- icon: "https://intangle.tools/icon.png",
215
+ icons: [
216
+ {
217
+ src: "https://intangle.tools/icon.png",
218
+ mimeType: "image/png",
219
+ },
220
+ ],
183
221
  },
184
222
  {
185
223
  capabilities: {
@@ -272,7 +310,7 @@ try {
272
310
  )
273
311
  }
274
312
 
275
- if (!args.add && !args.update && !args.delete && !args.link && !args.unlink) {
313
+ if (!args.add && !args.update && !args.delete) {
276
314
  throw new Error(
277
315
  "At least one operation must be provided"
278
316
  )
@@ -296,8 +334,6 @@ try {
296
334
  add,
297
335
  update: args.update,
298
336
  delete: args.delete,
299
- link: args.link,
300
- unlink: args.unlink,
301
337
  })
302
338
  }
303
339
 
@@ -336,12 +372,13 @@ try {
336
372
  case "view_spaces":
337
373
  result = await handleViewSpaces()
338
374
  break
339
- case "view_projects":
340
- result = await handleViewProjects(args)
341
- break
342
- case "view_project":
343
- result = await handleViewProject(args)
344
- break
375
+ // PROJECTS DISABLED - Projects have been disabled. May be re-enabled later.
376
+ // case "view_projects":
377
+ // result = await handleViewProjects(args)
378
+ // break
379
+ // case "view_project":
380
+ // result = await handleViewProject(args)
381
+ // break
345
382
  case "create_space":
346
383
  result = await handleCreateSpace(args)
347
384
  break
@@ -351,6 +388,7 @@ try {
351
388
  case "start":
352
389
  result = await handleStart(args)
353
390
  break
391
+ case "update_memory":
354
392
  case "update_space":
355
393
  result = await handleUpdateSpace(args)
356
394
  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.2",
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: {