@mcp-ts/sdk 1.3.7 → 1.3.10

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.
Files changed (66) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +397 -404
  3. package/dist/adapters/agui-middleware.js.map +1 -1
  4. package/dist/adapters/agui-middleware.mjs.map +1 -1
  5. package/dist/bin/mcp-ts.js +0 -0
  6. package/dist/bin/mcp-ts.js.map +1 -1
  7. package/dist/bin/mcp-ts.mjs +0 -0
  8. package/dist/bin/mcp-ts.mjs.map +1 -1
  9. package/dist/client/index.js.map +1 -1
  10. package/dist/client/index.mjs.map +1 -1
  11. package/dist/client/react.d.mts +10 -28
  12. package/dist/client/react.d.ts +10 -28
  13. package/dist/client/react.js +101 -52
  14. package/dist/client/react.js.map +1 -1
  15. package/dist/client/react.mjs +102 -53
  16. package/dist/client/react.mjs.map +1 -1
  17. package/dist/client/vue.js.map +1 -1
  18. package/dist/client/vue.mjs.map +1 -1
  19. package/dist/index.js +78 -6
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +73 -6
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/server/index.js +78 -6
  24. package/dist/server/index.js.map +1 -1
  25. package/dist/server/index.mjs +73 -6
  26. package/dist/server/index.mjs.map +1 -1
  27. package/dist/shared/index.js.map +1 -1
  28. package/dist/shared/index.mjs.map +1 -1
  29. package/package.json +185 -185
  30. package/src/adapters/agui-middleware.ts +382 -382
  31. package/src/bin/mcp-ts.ts +102 -102
  32. package/src/client/core/app-host.ts +417 -417
  33. package/src/client/core/sse-client.ts +371 -371
  34. package/src/client/core/types.ts +31 -31
  35. package/src/client/index.ts +27 -27
  36. package/src/client/react/index.ts +20 -16
  37. package/src/client/react/use-app-host.ts +74 -73
  38. package/src/client/react/use-mcp-apps.tsx +224 -214
  39. package/src/client/react/use-mcp.ts +669 -641
  40. package/src/client/vue/index.ts +10 -10
  41. package/src/client/vue/use-mcp.ts +617 -617
  42. package/src/index.ts +11 -11
  43. package/src/server/handlers/nextjs-handler.ts +204 -204
  44. package/src/server/handlers/sse-handler.ts +631 -631
  45. package/src/server/index.ts +57 -57
  46. package/src/server/mcp/multi-session-client.ts +228 -228
  47. package/src/server/mcp/oauth-client.ts +1188 -1188
  48. package/src/server/mcp/storage-oauth-provider.ts +272 -272
  49. package/src/server/storage/crypto.ts +92 -0
  50. package/src/server/storage/file-backend.ts +157 -157
  51. package/src/server/storage/index.ts +176 -176
  52. package/src/server/storage/memory-backend.ts +123 -123
  53. package/src/server/storage/redis-backend.ts +276 -276
  54. package/src/server/storage/redis.ts +160 -160
  55. package/src/server/storage/sqlite-backend.ts +182 -182
  56. package/src/server/storage/supabase-backend.ts +229 -228
  57. package/src/server/storage/types.ts +116 -116
  58. package/src/shared/constants.ts +29 -29
  59. package/src/shared/errors.ts +133 -133
  60. package/src/shared/event-routing.ts +28 -28
  61. package/src/shared/events.ts +180 -180
  62. package/src/shared/index.ts +75 -75
  63. package/src/shared/tool-utils.ts +61 -61
  64. package/src/shared/types.ts +282 -282
  65. package/src/shared/utils.ts +38 -38
  66. package/supabase/migrations/20260330195700_install_mcp_sessions.sql +84 -84
