@intangle/mcp-server 2.1.7 → 2.1.9

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
@@ -1,10 +1,10 @@
1
1
  # @intangle/mcp-server
2
2
 
3
- Model Context Protocol server for [Intangle](https://intangle.app) - Intelligent AI memory that persists across conversations.
3
+ Model Context Protocol server for [Intangle](https://intangle.app) - Intelligent AI context that persists across conversations.
4
4
 
5
5
  ## What is Intangle?
6
6
 
7
- Intangle is an AI memory system that gives Claude and other AI assistants persistent, searchable memory across all your conversations and isolated spaces. Unlike traditional chat interfaces where context is lost between sessions, Intangle maintains your personal memory across isolated spaces, with intelligent storing and retriveal.
7
+ Intangle is an AI context system that gives Claude and other AI assistants persistent, searchable context across all your conversations and isolated spaces. Unlike traditional chat interfaces where context is lost between sessions, Intangle maintains your personal context across isolated spaces, with intelligent storing and retrieval.
8
8
 
9
9
  **Important: You need an Intangle account to use this MCP server. Sign up at [intangle.app](https://intangle.app)**
10
10
 
@@ -46,29 +46,29 @@ Standard MCP (Claude desktop, Cursor): by adding to your `claude_desktop_config.
46
46
 
47
47
  ## Usage
48
48
 
49
- Once configured, Claude will automatically have access to your Intangle memory. You can:
49
+ Once configured, Claude will automatically have access to your Intangle context. You can:
50
50
 
51
- - **Store memories**: "Remember that I prefer TypeScript over JavaScript"
52
- - **Search memories**: "What did we discuss about the authentication system?"
53
- - **Organize with spaces**: Separate memories for personal, work, and different projects
54
- - **Tag with topics**: Memories are automatically tagged and organized
55
- - **Access across conversations**: All memories persist between chat sessions
51
+ - **Store context**: "Remember that I prefer TypeScript over JavaScript"
52
+ - **Search context**: "What did we discuss about the authentication system?"
53
+ - **Organize with spaces**: Separate context for personal, work, and different projects
54
+ - **Tag with topics**: Context is automatically tagged and organized
55
+ - **Access across conversations**: All context persists between chat sessions
56
56
 
57
57
  ## Available Tools
58
58
 
59
59
  The MCP server provides these tools to Claude:
60
60
 
61
- - `add_memory` - Store new memories with topics
62
- - `search_memories` - Search across all your memories
63
- - `get_recent_memories` - Retrieve recent memories
64
- - `list_spaces` - View available memory spaces
61
+ - `add_context` - Store new context with topics
62
+ - `search_context` - Search across all your context
63
+ - `get_recent_context` - Retrieve recent context
64
+ - `list_spaces` - View available context spaces
65
65
  - `get_space_info` - Get details about a specific space
66
- - `get_entities` - Extract entities from memories
67
- - `delete_memory` - Remove specific memories
66
+ - `get_entities` - Extract entities from context
67
+ - `delete_context` - Remove specific context
68
68
 
69
69
  ## Features
70
70
 
71
- - **Multi-space support**: Organize memories into separate spaces (personal, work, projects)
71
+ - **Multi-space support**: Organize context into separate spaces (personal, work, projects)
72
72
  - **Intelligent search**: Combines semantic search with text matching
73
73
  - **Entity extraction**: Automatically identifies people, places, and concepts
74
74
  - **Temporal awareness**: Tracks when events happened vs when they were recorded
@@ -76,7 +76,7 @@ The MCP server provides these tools to Claude:
76
76
 
77
77
  ## Troubleshooting
78
78
 
79
- If Claude can't access your memories:
79
+ If Claude can't access your context:
80
80
 
81
81
  1. Verify your API key is correct
82
82
  2. Check that the MCP server is listed in Claude's tool menu
package/biome.json CHANGED
@@ -1,39 +1,39 @@
1
1
  {
2
- "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
3
- "vcs": {
4
- "enabled": false,
5
- "clientKind": "git",
6
- "useIgnoreFile": false
7
- },
8
- "files": {
9
- "ignoreUnknown": false
10
- },
11
- "formatter": {
12
- "enabled": true,
13
- "formatWithErrors": false,
14
- "indentStyle": "space",
15
- "indentWidth": 2,
16
- "lineEnding": "lf",
17
- "lineWidth": 80,
18
- "attributePosition": "auto"
19
- },
20
- "linter": {
21
- "enabled": true,
22
- "rules": {
23
- "recommended": true
24
- }
25
- },
26
- "javascript": {
27
- "formatter": {
28
- "jsxQuoteStyle": "double",
29
- "quoteProperties": "asNeeded",
30
- "trailingCommas": "es5",
31
- "semicolons": "asNeeded",
32
- "arrowParentheses": "always",
33
- "bracketSpacing": true,
34
- "bracketSameLine": false,
35
- "quoteStyle": "double",
36
- "attributePosition": "auto"
37
- }
38
- }
2
+ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
3
+ "vcs": {
4
+ "enabled": false,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": false
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": false
10
+ },
11
+ "formatter": {
12
+ "enabled": true,
13
+ "formatWithErrors": false,
14
+ "indentStyle": "space",
15
+ "indentWidth": 2,
16
+ "lineEnding": "lf",
17
+ "lineWidth": 80,
18
+ "attributePosition": "auto"
19
+ },
20
+ "linter": {
21
+ "enabled": true,
22
+ "rules": {
23
+ "recommended": true
24
+ }
25
+ },
26
+ "javascript": {
27
+ "formatter": {
28
+ "jsxQuoteStyle": "double",
29
+ "quoteProperties": "asNeeded",
30
+ "trailingCommas": "es5",
31
+ "semicolons": "asNeeded",
32
+ "arrowParentheses": "always",
33
+ "bracketSpacing": true,
34
+ "bracketSameLine": false,
35
+ "quoteStyle": "double",
36
+ "attributePosition": "auto"
37
+ }
38
+ }
39
39
  }
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Endure MCP Server - Exposes Endure memory functionality through MCP
3
+ * Endure MCP Server - Exposes Endure context functionality through MCP
4
4
  */
5
- import { config } from "dotenv";
6
- import fetch from "node-fetch";
5
+ import { readFileSync } from "fs";
6
+ import { dirname, join } from "path";
7
+ import { fileURLToPath } from "url";
7
8
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
9
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
10
  import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
10
- import { readFileSync } from "fs";
11
- import { fileURLToPath } from "url";
12
- import { dirname, join } from "path";
11
+ import { config } from "dotenv";
12
+ import fetch from "node-fetch";
13
13
  import { TOOLS } from "./tool-definitions.js";
14
14
  // ... imports ...
15
15
  // Debug logging
@@ -119,7 +119,7 @@ try {
119
119
  return response.json();
120
120
  }
121
121
  const server = new Server({
122
- name: "intangle-memory",
122
+ name: "intangle-context",
123
123
  version: "1.0.0",
124
124
  vendor: "Intangle",
125
125
  icon: "https://intangle.tools/icon.png",
@@ -131,7 +131,7 @@ try {
131
131
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
132
132
  tools: TOOLS,
133
133
  }));
134
- async function handleSearchMemories(args) {
134
+ async function handleSearchContext(args) {
135
135
  const { space_id, query, topics } = args;
136
136
  // Require space_id
137
137
  if (!space_id) {
@@ -199,7 +199,7 @@ try {
199
199
  let result;
200
200
  switch (name) {
201
201
  case "search":
202
- result = await handleSearchMemories(args);
202
+ result = await handleSearchContext(args);
203
203
  break;
204
204
  case "fetch_items":
205
205
  result = await handleFetch(args);
@@ -46,7 +46,7 @@ export const TOOLS = [
46
46
  {
47
47
  name: "view_topic",
48
48
  title: "View Topic",
49
- description: "View all memories, tasks, and processes tagged with a specific topic. Perfect for exploring a topic area or following up on topics from the start briefing.",
49
+ description: "View all context, tasks, and processes tagged with a specific topic. Perfect for exploring a topic area or following up on topics from the start briefing.",
50
50
  inputSchema: {
51
51
  type: "object",
52
52
  properties: {
@@ -115,7 +115,7 @@ export const TOOLS = [
115
115
  config_badges: {
116
116
  type: "array",
117
117
  items: { type: "string" },
118
- description: "Array of keywords for start tool keywords in this NEW space. These keywords help steer what context gets loaded when running 'start' for this space. Examples: ['fitness', 'recipes', 'travel planning'], ['client work', 'meetings', 'proposals'], ['TypeScript', 'React', 'API design']. They act as search terms to prioritize relevant memories.",
118
+ description: "Array of keywords for start tool keywords in this NEW space. These keywords help steer what context gets loaded when running 'start' for this space. Examples: ['fitness', 'recipes', 'travel planning'], ['client work', 'meetings', 'proposals'], ['TypeScript', 'React', 'API design']. They act as search terms to prioritize relevant context.",
119
119
  },
120
120
  startup_preferences: {
121
121
  type: "string",
@@ -153,7 +153,7 @@ export const TOOLS = [
153
153
  },
154
154
  add: {
155
155
  type: "object",
156
- description: "Add new items to memory with automatic intelligent classification and topic suggestion",
156
+ description: "Add new items to context with automatic intelligent classification and topic suggestion",
157
157
  properties: {
158
158
  items: {
159
159
  type: "array",
package/index.ts CHANGED
@@ -1,348 +1,347 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Endure MCP Server - Exposes Endure memory functionality through MCP
4
+ * Endure MCP Server - Exposes Endure context functionality through MCP
5
5
  */
6
6
 
7
- import { config } from "dotenv";
8
- import fetch from "node-fetch";
9
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { readFileSync } from "fs"
8
+ import { dirname, join } from "path"
9
+ import { fileURLToPath } from "url"
10
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js"
11
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
11
12
  import {
12
- CallToolRequestSchema,
13
- ErrorCode,
14
- ListToolsRequestSchema,
15
- McpError,
16
- } from "@modelcontextprotocol/sdk/types.js";
17
- import { readFileSync } from "fs";
18
- import { fileURLToPath } from "url";
19
- import { dirname, join } from "path";
20
- import { TOOLS } from "./tool-definitions.js";
13
+ CallToolRequestSchema,
14
+ ErrorCode,
15
+ ListToolsRequestSchema,
16
+ McpError,
17
+ } from "@modelcontextprotocol/sdk/types.js"
18
+ import { config } from "dotenv"
19
+ import fetch from "node-fetch"
20
+ import { TOOLS } from "./tool-definitions.js"
21
21
 
22
22
  // ... imports ...
23
23
 
24
24
  // Debug logging
25
- import { appendFileSync } from "fs";
26
- const DEBUG_LOG = "/tmp/intangle-mcp-debug.log";
25
+ import { appendFileSync } from "fs"
26
+ const DEBUG_LOG = "/tmp/intangle-mcp-debug.log"
27
27
  function log(msg: string) {
28
- try {
29
- appendFileSync(DEBUG_LOG, `${new Date().toISOString()}: ${msg}\n`);
30
- } catch (e) { }
28
+ try {
29
+ appendFileSync(DEBUG_LOG, `${new Date().toISOString()}: ${msg}\n`)
30
+ } catch (e) {}
31
31
  }
32
32
 
33
- log("--- Server Starting ---");
33
+ log("--- Server Starting ---")
34
34
 
35
35
  // Client info captured from MCP initialize handshake
36
- let mcpClientName: string | undefined;
37
- let mcpClientVersion: string | undefined;
36
+ let mcpClientName: string | undefined
37
+ let mcpClientVersion: string | undefined
38
38
 
39
39
  try {
40
- // Load environment variables from .env and .env.local
41
- config({ quiet: true });
42
- config({ path: ".env.local", quiet: true });
43
-
44
- // Base URL for API calls to Next.js app
45
- const API_BASE_URL = process.env.NEXT_APP_URL || "https://intangle.app";
46
- const MCP_API_KEY = process.env.MCP_API_KEY;
47
-
48
- log(`CWD: ${process.cwd()}`);
49
- log(`Has API Key: ${!!MCP_API_KEY}`);
50
- log(`Node Version: ${process.version}`);
51
-
52
- if (!MCP_API_KEY) {
53
- log("Error: MCP_API_KEY environment variable is required");
54
- console.error("Error: MCP_API_KEY environment variable is required");
55
- console.error(
56
- "Please set your Intangle API key in the Claude Desktop configuration",
57
- );
58
- process.exit(1);
59
- }
60
-
61
- console.error("Intangle MCP Server starting - connecting to", API_BASE_URL);
62
-
63
- // Version checking - automatically read from package.json
64
- const __dirname = dirname(fileURLToPath(import.meta.url));
65
- let packageJson;
66
- try {
67
- packageJson = JSON.parse(
68
- readFileSync(join(__dirname, "package.json"), "utf-8"),
69
- );
70
- } catch {
71
- packageJson = JSON.parse(
72
- readFileSync(join(__dirname, "../package.json"), "utf-8"),
73
- );
74
- }
75
- const CURRENT_VERSION = packageJson.version;
76
- let latestVersion: string | null = null;
77
- let versionCheckDone = false;
78
-
79
- async function checkVersion() {
80
- if (versionCheckDone) return;
81
-
82
- try {
83
- const response = await fetch(
84
- "https://registry.npmjs.org/@intangle/mcp-server/latest",
85
- );
86
- const data = (await response.json()) as { version: string };
87
- latestVersion = data.version;
88
- versionCheckDone = true;
89
-
90
- if (latestVersion && latestVersion !== CURRENT_VERSION) {
91
- console.error("\n UPDATE AVAILABLE ");
92
- console.error(`Current version: ${CURRENT_VERSION}`);
93
- console.error(`Latest version: ${latestVersion}`);
94
- console.error("Update with: npx @intangle/mcp-server@latest\n");
95
- } else {
96
- console.error(`✓ Running latest version (${CURRENT_VERSION})`);
97
- }
98
- } catch (error) {
99
- // Silently fail version check - don't block startup
100
- versionCheckDone = true;
101
- }
102
- }
103
-
104
- // Check version on startup (non-blocking)
105
- checkVersion();
106
-
107
- // Helper to ensure client info is captured (called before API requests)
108
- function ensureClientInfo() {
109
- if (!mcpClientName) {
110
- const clientInfo = server.getClientVersion();
111
- if (clientInfo) {
112
- mcpClientName = clientInfo.name;
113
- mcpClientVersion = clientInfo.version;
114
- log(`Client identified (on-demand): ${mcpClientName} v${mcpClientVersion}`);
115
- }
116
- }
117
- }
118
-
119
- async function makeApiCall(endpoint: string, data: any) {
120
- // Ensure we have client info before making requests
121
- ensureClientInfo();
122
-
123
- // Build headers with client info if available
124
- const headers: Record<string, string> = {
125
- "Content-Type": "application/json",
126
- Authorization: `Bearer ${MCP_API_KEY}`,
127
- "User-Agent": mcpClientName
128
- ? `${mcpClientName}/${mcpClientVersion || "unknown"} (mcp-stdio)`
129
- : "MCP-Client-Stdio/1.1.2 (mcp)",
130
- };
131
-
132
- // Add explicit client info headers for backend processing
133
- if (mcpClientName) {
134
- headers["X-MCP-Client-Name"] = mcpClientName;
135
- }
136
- if (mcpClientVersion) {
137
- headers["X-MCP-Client-Version"] = mcpClientVersion;
138
- }
139
-
140
- const response = await fetch(`${API_BASE_URL}/api/mcp/${endpoint}`, {
141
- method: "POST",
142
- headers,
143
- body: JSON.stringify(data),
144
- });
145
-
146
- if (!response.ok) {
147
- throw new Error(
148
- `API call failed: ${response.status} ${response.statusText}`,
149
- );
150
- }
151
-
152
- return response.json();
153
- }
154
-
155
- const server = new Server(
156
- {
157
- name: "intangle-memory",
158
- version: "1.0.0",
159
- vendor: "Intangle",
160
- icon: "https://intangle.tools/icon.png",
161
- },
162
- {
163
- capabilities: {
164
- tools: {},
165
- },
166
- },
167
- );
168
-
169
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
170
- tools: TOOLS,
171
- }));
172
-
173
- async function handleSearchMemories(args: any) {
174
- const { space_id, query, topics } = args as {
175
- space_id: string;
176
- query: string;
177
- topics?: string[];
178
- };
179
-
180
- // Require space_id
181
- if (!space_id) {
182
- throw new Error(
183
- "space_id is required. Use list_spaces to see available options.",
184
- );
185
- }
186
-
187
- return makeApiCall("search-memories", {
188
- space_id,
189
- space_ids: [space_id], // Convert to array for backend compatibility
190
- query,
191
- topics,
192
- });
193
- }
194
-
195
- async function handleFetch(args: any) {
196
- const { id, ids } = args as { id?: string; ids?: string[] };
197
-
198
- return makeApiCall("fetch", { id, ids });
199
- }
200
-
201
- async function handleViewSpaces() {
202
- return makeApiCall("list-spaces", {});
203
- }
204
-
205
- async function handleViewTopics(args: any) {
206
- const { space_id } = args as { space_id: string };
207
- if (!space_id) {
208
- throw new Error(
209
- "space_id is required. Use view_spaces to see available options.",
210
- );
211
- }
212
- return makeApiCall("view-topics", { space_id });
213
- }
214
-
215
- async function handleViewTopic(args: any) {
216
- const { topic_id } = args as { topic_id: string };
217
- if (!topic_id) {
218
- throw new Error(
219
- "topic_id is required. Use view_topics to get valid IDs.",
220
- );
221
- }
222
- // Pass directly to API; ensure API expects 'topic_id' or adjust if it expects 'id'
223
- // Usually view-topic endpoint takes 'topic_id' or 'id'
224
- return makeApiCall("view-topic", { topic_id });
225
- }
226
-
227
- async function handleCreateSpace(args: any) {
228
- return makeApiCall("create-space", args);
229
- }
230
-
231
- async function handleViewSpace(args: any) {
232
- const { space_id } = args as { space_id: string };
233
- return makeApiCall("view-space", { space_id });
234
- }
235
-
236
- async function handleStart(args: any) {
237
- const { space_id } = args as { space_id: string };
238
- return makeApiCall("start", { space_id });
239
- }
240
-
241
- async function handleUpdateSpace(args: any) {
242
- if (!args.space_id) {
243
- throw new Error(
244
- "space_id is required. Use view_spaces to see available options.",
245
- );
246
- }
247
-
248
- if (!args.add && !args.update && !args.delete) {
249
- throw new Error(
250
- "At least one operation (add, update, delete) must be provided",
251
- );
252
- }
253
-
254
- // Pass through to API with new structure
255
- return makeApiCall("update-memory", {
256
- space_id: args.space_id,
257
- add: args.add,
258
- update: args.update,
259
- delete: args.delete,
260
- });
261
- }
262
-
263
- server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
264
- const { name, arguments: args } = request.params;
265
-
266
- try {
267
- let result: any;
268
-
269
- switch (name) {
270
- case "search":
271
- result = await handleSearchMemories(args);
272
- break;
273
- case "fetch_items":
274
- result = await handleFetch(args);
275
- break;
276
- case "view_spaces":
277
- result = await handleViewSpaces();
278
- break;
279
- case "view_topics":
280
- result = await handleViewTopics(args);
281
- break;
282
- case "view_topic":
283
- result = await handleViewTopic(args);
284
- break;
285
- case "create_space":
286
- result = await handleCreateSpace(args);
287
- break;
288
- case "view_space":
289
- result = await handleViewSpace(args);
290
- break;
291
- case "start":
292
- result = await handleStart(args);
293
- break;
294
- case "update_space":
295
- result = await handleUpdateSpace(args);
296
- break;
297
- default:
298
- throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
299
- }
300
-
301
- // Extract response field for Layer 2 compressed tools, otherwise stringify full result
302
- let responseText: string;
303
- if (
304
- result &&
305
- typeof result === "object" &&
306
- "response" in result &&
307
- typeof result.response === "string"
308
- ) {
309
- // Tool has Layer 2 compression - use the formatted response field
310
- responseText = result.response;
311
- } else {
312
- // Standard tool - return full JSON
313
- responseText = JSON.stringify(result, null, 2);
314
- }
315
-
316
- // Add version warning to response if outdated
317
- if (latestVersion && latestVersion !== CURRENT_VERSION) {
318
- const warning = `\n\n UPDATE AVAILABLE: MCP Server v${latestVersion} is available (you're on v${CURRENT_VERSION}). Update with: npx @intangle/mcp-server@latest`;
319
- responseText += warning;
320
- }
321
-
322
- return {
323
- content: [{ type: "text", text: responseText }],
324
- };
325
- } catch (error) {
326
- throw new McpError(
327
- ErrorCode.InternalError,
328
- `Error executing tool ${name}: ${error instanceof Error ? error.message : String(error)}`,
329
- );
330
- }
331
- });
332
-
333
- async function main() {
334
- const transport = new StdioServerTransport();
335
- await server.connect(transport);
336
- log("Server connected to transport");
337
- // Client info is captured on-demand in ensureClientInfo() before first API call
338
- }
339
-
340
- main().catch((err) => {
341
- log(`Error in main: ${err}`);
342
- process.exit(1);
343
- });
344
-
40
+ // Load environment variables from .env and .env.local
41
+ config({ quiet: true })
42
+ config({ path: ".env.local", quiet: true })
43
+
44
+ // Base URL for API calls to Next.js app
45
+ const API_BASE_URL = process.env.NEXT_APP_URL || "https://intangle.app"
46
+ const MCP_API_KEY = process.env.MCP_API_KEY
47
+
48
+ log(`CWD: ${process.cwd()}`)
49
+ log(`Has API Key: ${!!MCP_API_KEY}`)
50
+ log(`Node Version: ${process.version}`)
51
+
52
+ if (!MCP_API_KEY) {
53
+ log("Error: MCP_API_KEY environment variable is required")
54
+ console.error("Error: MCP_API_KEY environment variable is required")
55
+ console.error(
56
+ "Please set your Intangle API key in the Claude Desktop configuration"
57
+ )
58
+ process.exit(1)
59
+ }
60
+
61
+ console.error("Intangle MCP Server starting - connecting to", API_BASE_URL)
62
+
63
+ // Version checking - automatically read from package.json
64
+ const __dirname = dirname(fileURLToPath(import.meta.url))
65
+ let packageJson
66
+ try {
67
+ packageJson = JSON.parse(
68
+ readFileSync(join(__dirname, "package.json"), "utf-8")
69
+ )
70
+ } catch {
71
+ packageJson = JSON.parse(
72
+ readFileSync(join(__dirname, "../package.json"), "utf-8")
73
+ )
74
+ }
75
+ const CURRENT_VERSION = packageJson.version
76
+ let latestVersion: string | null = null
77
+ let versionCheckDone = false
78
+
79
+ async function checkVersion() {
80
+ if (versionCheckDone) return
81
+
82
+ try {
83
+ const response = await fetch(
84
+ "https://registry.npmjs.org/@intangle/mcp-server/latest"
85
+ )
86
+ const data = (await response.json()) as { version: string }
87
+ latestVersion = data.version
88
+ versionCheckDone = true
89
+
90
+ if (latestVersion && latestVersion !== CURRENT_VERSION) {
91
+ console.error("\n UPDATE AVAILABLE ")
92
+ console.error(`Current version: ${CURRENT_VERSION}`)
93
+ console.error(`Latest version: ${latestVersion}`)
94
+ console.error("Update with: npx @intangle/mcp-server@latest\n")
95
+ } else {
96
+ console.error(`✓ Running latest version (${CURRENT_VERSION})`)
97
+ }
98
+ } catch (error) {
99
+ // Silently fail version check - don't block startup
100
+ versionCheckDone = true
101
+ }
102
+ }
103
+
104
+ // Check version on startup (non-blocking)
105
+ checkVersion()
106
+
107
+ // Helper to ensure client info is captured (called before API requests)
108
+ function ensureClientInfo() {
109
+ if (!mcpClientName) {
110
+ const clientInfo = server.getClientVersion()
111
+ if (clientInfo) {
112
+ mcpClientName = clientInfo.name
113
+ mcpClientVersion = clientInfo.version
114
+ log(
115
+ `Client identified (on-demand): ${mcpClientName} v${mcpClientVersion}`
116
+ )
117
+ }
118
+ }
119
+ }
120
+
121
+ async function makeApiCall(endpoint: string, data: any) {
122
+ // Ensure we have client info before making requests
123
+ ensureClientInfo()
124
+
125
+ // Build headers with client info if available
126
+ const headers: Record<string, string> = {
127
+ "Content-Type": "application/json",
128
+ Authorization: `Bearer ${MCP_API_KEY}`,
129
+ "User-Agent": mcpClientName
130
+ ? `${mcpClientName}/${mcpClientVersion || "unknown"} (mcp-stdio)`
131
+ : "MCP-Client-Stdio/1.1.2 (mcp)",
132
+ }
133
+
134
+ // Add explicit client info headers for backend processing
135
+ if (mcpClientName) {
136
+ headers["X-MCP-Client-Name"] = mcpClientName
137
+ }
138
+ if (mcpClientVersion) {
139
+ headers["X-MCP-Client-Version"] = mcpClientVersion
140
+ }
141
+
142
+ const response = await fetch(`${API_BASE_URL}/api/mcp/${endpoint}`, {
143
+ method: "POST",
144
+ headers,
145
+ body: JSON.stringify(data),
146
+ })
147
+
148
+ if (!response.ok) {
149
+ throw new Error(
150
+ `API call failed: ${response.status} ${response.statusText}`
151
+ )
152
+ }
153
+
154
+ return response.json()
155
+ }
156
+
157
+ const server = new Server(
158
+ {
159
+ name: "intangle-context",
160
+ version: "1.0.0",
161
+ vendor: "Intangle",
162
+ icon: "https://intangle.tools/icon.png",
163
+ },
164
+ {
165
+ capabilities: {
166
+ tools: {},
167
+ },
168
+ }
169
+ )
170
+
171
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
172
+ tools: TOOLS,
173
+ }))
174
+
175
+ async function handleSearchContext(args: any) {
176
+ const { space_id, query, topics } = args as {
177
+ space_id: string
178
+ query: string
179
+ topics?: string[]
180
+ }
181
+
182
+ // Require space_id
183
+ if (!space_id) {
184
+ throw new Error(
185
+ "space_id is required. Use list_spaces to see available options."
186
+ )
187
+ }
188
+
189
+ return makeApiCall("search-memories", {
190
+ space_id,
191
+ space_ids: [space_id], // Convert to array for backend compatibility
192
+ query,
193
+ topics,
194
+ })
195
+ }
196
+
197
+ async function handleFetch(args: any) {
198
+ const { id, ids } = args as { id?: string; ids?: string[] }
199
+
200
+ return makeApiCall("fetch", { id, ids })
201
+ }
202
+
203
+ async function handleViewSpaces() {
204
+ return makeApiCall("list-spaces", {})
205
+ }
206
+
207
+ async function handleViewTopics(args: any) {
208
+ const { space_id } = args as { space_id: string }
209
+ if (!space_id) {
210
+ throw new Error(
211
+ "space_id is required. Use view_spaces to see available options."
212
+ )
213
+ }
214
+ return makeApiCall("view-topics", { space_id })
215
+ }
216
+
217
+ async function handleViewTopic(args: any) {
218
+ const { topic_id } = args as { topic_id: string }
219
+ if (!topic_id) {
220
+ throw new Error("topic_id is required. Use view_topics to get valid IDs.")
221
+ }
222
+ // Pass directly to API; ensure API expects 'topic_id' or adjust if it expects 'id'
223
+ // Usually view-topic endpoint takes 'topic_id' or 'id'
224
+ return makeApiCall("view-topic", { topic_id })
225
+ }
226
+
227
+ async function handleCreateSpace(args: any) {
228
+ return makeApiCall("create-space", args)
229
+ }
230
+
231
+ async function handleViewSpace(args: any) {
232
+ const { space_id } = args as { space_id: string }
233
+ return makeApiCall("view-space", { space_id })
234
+ }
235
+
236
+ async function handleStart(args: any) {
237
+ const { space_id } = args as { space_id: string }
238
+ return makeApiCall("start", { space_id })
239
+ }
240
+
241
+ async function handleUpdateSpace(args: any) {
242
+ if (!args.space_id) {
243
+ throw new Error(
244
+ "space_id is required. Use view_spaces to see available options."
245
+ )
246
+ }
247
+
248
+ if (!args.add && !args.update && !args.delete) {
249
+ throw new Error(
250
+ "At least one operation (add, update, delete) must be provided"
251
+ )
252
+ }
253
+
254
+ // Pass through to API with new structure
255
+ return makeApiCall("update-memory", {
256
+ space_id: args.space_id,
257
+ add: args.add,
258
+ update: args.update,
259
+ delete: args.delete,
260
+ })
261
+ }
262
+
263
+ server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
264
+ const { name, arguments: args } = request.params
265
+
266
+ try {
267
+ let result: any
268
+
269
+ switch (name) {
270
+ case "search":
271
+ result = await handleSearchContext(args)
272
+ break
273
+ case "fetch_items":
274
+ result = await handleFetch(args)
275
+ break
276
+ case "view_spaces":
277
+ result = await handleViewSpaces()
278
+ break
279
+ case "view_topics":
280
+ result = await handleViewTopics(args)
281
+ break
282
+ case "view_topic":
283
+ result = await handleViewTopic(args)
284
+ break
285
+ case "create_space":
286
+ result = await handleCreateSpace(args)
287
+ break
288
+ case "view_space":
289
+ result = await handleViewSpace(args)
290
+ break
291
+ case "start":
292
+ result = await handleStart(args)
293
+ break
294
+ case "update_space":
295
+ result = await handleUpdateSpace(args)
296
+ break
297
+ default:
298
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`)
299
+ }
300
+
301
+ // Extract response field for Layer 2 compressed tools, otherwise stringify full result
302
+ let responseText: string
303
+ if (
304
+ result &&
305
+ typeof result === "object" &&
306
+ "response" in result &&
307
+ typeof result.response === "string"
308
+ ) {
309
+ // Tool has Layer 2 compression - use the formatted response field
310
+ responseText = result.response
311
+ } else {
312
+ // Standard tool - return full JSON
313
+ responseText = JSON.stringify(result, null, 2)
314
+ }
315
+
316
+ // Add version warning to response if outdated
317
+ if (latestVersion && latestVersion !== CURRENT_VERSION) {
318
+ const warning = `\n\n UPDATE AVAILABLE: MCP Server v${latestVersion} is available (you're on v${CURRENT_VERSION}). Update with: npx @intangle/mcp-server@latest`
319
+ responseText += warning
320
+ }
321
+
322
+ return {
323
+ content: [{ type: "text", text: responseText }],
324
+ }
325
+ } catch (error) {
326
+ throw new McpError(
327
+ ErrorCode.InternalError,
328
+ `Error executing tool ${name}: ${error instanceof Error ? error.message : String(error)}`
329
+ )
330
+ }
331
+ })
332
+
333
+ async function main() {
334
+ const transport = new StdioServerTransport()
335
+ await server.connect(transport)
336
+ log("Server connected to transport")
337
+ // Client info is captured on-demand in ensureClientInfo() before first API call
338
+ }
339
+
340
+ main().catch((err) => {
341
+ log(`Error in main: ${err}`)
342
+ process.exit(1)
343
+ })
345
344
  } catch (err) {
346
- log(`Fatal startup error: ${err}`);
347
- process.exit(1);
345
+ log(`Fatal startup error: ${err}`)
346
+ process.exit(1)
348
347
  }
