@mcp-ts/sdk 1.3.7 → 1.3.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.
Files changed (61) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +398 -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 +2 -2
  12. package/dist/client/react.d.ts +2 -2
  13. package/dist/client/react.js +25 -2
  14. package/dist/client/react.js.map +1 -1
  15. package/dist/client/react.mjs +26 -3
  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.map +1 -1
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/server/index.js.map +1 -1
  22. package/dist/server/index.mjs.map +1 -1
  23. package/dist/shared/index.js.map +1 -1
  24. package/dist/shared/index.mjs.map +1 -1
  25. package/package.json +185 -185
  26. package/src/adapters/agui-middleware.ts +382 -382
  27. package/src/bin/mcp-ts.ts +102 -102
  28. package/src/client/core/app-host.ts +417 -417
  29. package/src/client/core/sse-client.ts +371 -371
  30. package/src/client/core/types.ts +31 -31
  31. package/src/client/index.ts +27 -27
  32. package/src/client/react/index.ts +16 -16
  33. package/src/client/react/use-app-host.ts +73 -73
  34. package/src/client/react/use-mcp-apps.tsx +247 -214
  35. package/src/client/react/use-mcp.ts +641 -641
  36. package/src/client/vue/index.ts +10 -10
  37. package/src/client/vue/use-mcp.ts +617 -617
  38. package/src/index.ts +11 -11
  39. package/src/server/handlers/nextjs-handler.ts +204 -204
  40. package/src/server/handlers/sse-handler.ts +631 -631
  41. package/src/server/index.ts +57 -57
  42. package/src/server/mcp/multi-session-client.ts +228 -228
  43. package/src/server/mcp/oauth-client.ts +1188 -1188
  44. package/src/server/mcp/storage-oauth-provider.ts +272 -272
  45. package/src/server/storage/file-backend.ts +157 -157
  46. package/src/server/storage/index.ts +176 -176
  47. package/src/server/storage/memory-backend.ts +123 -123
  48. package/src/server/storage/redis-backend.ts +276 -276
  49. package/src/server/storage/redis.ts +160 -160
  50. package/src/server/storage/sqlite-backend.ts +182 -182
  51. package/src/server/storage/supabase-backend.ts +228 -228
  52. package/src/server/storage/types.ts +116 -116
  53. package/src/shared/constants.ts +29 -29
  54. package/src/shared/errors.ts +133 -133
  55. package/src/shared/event-routing.ts +28 -28
  56. package/src/shared/events.ts +180 -180
  57. package/src/shared/index.ts +75 -75
  58. package/src/shared/tool-utils.ts +61 -61
  59. package/src/shared/types.ts +282 -282
  60. package/src/shared/utils.ts +38 -38
  61. 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
+ }