@@ -1,182 +1,182 @@
1
- import type { Database } from 'better-sqlite3';
2
- import { StorageBackend, SessionData } from './types.js'; // Ensure .js extension
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import { generateSessionId } from '../../shared/utils.js';
6
-
7
- export interface SqliteStorageOptions {
8
- path?: string;
9
- table?: string;
10
- }
11
-
12
- export class SqliteStorage implements StorageBackend {
13
- private db: Database | null = null;
14
- private table: string;
15
- private initialized = false;
16
- private dbPath: string;
17
-
18
- constructor(options: SqliteStorageOptions = {}) {
19
- this.dbPath = options.path || './sessions.db';
20
- this.table = options.table || 'mcp_sessions';
21
- }
22
-
23
- async init(): Promise<void> {
24
- if (this.initialized) return;
25
-
26
- try {
27
- // Dynamic import for peer dependency
28
- const DatabaseConstructor = (await import('better-sqlite3')).default;
29
-
30
- // Ensure directory exists
31
- const dir = path.dirname(this.dbPath);
32
- if (!fs.existsSync(dir)) {
33
- fs.mkdirSync(dir, { recursive: true });
34
- }
35
-
36
- this.db = new DatabaseConstructor(this.dbPath);
37
- this.db.exec(`
38
- CREATE TABLE IF NOT EXISTS ${this.table} (
39
- sessionId TEXT PRIMARY KEY,
40
- identity TEXT NOT NULL,
41
- data TEXT NOT NULL,
42
- expiresAt INTEGER
43
- );
44
- CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
45
- `);
46
-
47
- this.initialized = true;
48
- console.log(`[mcp-ts][Storage] SQLite: ✓ database at ${this.dbPath} verified.`);
49
- } catch (error: any) {
50
- if (error.code === 'MODULE_NOT_FOUND' || error.message?.includes('better-sqlite3')) {
51
- throw new Error(
52
- 'better-sqlite3 is not installed. Please install it with: npm install better-sqlite3'
53
- );
54
- }
55
- throw error;
56
- }
57
- }
58
-
59
- private ensureInitialized() {
60
- if (!this.initialized) {
61
- throw new Error('SqliteStorage not initialized. Call init() first.');
62
- }
63
- }
64
-
65
- generateSessionId(): string {
66
- return generateSessionId();
67
- }
68
-
69
- async createSession(session: SessionData, ttl?: number): Promise<void> {
70
- this.ensureInitialized();
71
- const { sessionId, identity } = session;
72
-
73
- if (!sessionId || !identity) {
74
- throw new Error('identity and sessionId required');
75
- }
76
-
77
- const expiresAt = ttl ? Date.now() + ttl * 1000 : null;
78
-
79
- try {
80
- const stmt = this.db!.prepare(
81
- `INSERT INTO ${this.table} (sessionId, identity, data, expiresAt) VALUES (?, ?, ?, ?)`
82
- );
83
- stmt.run(sessionId, identity, JSON.stringify(session), expiresAt);
84
- } catch (error: any) {
85
- if (error.code === 'SQLITE_CONSTRAINT_PRIMARYKEY') {
86
- throw new Error(`Session ${sessionId} already exists`);
87
- }
88
- throw error;
89
- }
90
- }
91
-
92
- async updateSession(identity: string, sessionId: string, data: Partial<SessionData>, ttl?: number): Promise<void> {
93
- this.ensureInitialized();
94
- if (!sessionId || !identity) {
95
- throw new Error('identity and sessionId required');
96
- }
97
-
98
- const currentSession = await this.getSession(identity, sessionId);
99
- if (!currentSession) {
100
- throw new Error(`Session ${sessionId} not found for identity ${identity}`);
101
- }
102
-
103
- const updatedSession = { ...currentSession, ...data };
104
- const expiresAt = ttl ? Date.now() + ttl * 1000 : null;
105
-
106
- const stmt = this.db!.prepare(
107
- `UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND identity = ?`
108
- );
109
-
110
- stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId, identity);
111
- }
112
-
113
- async getSession(identity: string, sessionId: string): Promise<SessionData | null> {
114
- this.ensureInitialized();
115
-
116
- const stmt = this.db!.prepare(
117
- `SELECT data FROM ${this.table} WHERE sessionId = ? AND identity = ?`
118
- );
119
- const row = stmt.get(sessionId, identity) as { data: string } | undefined;
120
-
121
- if (!row) return null;
122
- return JSON.parse(row.data) as SessionData;
123
- }
124
-
125
- async getIdentitySessionsData(identity: string): Promise<SessionData[]> {
126
- this.ensureInitialized();
127
-
128
- const stmt = this.db!.prepare(
129
- `SELECT data FROM ${this.table} WHERE identity = ?`
130
- );
131
- const rows = stmt.all(identity) as { data: string }[];
132
-
133
- return rows.map(row => JSON.parse(row.data) as SessionData);
134
- }
135
-
136
- async getIdentityMcpSessions(identity: string): Promise<string[]> {
137
- this.ensureInitialized();
138
-
139
- const stmt = this.db!.prepare(
140
- `SELECT sessionId FROM ${this.table} WHERE identity = ?`
141
- );
142
- const rows = stmt.all(identity) as { sessionId: string }[];
143
-
144
- return rows.map(row => row.sessionId);
145
- }
146
-
147
- async removeSession(identity: string, sessionId: string): Promise<void> {
148
- this.ensureInitialized();
149
- const stmt = this.db!.prepare(
150
- `DELETE FROM ${this.table} WHERE sessionId = ? AND identity = ?`
151
- );
152
- stmt.run(sessionId, identity);
153
- }
154
-
155
- async getAllSessionIds(): Promise<string[]> {
156
- this.ensureInitialized();
157
- const stmt = this.db!.prepare(`SELECT sessionId FROM ${this.table}`);
158
- const rows = stmt.all() as { sessionId: string }[];
159
- return rows.map(row => row.sessionId);
160
- }
161
-
162
- async clearAll(): Promise<void> {
163
- this.ensureInitialized();
164
- const stmt = this.db!.prepare(`DELETE FROM ${this.table}`);
165
- stmt.run();
166
- }
167
-
168
- async cleanupExpiredSessions(): Promise<void> {
169
- this.ensureInitialized();
170
- const now = Date.now();
171
- const stmt = this.db!.prepare(
172
- `DELETE FROM ${this.table} WHERE expiresAt IS NOT NULL AND expiresAt < ?`
173
- );
174
- stmt.run(now);
175
- }
176
-
177
- async disconnect(): Promise<void> {
178
- if (this.db) {
179
- this.db.close();
180
- }
181
- }
182
- }
1
+ import type { Database } from 'better-sqlite3';
2
+ import { StorageBackend, SessionData } from './types.js'; // Ensure .js extension
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import { generateSessionId } from '../../shared/utils.js';
6
+
7
+ export interface SqliteStorageOptions {
8
+ path?: string;
9
+ table?: string;
10
+ }
11
+
12
+ export class SqliteStorage implements StorageBackend {
13
+ private db: Database | null = null;
14
+ private table: string;
15
+ private initialized = false;
16
+ private dbPath: string;
17
+
18
+ constructor(options: SqliteStorageOptions = {}) {
19
+ this.dbPath = options.path || './sessions.db';
20
+ this.table = options.table || 'mcp_sessions';
21
+ }
22
+
23
+ async init(): Promise<void> {
24
+ if (this.initialized) return;
25
+
26
+ try {
27
+ // Dynamic import for peer dependency
28
+ const DatabaseConstructor = (await import('better-sqlite3')).default;
29
+
30
+ // Ensure directory exists
31
+ const dir = path.dirname(this.dbPath);
32
+ if (!fs.existsSync(dir)) {
33
+ fs.mkdirSync(dir, { recursive: true });
34
+ }
35
+
36
+ this.db = new DatabaseConstructor(this.dbPath);
37
+ this.db.exec(`
38
+ CREATE TABLE IF NOT EXISTS ${this.table} (
39
+ sessionId TEXT PRIMARY KEY,
40
+ identity TEXT NOT NULL,
41
+ data TEXT NOT NULL,
42
+ expiresAt INTEGER
43
+ );
44
+ CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
45
+ `);
46
+
47
+ this.initialized = true;
48
+ console.log(`[mcp-ts][Storage] SQLite: ✓ database at ${this.dbPath} verified.`);
49
+ } catch (error: any) {
50
+ if (error.code === 'MODULE_NOT_FOUND' || error.message?.includes('better-sqlite3')) {
51
+ throw new Error(
52
+ 'better-sqlite3 is not installed. Please install it with: npm install better-sqlite3'
53
+ );
54
+ }
55
+ throw error;
56
+ }
57
+ }
58
+
59
+ private ensureInitialized() {
60
+ if (!this.initialized) {
61
+ throw new Error('SqliteStorage not initialized. Call init() first.');
62
+ }
63
+ }
64
+
65
+ generateSessionId(): string {
66
+ return generateSessionId();
67
+ }
68
+
69
+ async createSession(session: SessionData, ttl?: number): Promise<void> {
70
+ this.ensureInitialized();
71
+ const { sessionId, identity } = session;
72
+
73
+ if (!sessionId || !identity) {
74
+ throw new Error('identity and sessionId required');
75
+ }
76
+
77
+ const expiresAt = ttl ? Date.now() + ttl * 1000 : null;
78
+
79
+ try {
80
+ const stmt = this.db!.prepare(
81
+ `INSERT INTO ${this.table} (sessionId, identity, data, expiresAt) VALUES (?, ?, ?, ?)`
82
+ );
83
+ stmt.run(sessionId, identity, JSON.stringify(session), expiresAt);
84
+ } catch (error: any) {
85
+ if (error.code === 'SQLITE_CONSTRAINT_PRIMARYKEY') {
86
+ throw new Error(`Session ${sessionId} already exists`);
87
+ }
88
+ throw error;
89
+ }
90
+ }
91
+
92
+ async updateSession(identity: string, sessionId: string, data: Partial<SessionData>, ttl?: number): Promise<void> {
93
+ this.ensureInitialized();
94
+ if (!sessionId || !identity) {
95
+ throw new Error('identity and sessionId required');
96
+ }
97
+
98
+ const currentSession = await this.getSession(identity, sessionId);
99
+ if (!currentSession) {
100
+ throw new Error(`Session ${sessionId} not found for identity ${identity}`);
101
+ }
102
+
103
+ const updatedSession = { ...currentSession, ...data };
104
+ const expiresAt = ttl ? Date.now() + ttl * 1000 : null;
105
+
106
+ const stmt = this.db!.prepare(
107
+ `UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND identity = ?`
108
+ );
109
+
110
+ stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId, identity);
111
+ }
112
+
113
+ async getSession(identity: string, sessionId: string): Promise<SessionData | null> {
114
+ this.ensureInitialized();
115
+
116
+ const stmt = this.db!.prepare(
117
+ `SELECT data FROM ${this.table} WHERE sessionId = ? AND identity = ?`
118
+ );
119
+ const row = stmt.get(sessionId, identity) as { data: string } | undefined;
120
+
121
+ if (!row) return null;
122
+ return JSON.parse(row.data) as SessionData;
123
+ }
124
+
125
+ async getIdentitySessionsData(identity: string): Promise<SessionData[]> {
126
+ this.ensureInitialized();
127
+
128
+ const stmt = this.db!.prepare(
129
+ `SELECT data FROM ${this.table} WHERE identity = ?`
130
+ );
131
+ const rows = stmt.all(identity) as { data: string }[];
132
+
133
+ return rows.map(row => JSON.parse(row.data) as SessionData);
134
+ }
135
+
136
+ async getIdentityMcpSessions(identity: string): Promise<string[]> {
137
+ this.ensureInitialized();
138
+
139
+ const stmt = this.db!.prepare(
140
+ `SELECT sessionId FROM ${this.table} WHERE identity = ?`
141
+ );
142
+ const rows = stmt.all(identity) as { sessionId: string }[];
143
+
144
+ return rows.map(row => row.sessionId);
145
+ }
146
+
147
+ async removeSession(identity: string, sessionId: string): Promise<void> {
148
+ this.ensureInitialized();
149
+ const stmt = this.db!.prepare(
150
+ `DELETE FROM ${this.table} WHERE sessionId = ? AND identity = ?`
151
+ );
152
+ stmt.run(sessionId, identity);
153
+ }
154
+
155
+ async getAllSessionIds(): Promise<string[]> {
156
+ this.ensureInitialized();
157
+ const stmt = this.db!.prepare(`SELECT sessionId FROM ${this.table}`);
158
+ const rows = stmt.all() as { sessionId: string }[];
159
+ return rows.map(row => row.sessionId);
160
+ }
161
+
162
+ async clearAll(): Promise<void> {
163
+ this.ensureInitialized();
164
+ const stmt = this.db!.prepare(`DELETE FROM ${this.table}`);
165
+ stmt.run();
166
+ }
167
+
168
+ async cleanupExpiredSessions(): Promise<void> {
169
+ this.ensureInitialized();
170
+ const now = Date.now();
171
+ const stmt = this.db!.prepare(
172
+ `DELETE FROM ${this.table} WHERE expiresAt IS NOT NULL AND expiresAt < ?`
173
+ );
174
+ stmt.run(now);
175
+ }
176
+
177
+ async disconnect(): Promise<void> {
178
+ if (this.db) {
179
+ this.db.close();
180
+ }
181
+ }
182
+ }