@mcp-ts/sdk 1.6.1 → 2.0.0
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 +12 -6
- package/dist/adapters/agui-adapter.d.mts +3 -3
- package/dist/adapters/agui-adapter.d.ts +3 -3
- package/dist/adapters/agui-adapter.js +4 -5
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +4 -5
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +3 -3
- package/dist/adapters/agui-middleware.d.ts +3 -3
- package/dist/adapters/ai-adapter.d.mts +9 -3
- package/dist/adapters/ai-adapter.d.ts +9 -3
- package/dist/adapters/ai-adapter.js +20 -6
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs +20 -6
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +3 -3
- package/dist/adapters/langchain-adapter.d.ts +3 -3
- package/dist/adapters/langchain-adapter.js +9 -6
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +9 -6
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.js +5 -1
- package/dist/adapters/mastra-adapter.js.map +1 -1
- package/dist/adapters/mastra-adapter.mjs +5 -1
- package/dist/adapters/mastra-adapter.mjs.map +1 -1
- package/dist/bin/mcp-ts.js +7 -1
- package/dist/bin/mcp-ts.js.map +1 -1
- package/dist/bin/mcp-ts.mjs +7 -1
- package/dist/bin/mcp-ts.mjs.map +1 -1
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +9 -13
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +9 -13
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +7 -7
- package/dist/client/react.d.ts +7 -7
- package/dist/client/react.js +111 -63
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +111 -63
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +7 -7
- package/dist/client/vue.d.ts +7 -7
- package/dist/client/vue.js +14 -18
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +14 -18
- package/dist/client/vue.mjs.map +1 -1
- package/dist/{index-DhA-OEAe.d.ts → index-C9gvpxy5.d.ts} +5 -5
- package/dist/{index-bFL4ZF2N.d.mts → index-eaH14_5u.d.mts} +5 -5
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +616 -370
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +615 -370
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-CHE8QpVE.d.ts → multi-session-client-BYtguGJm.d.ts} +22 -22
- package/dist/{multi-session-client-CQsRbxYI.d.mts → multi-session-client-DYNe6az3.d.mts} +22 -22
- package/dist/server/index.d.mts +31 -34
- package/dist/server/index.d.ts +31 -34
- package/dist/server/index.js +531 -256
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +530 -256
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +5 -5
- package/dist/shared/index.d.ts +5 -5
- package/dist/shared/index.js +76 -101
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +76 -101
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{tool-router-Dh2804tM.d.ts → tool-router-Ddtybmr0.d.ts} +71 -73
- package/dist/{tool-router-BVaV1udm.d.mts → tool-router-Dnd6IOKC.d.mts} +71 -73
- package/dist/{types-rIuN1CQi.d.mts → types-BCAG20P6.d.mts} +4 -4
- package/dist/{types-rIuN1CQi.d.ts → types-BCAG20P6.d.ts} +4 -4
- package/dist/{utils-0qmYrqoa.d.mts → utils-DELRKQPU.d.mts} +1 -1
- package/dist/{utils-0qmYrqoa.d.ts → utils-DELRKQPU.d.ts} +1 -1
- package/migrations/neon/20260513010000_install_mcp_sessions.sql +69 -0
- package/migrations/neon/20260513020000_add_session_cleanup_cron.sql +35 -0
- package/{supabase/migrations → migrations/supabase}/20260330195700_install_mcp_sessions.sql +7 -9
- package/package.json +14 -5
- package/src/adapters/ai-adapter.ts +30 -1
- package/src/adapters/langchain-adapter.ts +6 -2
- package/src/adapters/mastra-adapter.ts +6 -2
- package/src/bin/mcp-ts.ts +8 -1
- package/src/client/core/app-host.ts +1 -1
- package/src/client/core/sse-client.ts +12 -14
- package/src/client/core/types.ts +1 -1
- package/src/client/react/oauth-popup.tsx +111 -51
- package/src/client/react/use-mcp-apps.tsx +1 -1
- package/src/client/react/use-mcp.ts +11 -11
- package/src/client/vue/use-mcp.ts +10 -10
- package/src/server/handlers/nextjs-handler.ts +18 -15
- package/src/server/handlers/sse-handler.ts +29 -29
- package/src/server/index.ts +1 -1
- package/src/server/mcp/multi-session-client.ts +17 -17
- package/src/server/mcp/oauth-client.ts +37 -37
- package/src/server/mcp/storage-oauth-provider.ts +17 -17
- package/src/server/storage/file-backend.ts +25 -25
- package/src/server/storage/index.ts +67 -10
- package/src/server/storage/memory-backend.ts +34 -34
- package/src/server/storage/neon-backend.ts +281 -0
- package/src/server/storage/redis-backend.ts +64 -64
- package/src/server/storage/sqlite-backend.ts +33 -33
- package/src/server/storage/supabase-backend.ts +23 -24
- package/src/server/storage/types.ts +18 -21
- package/src/shared/errors.ts +1 -1
- package/src/shared/index.ts +1 -2
- package/src/shared/meta-tools.ts +4 -6
- package/src/shared/schema-compressor.ts +2 -42
- package/src/shared/tool-index.ts +89 -84
- package/src/shared/tool-router.ts +0 -24
- package/src/shared/types.ts +4 -4
- /package/{supabase/migrations → migrations/supabase}/20260421010000_add_session_cleanup_cron.sql +0 -0
|
@@ -5,15 +5,15 @@ import type {
|
|
|
5
5
|
OAuthClientInformationMixed,
|
|
6
6
|
} from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
7
7
|
|
|
8
|
-
export interface
|
|
8
|
+
export interface Session {
|
|
9
9
|
sessionId: string;
|
|
10
10
|
serverId?: string; // Database server ID for mapping
|
|
11
11
|
serverName?: string;
|
|
12
12
|
serverUrl: string;
|
|
13
|
-
transportType: 'sse' | '
|
|
13
|
+
transportType: 'sse' | 'streamable-http';
|
|
14
14
|
callbackUrl: string;
|
|
15
15
|
createdAt: number;
|
|
16
|
-
|
|
16
|
+
userId: string;
|
|
17
17
|
headers?: Record<string, string>;
|
|
18
18
|
/**
|
|
19
19
|
* Session status marker used for TTL transitions:
|
|
@@ -36,15 +36,15 @@ export interface SetClientOptions {
|
|
|
36
36
|
client?: MCPClient;
|
|
37
37
|
serverUrl?: string;
|
|
38
38
|
callbackUrl?: string;
|
|
39
|
-
transportType?: 'sse' | '
|
|
40
|
-
|
|
39
|
+
transportType?: 'sse' | 'streamable-http';
|
|
40
|
+
userId?: string;
|
|
41
41
|
headers?: Record<string, string>;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* Interface for MCP
|
|
45
|
+
* Interface for MCP session stores.
|
|
46
46
|
*/
|
|
47
|
-
export interface
|
|
47
|
+
export interface SessionStore {
|
|
48
48
|
/**
|
|
49
49
|
* Optional initialization (e.g., database connection)
|
|
50
50
|
*/
|
|
@@ -55,49 +55,46 @@ export interface StorageBackend {
|
|
|
55
55
|
*/
|
|
56
56
|
generateSessionId(): string;
|
|
57
57
|
|
|
58
|
-
/**
|
|
59
|
-
* Stores or updates a session
|
|
60
|
-
*/
|
|
61
58
|
/**
|
|
62
59
|
* Creates a new session. Throws if session already exists.
|
|
63
60
|
* @param session - Session data to create
|
|
64
61
|
* @param ttl - Optional TTL in seconds (defaults to backend's default)
|
|
65
62
|
*/
|
|
66
|
-
|
|
63
|
+
create(session: Session, ttl?: number): Promise<void>;
|
|
67
64
|
|
|
68
65
|
/**
|
|
69
66
|
* Updates an existing session with partial data. Throws if session does not exist.
|
|
70
|
-
* @param
|
|
67
|
+
* @param userId - User identifier
|
|
71
68
|
* @param sessionId - Session identifier
|
|
72
69
|
* @param data - Partial session data to update
|
|
73
70
|
* @param ttl - Optional TTL in seconds (defaults to backend's default)
|
|
74
71
|
*/
|
|
75
|
-
|
|
72
|
+
update(userId: string, sessionId: string, data: Partial<Session>, ttl?: number): Promise<void>;
|
|
76
73
|
|
|
77
74
|
/**
|
|
78
75
|
* Retrieves a session
|
|
79
76
|
*/
|
|
80
|
-
|
|
77
|
+
get(userId: string, sessionId: string): Promise<Session | null>;
|
|
81
78
|
|
|
82
79
|
/**
|
|
83
|
-
* Gets full session data for all
|
|
80
|
+
* Gets full session data for all sessions owned by a user
|
|
84
81
|
*/
|
|
85
|
-
|
|
82
|
+
list(userId: string): Promise<Session[]>;
|
|
86
83
|
|
|
87
84
|
/**
|
|
88
85
|
* Removes a session
|
|
89
86
|
*/
|
|
90
|
-
|
|
87
|
+
delete(userId: string, sessionId: string): Promise<void>;
|
|
91
88
|
|
|
92
89
|
/**
|
|
93
|
-
* Gets all
|
|
90
|
+
* Gets all session IDs owned by a user
|
|
94
91
|
*/
|
|
95
|
-
|
|
92
|
+
listIds(userId: string): Promise<string[]>;
|
|
96
93
|
|
|
97
94
|
/**
|
|
98
95
|
* Gets all session IDs across all users (Admin)
|
|
99
96
|
*/
|
|
100
|
-
|
|
97
|
+
listAllIds(): Promise<string[]>;
|
|
101
98
|
|
|
102
99
|
/**
|
|
103
100
|
* Clears all sessions (Admin)
|
|
@@ -107,7 +104,7 @@ export interface StorageBackend {
|
|
|
107
104
|
/**
|
|
108
105
|
* Clean up expired sessions
|
|
109
106
|
*/
|
|
110
|
-
|
|
107
|
+
cleanupExpired(): Promise<void>;
|
|
111
108
|
|
|
112
109
|
/**
|
|
113
110
|
* Disconnect from storage backend
|
package/src/shared/errors.ts
CHANGED
|
@@ -123,7 +123,7 @@ export class ToolExecutionError extends McpError {
|
|
|
123
123
|
*/
|
|
124
124
|
export const RpcErrorCodes = {
|
|
125
125
|
EXECUTION_ERROR: 'EXECUTION_ERROR',
|
|
126
|
-
|
|
126
|
+
MISSING_USER_ID: 'MISSING_USER_ID',
|
|
127
127
|
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
128
128
|
NO_CONNECTION: 'NO_CONNECTION',
|
|
129
129
|
UNKNOWN_METHOD: 'UNKNOWN_METHOD',
|
package/src/shared/index.ts
CHANGED
|
@@ -52,7 +52,7 @@ export type {
|
|
|
52
52
|
SessionListResult,
|
|
53
53
|
ConnectResult,
|
|
54
54
|
DisconnectResult,
|
|
55
|
-
|
|
55
|
+
GetSessionResult,
|
|
56
56
|
FinishAuthResult,
|
|
57
57
|
ListToolsRpcResult,
|
|
58
58
|
ListPromptsResult,
|
|
@@ -98,7 +98,6 @@ export {
|
|
|
98
98
|
export {
|
|
99
99
|
SchemaCompressor,
|
|
100
100
|
type CompactTool,
|
|
101
|
-
type CompressionStats,
|
|
102
101
|
} from './schema-compressor.js';
|
|
103
102
|
|
|
104
103
|
export {
|
package/src/shared/meta-tools.ts
CHANGED
|
@@ -337,7 +337,7 @@ export async function executeMetaTool(
|
|
|
337
337
|
|
|
338
338
|
if (found.length > 0) {
|
|
339
339
|
lines.push(...found.map((t, i) =>
|
|
340
|
-
`${i + 1}. **${t.name}** (
|
|
340
|
+
`${i + 1}. **${t.name}** (serverName: ${t.serverName}, serverId: ${t.serverId})\n ${t.description}`
|
|
341
341
|
));
|
|
342
342
|
}
|
|
343
343
|
|
|
@@ -380,7 +380,7 @@ export async function executeMetaTool(
|
|
|
380
380
|
: servers
|
|
381
381
|
.map(
|
|
382
382
|
(server, i) =>
|
|
383
|
-
`${i + 1}. **${server.serverName}** (serverId: ${server.serverId}
|
|
383
|
+
`${i + 1}. **${server.serverName}** (serverId: ${server.serverId})\n` +
|
|
384
384
|
` Tool count: ${server.toolCount}`
|
|
385
385
|
)
|
|
386
386
|
.join('\n');
|
|
@@ -518,14 +518,12 @@ function formatToolSummaries(
|
|
|
518
518
|
description: string;
|
|
519
519
|
serverName: string;
|
|
520
520
|
serverId: string;
|
|
521
|
-
estimatedTokens: number;
|
|
522
521
|
}>
|
|
523
522
|
): string[] {
|
|
524
523
|
return tools.map(
|
|
525
524
|
(t, i) =>
|
|
526
|
-
`${i + 1}. **${t.name}** (
|
|
527
|
-
` ${t.description}
|
|
528
|
-
` Estimated tokens: ${t.estimatedTokens}`
|
|
525
|
+
`${i + 1}. **${t.name}** (serverName: ${t.serverName}, serverId: ${t.serverId})\n` +
|
|
526
|
+
` ${t.description}`
|
|
529
527
|
);
|
|
530
528
|
}
|
|
531
529
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SchemaCompressor — Utilities for
|
|
2
|
+
* SchemaCompressor — Utilities for compact tool representations.
|
|
3
3
|
*
|
|
4
4
|
* Provides compact representations of tools (name + description only,
|
|
5
|
-
* no inputSchema)
|
|
5
|
+
* no inputSchema).
|
|
6
6
|
*
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
-
import { ToolIndex } from './tool-index.js';
|
|
12
11
|
|
|
13
12
|
// ---------------------------------------------------------------------------
|
|
14
13
|
// Types
|
|
@@ -28,17 +27,6 @@ export interface CompactTool {
|
|
|
28
27
|
parameterHint?: string;
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
export interface CompressionStats {
|
|
32
|
-
/** Estimated tokens for the *full* tool list. */
|
|
33
|
-
fullTokens: number;
|
|
34
|
-
/** Estimated tokens for the *compact* tool list. */
|
|
35
|
-
compactTokens: number;
|
|
36
|
-
/** Absolute token savings. */
|
|
37
|
-
savedTokens: number;
|
|
38
|
-
/** Percentage savings as a human-readable string, e.g. "82.3%". */
|
|
39
|
-
savingsPercent: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
30
|
// ---------------------------------------------------------------------------
|
|
43
31
|
// SchemaCompressor
|
|
44
32
|
// ---------------------------------------------------------------------------
|
|
@@ -93,32 +81,4 @@ export class SchemaCompressor {
|
|
|
93
81
|
const limited = options?.maxTools ? tools.slice(0, options.maxTools) : tools;
|
|
94
82
|
return limited.map((t) => SchemaCompressor.toCompact(t));
|
|
95
83
|
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Estimate token savings from using compact vs full tool schemas.
|
|
99
|
-
*/
|
|
100
|
-
static estimateSavings(tools: Tool[]): CompressionStats {
|
|
101
|
-
let fullTokens = 0;
|
|
102
|
-
let compactTokens = 0;
|
|
103
|
-
|
|
104
|
-
for (const tool of tools) {
|
|
105
|
-
fullTokens += ToolIndex.estimateTokens(tool);
|
|
106
|
-
|
|
107
|
-
// Compact form: name + description + parameterHint
|
|
108
|
-
const compact = SchemaCompressor.toCompact(tool);
|
|
109
|
-
const text = [compact.name, compact.description ?? '', compact.parameterHint ?? ''].join(' ');
|
|
110
|
-
// Simple estimation for compact: ~4 chars per token for plain text
|
|
111
|
-
compactTokens += Math.ceil(text.length / 4);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const saved = fullTokens - compactTokens;
|
|
115
|
-
const pct = fullTokens > 0 ? ((saved / fullTokens) * 100).toFixed(1) : '0.0';
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
fullTokens,
|
|
119
|
-
compactTokens,
|
|
120
|
-
savedTokens: saved,
|
|
121
|
-
savingsPercent: `${pct}%`,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
84
|
}
|
package/src/shared/tool-index.ts
CHANGED
|
@@ -28,8 +28,6 @@ export interface ToolSummary {
|
|
|
28
28
|
serverId: string;
|
|
29
29
|
/** Session the tool belongs to */
|
|
30
30
|
sessionId: string;
|
|
31
|
-
/** Estimated token cost of the full inputSchema */
|
|
32
|
-
estimatedTokens: number;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
/** Server-level summary derived from indexed tools. */
|
|
@@ -106,41 +104,6 @@ export interface ToolIndexOptions {
|
|
|
106
104
|
keywordWeight?: number;
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
// Token Estimation
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Character-class weights for accurate-ish token estimation without a real
|
|
115
|
-
* tokenizer. Empirically calibrated against cl100k_base on typical JSON
|
|
116
|
-
* Schema payloads.
|
|
117
|
-
*
|
|
118
|
-
* | Char class | Approx chars per token |
|
|
119
|
-
* |--------------------|------------------------|
|
|
120
|
-
* | Whitespace / punct | 1–2 |
|
|
121
|
-
* | English words | ~4 |
|
|
122
|
-
* | JSON keys/values | ~3.5 |
|
|
123
|
-
*
|
|
124
|
-
* We walk the string once and accumulate a weighted character count, then
|
|
125
|
-
* divide by a calibrated divisor.
|
|
126
|
-
*/
|
|
127
|
-
const CALIBRATION_DIVISOR = 3.6;
|
|
128
|
-
|
|
129
|
-
function classifyChar(ch: string): number {
|
|
130
|
-
const code = ch.charCodeAt(0);
|
|
131
|
-
// whitespace / common JSON structural chars → high token density
|
|
132
|
-
if (code <= 0x20 || ch === '{' || ch === '}' || ch === '[' || ch === ']' || ch === ':' || ch === ',') return 1.0;
|
|
133
|
-
// digits and symbols
|
|
134
|
-
if (code >= 0x21 && code <= 0x2f) return 1.5;
|
|
135
|
-
if (code >= 0x30 && code <= 0x39) return 2.0;
|
|
136
|
-
// uppercase (often JSON keys)
|
|
137
|
-
if (code >= 0x41 && code <= 0x5a) return 3.5;
|
|
138
|
-
// lowercase (natural language in descriptions)
|
|
139
|
-
if (code >= 0x61 && code <= 0x7a) return 4.0;
|
|
140
|
-
// everything else (unicode, emojis, etc.)
|
|
141
|
-
return 2.5;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
107
|
// ---------------------------------------------------------------------------
|
|
145
108
|
// ToolIndex
|
|
146
109
|
// ---------------------------------------------------------------------------
|
|
@@ -170,9 +133,6 @@ export class ToolIndex {
|
|
|
170
133
|
/** BM25: average document length across the entire index. */
|
|
171
134
|
private avgDocLength = 0;
|
|
172
135
|
|
|
173
|
-
/** Cached total estimated token cost across all indexed tools. */
|
|
174
|
-
private totalTokenCost = 0;
|
|
175
|
-
|
|
176
136
|
private options: Required<ToolIndexOptions>;
|
|
177
137
|
|
|
178
138
|
constructor(options: ToolIndexOptions = {}) {
|
|
@@ -199,7 +159,6 @@ export class ToolIndex {
|
|
|
199
159
|
this.embeddings.clear();
|
|
200
160
|
this.docLengths.clear();
|
|
201
161
|
this.avgDocLength = 0;
|
|
202
|
-
this.totalTokenCost = 0;
|
|
203
162
|
|
|
204
163
|
// 1. Populate tool map + search text
|
|
205
164
|
const allTokenSets: Map<string, Set<string>> = new Map();
|
|
@@ -212,21 +171,19 @@ export class ToolIndex {
|
|
|
212
171
|
this.tools.set(tool.name, []);
|
|
213
172
|
}
|
|
214
173
|
this.tools.get(tool.name)!.push(tool);
|
|
215
|
-
const estimatedTokens = ToolIndex.estimateTokens(tool);
|
|
216
174
|
this.toolSummaries.set(docKey, {
|
|
217
175
|
name: tool.name,
|
|
218
176
|
description: tool.description ?? '',
|
|
219
177
|
serverName: tool.serverName,
|
|
220
178
|
serverId: tool.serverId,
|
|
221
179
|
sessionId: tool.sessionId,
|
|
222
|
-
estimatedTokens,
|
|
223
180
|
});
|
|
224
|
-
this.totalTokenCost += estimatedTokens;
|
|
225
181
|
|
|
226
|
-
const
|
|
182
|
+
const rawText = this.buildSearchableText(tool);
|
|
183
|
+
const text = rawText.toLowerCase();
|
|
227
184
|
this.searchTexts.set(docKey, text);
|
|
228
185
|
|
|
229
|
-
const tokens = this.tokenize(
|
|
186
|
+
const tokens = this.tokenize(rawText);
|
|
230
187
|
const tf = new Map<string, number>();
|
|
231
188
|
const uniqueTokens = new Set<string>();
|
|
232
189
|
|
|
@@ -578,60 +535,107 @@ export class ToolIndex {
|
|
|
578
535
|
return count;
|
|
579
536
|
}
|
|
580
537
|
|
|
581
|
-
/** Total estimated token cost of all indexed tool schemas. */
|
|
582
|
-
getTotalTokenCost(): number {
|
|
583
|
-
return this.totalTokenCost;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
538
|
// -----------------------------------------------------------------------
|
|
587
|
-
//
|
|
539
|
+
// Internals
|
|
588
540
|
// -----------------------------------------------------------------------
|
|
589
541
|
|
|
590
|
-
/**
|
|
591
|
-
|
|
592
|
-
*
|
|
593
|
-
* Uses character-class weighted counting calibrated against cl100k_base.
|
|
594
|
-
* Accuracy is typically within ±10% for JSON Schema payloads.
|
|
595
|
-
*/
|
|
596
|
-
static estimateTokens(tool: Tool): number {
|
|
542
|
+
/** Build a single searchable string from tool metadata. */
|
|
543
|
+
private buildSearchableText(tool: Tool): string {
|
|
597
544
|
const parts: string[] = [tool.name];
|
|
598
545
|
if (tool.description) parts.push(tool.description);
|
|
599
|
-
if (tool.inputSchema) parts.push(JSON.stringify(tool.inputSchema));
|
|
600
546
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
for (let i = 0; i < text.length; i++) {
|
|
605
|
-
weightedLen += 1 / classifyChar(text[i]);
|
|
547
|
+
if (tool.inputSchema && typeof tool.inputSchema === 'object') {
|
|
548
|
+
this.collectSchemaSearchText(tool.inputSchema, parts);
|
|
606
549
|
}
|
|
607
550
|
|
|
608
|
-
return
|
|
551
|
+
return parts.join(' ');
|
|
609
552
|
}
|
|
610
553
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
554
|
+
/** Recursively collect JSON Schema argument names and descriptions. */
|
|
555
|
+
private collectSchemaSearchText(
|
|
556
|
+
schema: unknown,
|
|
557
|
+
parts: string[],
|
|
558
|
+
seen = new WeakSet<object>()
|
|
559
|
+
): void {
|
|
560
|
+
if (!schema || typeof schema !== 'object') return;
|
|
561
|
+
if (seen.has(schema)) return;
|
|
562
|
+
seen.add(schema);
|
|
563
|
+
|
|
564
|
+
if (Array.isArray(schema)) {
|
|
565
|
+
for (const item of schema) {
|
|
566
|
+
this.collectSchemaSearchText(item, parts, seen);
|
|
567
|
+
}
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
614
570
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
if (tool.description) parts.push(tool.description);
|
|
571
|
+
const schemaObject = schema as Record<string, unknown>;
|
|
572
|
+
this.pushStringValue(schemaObject.description, parts);
|
|
573
|
+
this.pushStringValue(schemaObject.title, parts);
|
|
619
574
|
|
|
620
|
-
|
|
621
|
-
if (
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
575
|
+
const properties = schemaObject.properties;
|
|
576
|
+
if (properties && typeof properties === 'object' && !Array.isArray(properties)) {
|
|
577
|
+
for (const [propertyName, propertySchema] of Object.entries(properties)) {
|
|
578
|
+
parts.push(propertyName);
|
|
579
|
+
this.collectSchemaSearchText(propertySchema, parts, seen);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const patternProperties = schemaObject.patternProperties;
|
|
584
|
+
if (
|
|
585
|
+
patternProperties &&
|
|
586
|
+
typeof patternProperties === 'object' &&
|
|
587
|
+
!Array.isArray(patternProperties)
|
|
588
|
+
) {
|
|
589
|
+
for (const [propertyPattern, propertySchema] of Object.entries(patternProperties)) {
|
|
590
|
+
parts.push(propertyPattern);
|
|
591
|
+
this.collectSchemaSearchText(propertySchema, parts, seen);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const dependentSchemas = schemaObject.dependentSchemas;
|
|
596
|
+
if (
|
|
597
|
+
dependentSchemas &&
|
|
598
|
+
typeof dependentSchemas === 'object' &&
|
|
599
|
+
!Array.isArray(dependentSchemas)
|
|
600
|
+
) {
|
|
601
|
+
for (const [propertyName, dependentSchema] of Object.entries(dependentSchemas)) {
|
|
602
|
+
parts.push(propertyName);
|
|
603
|
+
this.collectSchemaSearchText(dependentSchema, parts, seen);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
for (const key of [
|
|
608
|
+
'items',
|
|
609
|
+
'additionalProperties',
|
|
610
|
+
'contains',
|
|
611
|
+
'propertyNames',
|
|
612
|
+
'if',
|
|
613
|
+
'then',
|
|
614
|
+
'else',
|
|
615
|
+
'not',
|
|
616
|
+
]) {
|
|
617
|
+
this.collectSchemaSearchText(schemaObject[key], parts, seen);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
for (const key of ['allOf', 'anyOf', 'oneOf', 'prefixItems']) {
|
|
621
|
+
this.collectSchemaSearchText(schemaObject[key], parts, seen);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
for (const key of ['$defs', 'definitions']) {
|
|
625
|
+
const definitions = schemaObject[key];
|
|
626
|
+
if (definitions && typeof definitions === 'object' && !Array.isArray(definitions)) {
|
|
627
|
+
for (const [definitionName, definitionSchema] of Object.entries(definitions)) {
|
|
628
|
+
parts.push(definitionName);
|
|
629
|
+
this.collectSchemaSearchText(definitionSchema, parts, seen);
|
|
630
630
|
}
|
|
631
631
|
}
|
|
632
632
|
}
|
|
633
|
+
}
|
|
633
634
|
|
|
634
|
-
|
|
635
|
+
private pushStringValue(value: unknown, parts: string[]): void {
|
|
636
|
+
if (typeof value === 'string' && value.trim()) {
|
|
637
|
+
parts.push(value);
|
|
638
|
+
}
|
|
635
639
|
}
|
|
636
640
|
|
|
637
641
|
private getDocumentKey(tool: IndexedTool): string {
|
|
@@ -662,6 +666,7 @@ export class ToolIndex {
|
|
|
662
666
|
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
663
667
|
// Split snake_case / kebab-case
|
|
664
668
|
.replace(/[_-]/g, ' ')
|
|
669
|
+
.toLowerCase()
|
|
665
670
|
// Remove non-alphanumeric (except spaces)
|
|
666
671
|
.replace(/[^a-z0-9\s]/g, '')
|
|
667
672
|
// Split on whitespace
|
|
@@ -290,30 +290,6 @@ export class ToolRouter {
|
|
|
290
290
|
return [...this.activeGroups];
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
-
// -----------------------------------------------------------------------
|
|
294
|
-
// Stats & Introspection
|
|
295
|
-
// -----------------------------------------------------------------------
|
|
296
|
-
|
|
297
|
-
/** Total token cost of all tools if loaded without filtering. */
|
|
298
|
-
getTotalTokenCost(): number {
|
|
299
|
-
return this.index.getTotalTokenCost();
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/** Estimate token cost of the currently filtered tool set. */
|
|
303
|
-
async getFilteredTokenCost(): Promise<number> {
|
|
304
|
-
const tools = await this.getFilteredTools();
|
|
305
|
-
let total = 0;
|
|
306
|
-
for (const tool of tools) {
|
|
307
|
-
total += ToolIndex.estimateTokens(tool);
|
|
308
|
-
}
|
|
309
|
-
return total;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/** Get compression stats showing savings from current strategy. */
|
|
313
|
-
getCompressionStats() {
|
|
314
|
-
return SchemaCompressor.estimateSavings(this.allTools);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
293
|
/** Number of total indexed tools. */
|
|
318
294
|
get totalToolCount(): number {
|
|
319
295
|
return this.allTools.length;
|
package/src/shared/types.ts
CHANGED
|
@@ -166,7 +166,7 @@ export type ToolInfo = {
|
|
|
166
166
|
};
|
|
167
167
|
|
|
168
168
|
// Transport type
|
|
169
|
-
export type TransportType = 'sse' | '
|
|
169
|
+
export type TransportType = 'sse' | 'streamable-http';
|
|
170
170
|
|
|
171
171
|
// SSE/RPC types
|
|
172
172
|
export type McpRpcMethod =
|
|
@@ -174,8 +174,8 @@ export type McpRpcMethod =
|
|
|
174
174
|
| 'disconnect'
|
|
175
175
|
| 'listTools'
|
|
176
176
|
| 'callTool'
|
|
177
|
-
| '
|
|
178
|
-
| '
|
|
177
|
+
| 'listSessions'
|
|
178
|
+
| 'getSession'
|
|
179
179
|
| 'finishAuth'
|
|
180
180
|
| 'listPrompts'
|
|
181
181
|
| 'getPrompt'
|
|
@@ -275,7 +275,7 @@ export interface DisconnectResult {
|
|
|
275
275
|
success: boolean;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
export interface
|
|
278
|
+
export interface GetSessionResult {
|
|
279
279
|
success: boolean;
|
|
280
280
|
toolCount: number;
|
|
281
281
|
}
|
/package/{supabase/migrations → migrations/supabase}/20260421010000_add_session_cleanup_cron.sql
RENAMED
|
File without changes
|