package/package.json CHANGED
@@ -1,53 +1,53 @@
1
1
  {
2
- "name": "@intangle/mcp-server",
3
- "version": "2.1.7",
4
- "description": "Model Context Protocol server for Intangle - AI memory that persists across conversations",
5
- "main": "dist/index.js",
6
- "type": "module",
7
- "scripts": {
8
- "start": "node dist/index.js",
9
- "dev": "tsx watch index.ts",
10
- "prebuild": "cp ../web/src/app/api/mcp-remote/tool-definitions.ts ./tool-definitions.ts",
11
- "build": "tsc",
12
- "lint": "biome check .",
13
- "lint:fix": "biome check --fix .",
14
- "prepublishOnly": "npm run build"
15
- },
16
- "bin": {
17
- "intangle-mcp": "dist/index.js"
18
- },
19
- "keywords": [
20
- "mcp",
21
- "model-context-protocol",
22
- "claude",
23
- "claude-code",
24
- "ai",
25
- "memory",
26
- "knowledge-management",
27
- "intangle",
28
- "claude-desktop",
29
- "anthropic"
30
- ],
31
- "author": "Intangle",
32
- "license": "MIT",
33
- "repository": {
34
- "type": "git",
35
- "url": "git+https://github.com/intangle/mcp-server.git"
36
- },
37
- "homepage": "https://intangle.app",
38
- "engines": {
39
- "node": ">=18.0.0"
40
- },
41
- "dependencies": {
42
- "@modelcontextprotocol/sdk": "^1.0.0",
43
- "dotenv": "^17.2.0",
44
- "node-fetch": "^3.3.2"
45
- },
46
- "devDependencies": {
47
- "@biomejs/biome": "^1.9.4",
48
- "@types/node": "^22.0.0",
49
- "@types/node-fetch": "^2.6.12",
50
- "tsx": "^4.0.0",
51
- "typescript": "^5.0.0"
52
- }
2
+ "name": "@intangle/mcp-server",
3
+ "version": "2.1.9",
4
+ "description": "Model Context Protocol server for Intangle - AI context that persists across conversations",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "node dist/index.js",
9
+ "dev": "tsx watch index.ts",
10
+ "prebuild": "cp ../web/src/app/api/mcp-remote/tool-definitions.ts ./tool-definitions.ts",
11
+ "build": "tsc",
12
+ "lint": "biome check .",
13
+ "lint:fix": "biome check --fix .",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "bin": {
17
+ "intangle-mcp": "dist/index.js"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "model-context-protocol",
22
+ "claude",
23
+ "claude-code",
24
+ "ai",
25
+ "context",
26
+ "knowledge-management",
27
+ "intangle",
28
+ "claude-desktop",
29
+ "anthropic"
30
+ ],
31
+ "author": "Intangle",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/intangle/mcp-server.git"
36
+ },
37
+ "homepage": "https://intangle.app",
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ },
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.0.0",
43
+ "dotenv": "^17.2.0",
44
+ "node-fetch": "^3.3.2"
45
+ },
46
+ "devDependencies": {
47
+ "@biomejs/biome": "^1.9.4",
48
+ "@types/node": "^22.0.0",
49
+ "@types/node-fetch": "^2.6.12",
50
+ "tsx": "^4.0.0",
51
+ "typescript": "^5.0.0"
52
+ }
53
53
  }
