@intangle/mcp-server 2.5.4 → 2.5.5
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/dist/index.js +80 -1
- package/dist/tool-definitions.js +4 -4
- package/index.ts +119 -7
- package/package.json +1 -1
- package/tool-definitions.ts +4 -4
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { dirname, join } from "path";
|
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
9
9
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
-
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { CallToolRequestSchema, ErrorCode, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
11
11
|
import { config } from "dotenv";
|
|
12
12
|
import fetch from "node-fetch";
|
|
13
13
|
import { TOOLS } from "./tool-definitions.js";
|
|
@@ -101,6 +101,13 @@ try {
|
|
|
101
101
|
}
|
|
102
102
|
return url.toString();
|
|
103
103
|
}
|
|
104
|
+
function buildRemoteApiUrl() {
|
|
105
|
+
const url = new URL("/api/mcp-remote", API_BASE_URL);
|
|
106
|
+
if (VERCEL_BYPASS_TOKEN) {
|
|
107
|
+
url.searchParams.set("x-vercel-protection-bypass", VERCEL_BYPASS_TOKEN);
|
|
108
|
+
}
|
|
109
|
+
return url.toString();
|
|
110
|
+
}
|
|
104
111
|
async function makeApiCall(endpoint, data, timeoutMs) {
|
|
105
112
|
// Ensure we have client info before making requests
|
|
106
113
|
ensureClientInfo();
|
|
@@ -160,6 +167,57 @@ try {
|
|
|
160
167
|
clearTimeout(timeoutId);
|
|
161
168
|
}
|
|
162
169
|
}
|
|
170
|
+
async function makeRemoteRpcCall(method, params) {
|
|
171
|
+
ensureClientInfo();
|
|
172
|
+
const headers = {
|
|
173
|
+
"Content-Type": "application/json",
|
|
174
|
+
Authorization: `Bearer ${MCP_API_KEY}`,
|
|
175
|
+
"User-Agent": mcpClientName
|
|
176
|
+
? `${mcpClientName}/${mcpClientVersion || "unknown"} (mcp-stdio)`
|
|
177
|
+
: "MCP-Client-Stdio/1.1.2 (mcp)",
|
|
178
|
+
};
|
|
179
|
+
if (mcpClientName) {
|
|
180
|
+
headers["X-MCP-Client-Name"] = mcpClientName;
|
|
181
|
+
}
|
|
182
|
+
if (mcpClientVersion) {
|
|
183
|
+
headers["X-MCP-Client-Version"] = mcpClientVersion;
|
|
184
|
+
}
|
|
185
|
+
if (VERCEL_BYPASS_TOKEN) {
|
|
186
|
+
headers["x-vercel-protection-bypass"] = VERCEL_BYPASS_TOKEN;
|
|
187
|
+
}
|
|
188
|
+
const requestId = Date.now();
|
|
189
|
+
const rpcBody = {
|
|
190
|
+
jsonrpc: "2.0",
|
|
191
|
+
id: requestId,
|
|
192
|
+
method,
|
|
193
|
+
params,
|
|
194
|
+
};
|
|
195
|
+
const response = await fetch(buildRemoteApiUrl(), {
|
|
196
|
+
method: "POST",
|
|
197
|
+
headers,
|
|
198
|
+
body: JSON.stringify(rpcBody),
|
|
199
|
+
});
|
|
200
|
+
const responseText = await response.text();
|
|
201
|
+
let responseJson = {};
|
|
202
|
+
try {
|
|
203
|
+
responseJson = responseText ? JSON.parse(responseText) : {};
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
throw new Error(`Failed to parse MCP remote ${method} response`);
|
|
207
|
+
}
|
|
208
|
+
if (!response.ok) {
|
|
209
|
+
const message = responseJson?.error?.message ||
|
|
210
|
+
responseJson?.message ||
|
|
211
|
+
`${response.status} ${response.statusText}`;
|
|
212
|
+
throw new Error(`MCP remote ${method} failed: ${message}`);
|
|
213
|
+
}
|
|
214
|
+
if (responseJson?.error) {
|
|
215
|
+
const code = responseJson.error.code;
|
|
216
|
+
const message = responseJson.error.message || "Unknown MCP remote error";
|
|
217
|
+
throw new Error(`MCP remote ${method} error (${code}): ${message}`);
|
|
218
|
+
}
|
|
219
|
+
return responseJson?.result ?? {};
|
|
220
|
+
}
|
|
163
221
|
const server = new Server({
|
|
164
222
|
name: "intangle-context",
|
|
165
223
|
version: "1.0.0",
|
|
@@ -171,12 +229,33 @@ try {
|
|
|
171
229
|
],
|
|
172
230
|
}, {
|
|
173
231
|
capabilities: {
|
|
232
|
+
resources: {},
|
|
174
233
|
tools: {},
|
|
175
234
|
},
|
|
176
235
|
});
|
|
177
236
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
178
237
|
tools: TOOLS,
|
|
179
238
|
}));
|
|
239
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
240
|
+
const result = await makeRemoteRpcCall("resources/list", {});
|
|
241
|
+
return {
|
|
242
|
+
resources: Array.isArray(result?.resources) ? result.resources : [],
|
|
243
|
+
nextCursor: typeof result?.nextCursor === "string" ? result.nextCursor : undefined,
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
247
|
+
const uri = request?.params?.uri;
|
|
248
|
+
if (!uri || typeof uri !== "string") {
|
|
249
|
+
throw new McpError(ErrorCode.InvalidParams, "uri is required for resources/read");
|
|
250
|
+
}
|
|
251
|
+
const result = await makeRemoteRpcCall("resources/read", { uri });
|
|
252
|
+
return {
|
|
253
|
+
contents: Array.isArray(result?.contents) ? result.contents : [],
|
|
254
|
+
};
|
|
255
|
+
});
|
|
256
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
|
|
257
|
+
resourceTemplates: [],
|
|
258
|
+
}));
|
|
180
259
|
async function handleSearchContext(args) {
|
|
181
260
|
const { space_id, query, topics } = args;
|
|
182
261
|
// Require space_id
|
package/dist/tool-definitions.js
CHANGED
|
@@ -312,7 +312,7 @@ export const TOOLS = [
|
|
|
312
312
|
{
|
|
313
313
|
name: "message",
|
|
314
314
|
title: "Message Assistant",
|
|
315
|
-
description: "Send a
|
|
315
|
+
description: "Primary orchestration tool. Send a request to the Intangle assistant and wait for one assistant turn to complete. Returns assistant text plus continuity IDs (`session_id`, `conversation_id`) so callers can continue the same thread reliably across turns.",
|
|
316
316
|
inputSchema: {
|
|
317
317
|
type: "object",
|
|
318
318
|
properties: {
|
|
@@ -330,11 +330,11 @@ export const TOOLS = [
|
|
|
330
330
|
},
|
|
331
331
|
conversation_id: {
|
|
332
332
|
type: "string",
|
|
333
|
-
description: "Optional existing conversation/chat summary ID to resume
|
|
333
|
+
description: "Optional existing conversation/chat summary ID to resume a specific conversation. If omitted, Intangle uses/creates the active conversation for this space."
|
|
334
334
|
},
|
|
335
335
|
session_id: {
|
|
336
336
|
type: "string",
|
|
337
|
-
description: "Optional runtime session ID to reuse across
|
|
337
|
+
description: "Optional runtime session ID to reuse across calls. Reuse the returned session_id for best continuity and lower warm-up overhead."
|
|
338
338
|
},
|
|
339
339
|
project_id: {
|
|
340
340
|
type: "string",
|
|
@@ -355,7 +355,7 @@ export const TOOLS = [
|
|
|
355
355
|
},
|
|
356
356
|
required: ["space_id", "content"]
|
|
357
357
|
}
|
|
358
|
-
}
|
|
358
|
+
}
|
|
359
359
|
// DISABLED: memory_action tool is broken and causing errors.
|
|
360
360
|
// Pending OHM protocol fix. Use update_space, search, or fetch_items instead.
|
|
361
361
|
// {
|
package/index.ts
CHANGED
|
@@ -12,8 +12,11 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
12
12
|
import {
|
|
13
13
|
CallToolRequestSchema,
|
|
14
14
|
ErrorCode,
|
|
15
|
+
ListResourceTemplatesRequestSchema,
|
|
16
|
+
ListResourcesRequestSchema,
|
|
15
17
|
ListToolsRequestSchema,
|
|
16
18
|
McpError,
|
|
19
|
+
ReadResourceRequestSchema,
|
|
17
20
|
} from "@modelcontextprotocol/sdk/types.js"
|
|
18
21
|
import { config } from "dotenv"
|
|
19
22
|
import fetch from "node-fetch"
|
|
@@ -134,6 +137,16 @@ try {
|
|
|
134
137
|
return url.toString()
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
function buildRemoteApiUrl() {
|
|
141
|
+
const url = new URL("/api/mcp-remote", API_BASE_URL)
|
|
142
|
+
|
|
143
|
+
if (VERCEL_BYPASS_TOKEN) {
|
|
144
|
+
url.searchParams.set("x-vercel-protection-bypass", VERCEL_BYPASS_TOKEN)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return url.toString()
|
|
148
|
+
}
|
|
149
|
+
|
|
137
150
|
async function makeApiCall(endpoint: string, data: any, timeoutMs?: number) {
|
|
138
151
|
// Ensure we have client info before making requests
|
|
139
152
|
ensureClientInfo()
|
|
@@ -187,7 +200,9 @@ try {
|
|
|
187
200
|
)
|
|
188
201
|
}
|
|
189
202
|
|
|
190
|
-
throw new Error(
|
|
203
|
+
throw new Error(
|
|
204
|
+
`API call failed: ${response.status} ${response.statusText}`
|
|
205
|
+
)
|
|
191
206
|
}
|
|
192
207
|
|
|
193
208
|
if (responseBody.trim() === "") {
|
|
@@ -207,6 +222,70 @@ try {
|
|
|
207
222
|
}
|
|
208
223
|
}
|
|
209
224
|
|
|
225
|
+
async function makeRemoteRpcCall(
|
|
226
|
+
method: string,
|
|
227
|
+
params: Record<string, unknown>
|
|
228
|
+
) {
|
|
229
|
+
ensureClientInfo()
|
|
230
|
+
|
|
231
|
+
const headers: Record<string, string> = {
|
|
232
|
+
"Content-Type": "application/json",
|
|
233
|
+
Authorization: `Bearer ${MCP_API_KEY}`,
|
|
234
|
+
"User-Agent": mcpClientName
|
|
235
|
+
? `${mcpClientName}/${mcpClientVersion || "unknown"} (mcp-stdio)`
|
|
236
|
+
: "MCP-Client-Stdio/1.1.2 (mcp)",
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (mcpClientName) {
|
|
240
|
+
headers["X-MCP-Client-Name"] = mcpClientName
|
|
241
|
+
}
|
|
242
|
+
if (mcpClientVersion) {
|
|
243
|
+
headers["X-MCP-Client-Version"] = mcpClientVersion
|
|
244
|
+
}
|
|
245
|
+
if (VERCEL_BYPASS_TOKEN) {
|
|
246
|
+
headers["x-vercel-protection-bypass"] = VERCEL_BYPASS_TOKEN
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const requestId = Date.now()
|
|
250
|
+
const rpcBody = {
|
|
251
|
+
jsonrpc: "2.0",
|
|
252
|
+
id: requestId,
|
|
253
|
+
method,
|
|
254
|
+
params,
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const response = await fetch(buildRemoteApiUrl(), {
|
|
258
|
+
method: "POST",
|
|
259
|
+
headers,
|
|
260
|
+
body: JSON.stringify(rpcBody),
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
const responseText = await response.text()
|
|
264
|
+
let responseJson: any = {}
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
responseJson = responseText ? JSON.parse(responseText) : {}
|
|
268
|
+
} catch {
|
|
269
|
+
throw new Error(`Failed to parse MCP remote ${method} response`)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (!response.ok) {
|
|
273
|
+
const message =
|
|
274
|
+
responseJson?.error?.message ||
|
|
275
|
+
responseJson?.message ||
|
|
276
|
+
`${response.status} ${response.statusText}`
|
|
277
|
+
throw new Error(`MCP remote ${method} failed: ${message}`)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (responseJson?.error) {
|
|
281
|
+
const code = responseJson.error.code
|
|
282
|
+
const message = responseJson.error.message || "Unknown MCP remote error"
|
|
283
|
+
throw new Error(`MCP remote ${method} error (${code}): ${message}`)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return responseJson?.result ?? {}
|
|
287
|
+
}
|
|
288
|
+
|
|
210
289
|
const server = new Server(
|
|
211
290
|
{
|
|
212
291
|
name: "intangle-context",
|
|
@@ -220,6 +299,7 @@ try {
|
|
|
220
299
|
},
|
|
221
300
|
{
|
|
222
301
|
capabilities: {
|
|
302
|
+
resources: {},
|
|
223
303
|
tools: {},
|
|
224
304
|
},
|
|
225
305
|
}
|
|
@@ -229,6 +309,34 @@ try {
|
|
|
229
309
|
tools: TOOLS,
|
|
230
310
|
}))
|
|
231
311
|
|
|
312
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
313
|
+
const result = await makeRemoteRpcCall("resources/list", {})
|
|
314
|
+
return {
|
|
315
|
+
resources: Array.isArray(result?.resources) ? result.resources : [],
|
|
316
|
+
nextCursor:
|
|
317
|
+
typeof result?.nextCursor === "string" ? result.nextCursor : undefined,
|
|
318
|
+
}
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request: any) => {
|
|
322
|
+
const uri = request?.params?.uri
|
|
323
|
+
if (!uri || typeof uri !== "string") {
|
|
324
|
+
throw new McpError(
|
|
325
|
+
ErrorCode.InvalidParams,
|
|
326
|
+
"uri is required for resources/read"
|
|
327
|
+
)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const result = await makeRemoteRpcCall("resources/read", { uri })
|
|
331
|
+
return {
|
|
332
|
+
contents: Array.isArray(result?.contents) ? result.contents : [],
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
|
|
337
|
+
resourceTemplates: [],
|
|
338
|
+
}))
|
|
339
|
+
|
|
232
340
|
async function handleSearchContext(args: any) {
|
|
233
341
|
const { space_id, query, topics } = args as {
|
|
234
342
|
space_id: string
|
|
@@ -278,11 +386,15 @@ try {
|
|
|
278
386
|
}
|
|
279
387
|
|
|
280
388
|
if (!project_id && !slug) {
|
|
281
|
-
throw new Error(
|
|
389
|
+
throw new Error(
|
|
390
|
+
"Either project_id or slug (with space_id) is required. Use view_projects to get valid IDs."
|
|
391
|
+
)
|
|
282
392
|
}
|
|
283
393
|
|
|
284
394
|
if (slug && !space_id) {
|
|
285
|
-
throw new Error(
|
|
395
|
+
throw new Error(
|
|
396
|
+
"space_id is required when using slug. Use view_spaces to see available options."
|
|
397
|
+
)
|
|
286
398
|
}
|
|
287
399
|
|
|
288
400
|
return makeApiCall("view-project", { project_id, space_id, slug })
|
|
@@ -310,9 +422,7 @@ try {
|
|
|
310
422
|
}
|
|
311
423
|
|
|
312
424
|
if (!args.add && !args.update && !args.delete) {
|
|
313
|
-
throw new Error(
|
|
314
|
-
"At least one operation must be provided"
|
|
315
|
-
)
|
|
425
|
+
throw new Error("At least one operation must be provided")
|
|
316
426
|
}
|
|
317
427
|
|
|
318
428
|
// Ensure all add items have a type field to prevent classification timeout
|
|
@@ -320,7 +430,9 @@ try {
|
|
|
320
430
|
if (add?.items && Array.isArray(add.items)) {
|
|
321
431
|
for (const item of add.items) {
|
|
322
432
|
if (!item.type) {
|
|
323
|
-
log(
|
|
433
|
+
log(
|
|
434
|
+
`WARNING: Item "${item.title}" missing type field, defaulting to "context" to prevent classification timeout`
|
|
435
|
+
)
|
|
324
436
|
item.type = "context"
|
|
325
437
|
}
|
|
326
438
|
}
|
package/package.json
CHANGED
package/tool-definitions.ts
CHANGED
|
@@ -346,7 +346,7 @@ export const TOOLS = [
|
|
|
346
346
|
name: "message",
|
|
347
347
|
title: "Message Assistant",
|
|
348
348
|
description:
|
|
349
|
-
"Send a
|
|
349
|
+
"Primary orchestration tool. Send a request to the Intangle assistant and wait for one assistant turn to complete. Returns assistant text plus continuity IDs (`session_id`, `conversation_id`) so callers can continue the same thread reliably across turns.",
|
|
350
350
|
inputSchema: {
|
|
351
351
|
type: "object",
|
|
352
352
|
properties: {
|
|
@@ -366,12 +366,12 @@ export const TOOLS = [
|
|
|
366
366
|
conversation_id: {
|
|
367
367
|
type: "string",
|
|
368
368
|
description:
|
|
369
|
-
"Optional existing conversation/chat summary ID to resume
|
|
369
|
+
"Optional existing conversation/chat summary ID to resume a specific conversation. If omitted, Intangle uses/creates the active conversation for this space."
|
|
370
370
|
},
|
|
371
371
|
session_id: {
|
|
372
372
|
type: "string",
|
|
373
373
|
description:
|
|
374
|
-
"Optional runtime session ID to reuse across
|
|
374
|
+
"Optional runtime session ID to reuse across calls. Reuse the returned session_id for best continuity and lower warm-up overhead."
|
|
375
375
|
},
|
|
376
376
|
project_id: {
|
|
377
377
|
type: "string",
|
|
@@ -394,7 +394,7 @@ export const TOOLS = [
|
|
|
394
394
|
},
|
|
395
395
|
required: ["space_id", "content"]
|
|
396
396
|
}
|
|
397
|
-
}
|
|
397
|
+
}
|
|
398
398
|
// DISABLED: memory_action tool is broken and causing errors.
|
|
399
399
|
// Pending OHM protocol fix. Use update_space, search, or fetch_items instead.
|
|
400
400
|
// {
|