@mcp-ts/sdk 1.6.2 → 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 +15 -19
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +15 -19
- 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/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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Database } from 'better-sqlite3';
|
|
2
|
-
import {
|
|
2
|
+
import type { SessionStore, Session } from './types.js';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { generateSessionId } from '../../shared/utils.js';
|
|
@@ -9,7 +9,7 @@ export interface SqliteStorageOptions {
|
|
|
9
9
|
table?: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export class SqliteStorage implements
|
|
12
|
+
export class SqliteStorage implements SessionStore {
|
|
13
13
|
private db: Database | null = null;
|
|
14
14
|
private table: string;
|
|
15
15
|
private initialized = false;
|
|
@@ -37,11 +37,11 @@ export class SqliteStorage implements StorageBackend {
|
|
|
37
37
|
this.db.exec(`
|
|
38
38
|
CREATE TABLE IF NOT EXISTS ${this.table} (
|
|
39
39
|
sessionId TEXT PRIMARY KEY,
|
|
40
|
-
|
|
40
|
+
userId TEXT NOT NULL,
|
|
41
41
|
data TEXT NOT NULL,
|
|
42
42
|
expiresAt INTEGER
|
|
43
43
|
);
|
|
44
|
-
CREATE INDEX IF NOT EXISTS idx_${this.table}
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_${this.table}_userId ON ${this.table}(userId);
|
|
45
45
|
`);
|
|
46
46
|
|
|
47
47
|
this.initialized = true;
|
|
@@ -66,21 +66,21 @@ export class SqliteStorage implements StorageBackend {
|
|
|
66
66
|
return generateSessionId();
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
async
|
|
69
|
+
async create(session: Session, ttl?: number): Promise<void> {
|
|
70
70
|
this.ensureInitialized();
|
|
71
|
-
const { sessionId,
|
|
71
|
+
const { sessionId, userId } = session;
|
|
72
72
|
|
|
73
|
-
if (!sessionId || !
|
|
74
|
-
throw new Error('
|
|
73
|
+
if (!sessionId || !userId) {
|
|
74
|
+
throw new Error('userId and sessionId required');
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const expiresAt = ttl ? Date.now() + ttl * 1000 : null;
|
|
78
78
|
|
|
79
79
|
try {
|
|
80
80
|
const stmt = this.db!.prepare(
|
|
81
|
-
`INSERT INTO ${this.table} (sessionId,
|
|
81
|
+
`INSERT INTO ${this.table} (sessionId, userId, data, expiresAt) VALUES (?, ?, ?, ?)`
|
|
82
82
|
);
|
|
83
|
-
stmt.run(sessionId,
|
|
83
|
+
stmt.run(sessionId, userId, JSON.stringify(session), expiresAt);
|
|
84
84
|
} catch (error: any) {
|
|
85
85
|
if (error.code === 'SQLITE_CONSTRAINT_PRIMARYKEY') {
|
|
86
86
|
throw new Error(`Session ${sessionId} already exists`);
|
|
@@ -89,70 +89,70 @@ export class SqliteStorage implements StorageBackend {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
async
|
|
92
|
+
async update(userId: string, sessionId: string, data: Partial<Session>, ttl?: number): Promise<void> {
|
|
93
93
|
this.ensureInitialized();
|
|
94
|
-
if (!sessionId || !
|
|
95
|
-
throw new Error('
|
|
94
|
+
if (!sessionId || !userId) {
|
|
95
|
+
throw new Error('userId and sessionId required');
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
const currentSession = await this.
|
|
98
|
+
const currentSession = await this.get(userId, sessionId);
|
|
99
99
|
if (!currentSession) {
|
|
100
|
-
throw new Error(`Session ${sessionId} not found for
|
|
100
|
+
throw new Error(`Session ${sessionId} not found for userId ${userId}`);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
const updatedSession = { ...currentSession, ...data };
|
|
104
104
|
const expiresAt = ttl ? Date.now() + ttl * 1000 : null;
|
|
105
105
|
|
|
106
106
|
const stmt = this.db!.prepare(
|
|
107
|
-
`UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND
|
|
107
|
+
`UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND userId = ?`
|
|
108
108
|
);
|
|
109
109
|
|
|
110
|
-
stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId,
|
|
110
|
+
stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId, userId);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
async
|
|
113
|
+
async get(userId: string, sessionId: string): Promise<Session | null> {
|
|
114
114
|
this.ensureInitialized();
|
|
115
115
|
|
|
116
116
|
const stmt = this.db!.prepare(
|
|
117
|
-
`SELECT data FROM ${this.table} WHERE sessionId = ? AND
|
|
117
|
+
`SELECT data FROM ${this.table} WHERE sessionId = ? AND userId = ?`
|
|
118
118
|
);
|
|
119
|
-
const row = stmt.get(sessionId,
|
|
119
|
+
const row = stmt.get(sessionId, userId) as { data: string } | undefined;
|
|
120
120
|
|
|
121
121
|
if (!row) return null;
|
|
122
|
-
return JSON.parse(row.data) as
|
|
122
|
+
return JSON.parse(row.data) as Session;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
async
|
|
125
|
+
async list(userId: string): Promise<Session[]> {
|
|
126
126
|
this.ensureInitialized();
|
|
127
127
|
|
|
128
128
|
const stmt = this.db!.prepare(
|
|
129
|
-
`SELECT data FROM ${this.table} WHERE
|
|
129
|
+
`SELECT data FROM ${this.table} WHERE userId = ?`
|
|
130
130
|
);
|
|
131
|
-
const rows = stmt.all(
|
|
131
|
+
const rows = stmt.all(userId) as { data: string }[];
|
|
132
132
|
|
|
133
|
-
return rows.map(row => JSON.parse(row.data) as
|
|
133
|
+
return rows.map(row => JSON.parse(row.data) as Session);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
async
|
|
136
|
+
async listIds(userId: string): Promise<string[]> {
|
|
137
137
|
this.ensureInitialized();
|
|
138
138
|
|
|
139
139
|
const stmt = this.db!.prepare(
|
|
140
|
-
`SELECT sessionId FROM ${this.table} WHERE
|
|
140
|
+
`SELECT sessionId FROM ${this.table} WHERE userId = ?`
|
|
141
141
|
);
|
|
142
|
-
const rows = stmt.all(
|
|
142
|
+
const rows = stmt.all(userId) as { sessionId: string }[];
|
|
143
143
|
|
|
144
144
|
return rows.map(row => row.sessionId);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
async
|
|
147
|
+
async delete(userId: string, sessionId: string): Promise<void> {
|
|
148
148
|
this.ensureInitialized();
|
|
149
149
|
const stmt = this.db!.prepare(
|
|
150
|
-
`DELETE FROM ${this.table} WHERE sessionId = ? AND
|
|
150
|
+
`DELETE FROM ${this.table} WHERE sessionId = ? AND userId = ?`
|
|
151
151
|
);
|
|
152
|
-
stmt.run(sessionId,
|
|
152
|
+
stmt.run(sessionId, userId);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
async
|
|
155
|
+
async listAllIds(): Promise<string[]> {
|
|
156
156
|
this.ensureInitialized();
|
|
157
157
|
const stmt = this.db!.prepare(`SELECT sessionId FROM ${this.table}`);
|
|
158
158
|
const rows = stmt.all() as { sessionId: string }[];
|
|
@@ -165,7 +165,7 @@ export class SqliteStorage implements StorageBackend {
|
|
|
165
165
|
stmt.run();
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
async
|
|
168
|
+
async cleanupExpired(): Promise<void> {
|
|
169
169
|
this.ensureInitialized();
|
|
170
170
|
const now = Date.now();
|
|
171
171
|
const stmt = this.db!.prepare(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
-
import {
|
|
2
|
+
import type { SessionStore, Session } from './types.js';
|
|
3
3
|
import { SESSION_TTL_SECONDS } from '../../shared/constants.js';
|
|
4
4
|
import { generateSessionId } from '../../shared/utils.js';
|
|
5
5
|
import { encryptObject, decryptObject } from './crypto.js';
|
|
6
6
|
|
|
7
|
-
export class SupabaseStorageBackend implements
|
|
7
|
+
export class SupabaseStorageBackend implements SessionStore {
|
|
8
8
|
private readonly DEFAULT_TTL = SESSION_TTL_SECONDS;
|
|
9
9
|
|
|
10
10
|
constructor(private supabase: SupabaseClient) {}
|
|
@@ -34,7 +34,7 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
34
34
|
return generateSessionId();
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
private mapRowToSessionData(row: any):
|
|
37
|
+
private mapRowToSessionData(row: any): Session {
|
|
38
38
|
return {
|
|
39
39
|
sessionId: row.session_id,
|
|
40
40
|
serverId: row.server_id,
|
|
@@ -43,7 +43,7 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
43
43
|
transportType: row.transport_type,
|
|
44
44
|
callbackUrl: row.callback_url,
|
|
45
45
|
createdAt: new Date(row.created_at).getTime(),
|
|
46
|
-
|
|
46
|
+
userId: row.user_id,
|
|
47
47
|
headers: decryptObject(row.headers),
|
|
48
48
|
active: row.active,
|
|
49
49
|
clientInformation: row.client_information,
|
|
@@ -53,9 +53,9 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
async
|
|
57
|
-
const { sessionId,
|
|
58
|
-
if (!sessionId || !
|
|
56
|
+
async create(session: Session, ttl?: number): Promise<void> {
|
|
57
|
+
const { sessionId, userId } = session;
|
|
58
|
+
if (!sessionId || !userId) throw new Error('userId and sessionId required');
|
|
59
59
|
|
|
60
60
|
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
61
61
|
const expiresAt = new Date(Date.now() + effectiveTtl * 1000).toISOString();
|
|
@@ -64,14 +64,13 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
64
64
|
.from('mcp_sessions')
|
|
65
65
|
.insert({
|
|
66
66
|
session_id: sessionId,
|
|
67
|
-
user_id:
|
|
67
|
+
user_id: userId, // Maps user_id to userId to support RLS using auth.uid()
|
|
68
68
|
server_id: session.serverId,
|
|
69
69
|
server_name: session.serverName,
|
|
70
70
|
server_url: session.serverUrl,
|
|
71
71
|
transport_type: session.transportType,
|
|
72
72
|
callback_url: session.callbackUrl,
|
|
73
73
|
created_at: new Date(session.createdAt || Date.now()).toISOString(),
|
|
74
|
-
identity: identity,
|
|
75
74
|
headers: encryptObject(session.headers),
|
|
76
75
|
active: session.active ?? false,
|
|
77
76
|
client_information: session.clientInformation,
|
|
@@ -90,7 +89,7 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
async
|
|
92
|
+
async update(userId: string, sessionId: string, data: Partial<Session>, ttl?: number): Promise<void> {
|
|
94
93
|
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
95
94
|
const expiresAt = new Date(Date.now() + effectiveTtl * 1000).toISOString();
|
|
96
95
|
|
|
@@ -115,7 +114,7 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
115
114
|
const { data: updatedRows, error } = await this.supabase
|
|
116
115
|
.from('mcp_sessions')
|
|
117
116
|
.update(updateData)
|
|
118
|
-
.eq('
|
|
117
|
+
.eq('user_id', userId)
|
|
119
118
|
.eq('session_id', sessionId)
|
|
120
119
|
.select('id');
|
|
121
120
|
|
|
@@ -124,15 +123,15 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
if (!updatedRows || updatedRows.length === 0) {
|
|
127
|
-
throw new Error(`Session ${sessionId} not found for
|
|
126
|
+
throw new Error(`Session ${sessionId} not found for userId ${userId}`);
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
async
|
|
130
|
+
async get(userId: string, sessionId: string): Promise<Session | null> {
|
|
132
131
|
const { data, error } = await this.supabase
|
|
133
132
|
.from('mcp_sessions')
|
|
134
133
|
.select('*')
|
|
135
|
-
.eq('
|
|
134
|
+
.eq('user_id', userId)
|
|
136
135
|
.eq('session_id', sessionId)
|
|
137
136
|
.maybeSingle();
|
|
138
137
|
|
|
@@ -146,25 +145,25 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
146
145
|
return this.mapRowToSessionData(data);
|
|
147
146
|
}
|
|
148
147
|
|
|
149
|
-
async
|
|
148
|
+
async list(userId: string): Promise<Session[]> {
|
|
150
149
|
const { data, error } = await this.supabase
|
|
151
150
|
.from('mcp_sessions')
|
|
152
151
|
.select('*')
|
|
153
|
-
.eq('
|
|
152
|
+
.eq('user_id', userId);
|
|
154
153
|
|
|
155
154
|
if (error) {
|
|
156
|
-
console.error(`[SupabaseStorage] Failed to get session data for ${
|
|
155
|
+
console.error(`[SupabaseStorage] Failed to get session data for ${userId}:`, error);
|
|
157
156
|
return [];
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
return data.map(row => this.mapRowToSessionData(row));
|
|
161
160
|
}
|
|
162
161
|
|
|
163
|
-
async
|
|
162
|
+
async delete(userId: string, sessionId: string): Promise<void> {
|
|
164
163
|
const { error } = await this.supabase
|
|
165
164
|
.from('mcp_sessions')
|
|
166
165
|
.delete()
|
|
167
|
-
.eq('
|
|
166
|
+
.eq('user_id', userId)
|
|
168
167
|
.eq('session_id', sessionId);
|
|
169
168
|
|
|
170
169
|
if (error) {
|
|
@@ -172,21 +171,21 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
172
171
|
}
|
|
173
172
|
}
|
|
174
173
|
|
|
175
|
-
async
|
|
174
|
+
async listIds(userId: string): Promise<string[]> {
|
|
176
175
|
const { data, error } = await this.supabase
|
|
177
176
|
.from('mcp_sessions')
|
|
178
177
|
.select('session_id')
|
|
179
|
-
.eq('
|
|
178
|
+
.eq('user_id', userId);
|
|
180
179
|
|
|
181
180
|
if (error) {
|
|
182
|
-
console.error(`[SupabaseStorage] Failed to get sessions for ${
|
|
181
|
+
console.error(`[SupabaseStorage] Failed to get sessions for ${userId}:`, error);
|
|
183
182
|
return [];
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
return data.map(row => row.session_id);
|
|
187
186
|
}
|
|
188
187
|
|
|
189
|
-
async
|
|
188
|
+
async listAllIds(): Promise<string[]> {
|
|
190
189
|
const { data, error } = await this.supabase
|
|
191
190
|
.from('mcp_sessions')
|
|
192
191
|
.select('session_id');
|
|
@@ -211,7 +210,7 @@ export class SupabaseStorageBackend implements StorageBackend {
|
|
|
211
210
|
}
|
|
212
211
|
}
|
|
213
212
|
|
|
214
|
-
async
|
|
213
|
+
async cleanupExpired(): Promise<void> {
|
|
215
214
|
const { error } = await this.supabase
|
|
216
215
|
.from('mcp_sessions')
|
|
217
216
|
.delete()
|
|
@@ -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
|
}
|