@@ -52,7 +52,7 @@ export const TOOLS = [
52
52
  name: "view_topic",
53
53
  title: "View Topic",
54
54
  description:
55
- "View all memories, tasks, and processes tagged with a specific topic. Perfect for exploring a topic area or following up on topics from the start briefing.",
55
+ "View all context, tasks, and processes tagged with a specific topic. Perfect for exploring a topic area or following up on topics from the start briefing.",
56
56
  inputSchema: {
57
57
  type: "object",
58
58
  properties: {
@@ -128,7 +128,7 @@ export const TOOLS = [
128
128
  type: "array",
129
129
  items: { type: "string" },
130
130
  description:
131
- "Array of keywords for start tool keywords in this NEW space. These keywords help steer what context gets loaded when running 'start' for this space. Examples: ['fitness', 'recipes', 'travel planning'], ['client work', 'meetings', 'proposals'], ['TypeScript', 'React', 'API design']. They act as search terms to prioritize relevant memories.",
131
+ "Array of keywords for start tool keywords in this NEW space. These keywords help steer what context gets loaded when running 'start' for this space. Examples: ['fitness', 'recipes', 'travel planning'], ['client work', 'meetings', 'proposals'], ['TypeScript', 'React', 'API design']. They act as search terms to prioritize relevant context.",
132
132
  },
133
133
  startup_preferences: {
134
134
  type: "string",
@@ -170,7 +170,7 @@ export const TOOLS = [
170
170
  },
171
171
  add: {
172
172
  type: "object",
173
- description: "Add new items to memory with automatic intelligent classification and topic suggestion",
173
+ description: "Add new items to context with automatic intelligent classification and topic suggestion",
174
174
  properties: {
175
175
  items: {
176
176
  type: "array",
package/tsconfig.json CHANGED
@@ -15,4 +15,4 @@
15
15
  },
16
16
  "include": ["**/*.ts"],
17
17
  "exclude": ["node_modules", "dist"]
18
- }
18
+ }