@dotdo/postgres 0.1.2 → 0.1.3

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 (103) hide show
  1. package/README.md +73 -1
  2. package/dist/client/index.d.ts +47 -0
  3. package/dist/client/index.d.ts.map +1 -0
  4. package/dist/client/index.js +47 -0
  5. package/dist/client/index.js.map +1 -0
  6. package/dist/client/postgres-client.d.ts +273 -0
  7. package/dist/client/postgres-client.d.ts.map +1 -0
  8. package/dist/client/postgres-client.js +389 -0
  9. package/dist/client/postgres-client.js.map +1 -0
  10. package/dist/client/types.d.ts +167 -0
  11. package/dist/client/types.d.ts.map +1 -0
  12. package/dist/client/types.js +7 -0
  13. package/dist/client/types.js.map +1 -0
  14. package/dist/do/index.d.ts +18 -0
  15. package/dist/do/index.d.ts.map +1 -0
  16. package/dist/do/index.js +18 -0
  17. package/dist/do/index.js.map +1 -0
  18. package/dist/do/postgres.d.ts +110 -0
  19. package/dist/do/postgres.d.ts.map +1 -0
  20. package/dist/do/postgres.js +266 -0
  21. package/dist/do/postgres.js.map +1 -0
  22. package/dist/do/sql.d.ts +92 -0
  23. package/dist/do/sql.d.ts.map +1 -0
  24. package/dist/do/sql.js +204 -0
  25. package/dist/do/sql.js.map +1 -0
  26. package/dist/index.d.ts +25 -30
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +29 -30
  29. package/dist/index.js.map +1 -1
  30. package/dist/mcp/binding.d.ts +47 -0
  31. package/dist/mcp/binding.d.ts.map +1 -0
  32. package/dist/mcp/binding.js +183 -0
  33. package/dist/mcp/binding.js.map +1 -0
  34. package/dist/mcp/index.d.ts +92 -0
  35. package/dist/mcp/index.d.ts.map +1 -0
  36. package/dist/mcp/index.js +91 -0
  37. package/dist/mcp/index.js.map +1 -0
  38. package/dist/mcp/server.d.ts +62 -0
  39. package/dist/mcp/server.d.ts.map +1 -0
  40. package/dist/mcp/server.js +278 -0
  41. package/dist/mcp/server.js.map +1 -0
  42. package/dist/mcp/tools.d.ts +58 -0
  43. package/dist/mcp/tools.d.ts.map +1 -0
  44. package/dist/mcp/tools.js +356 -0
  45. package/dist/mcp/tools.js.map +1 -0
  46. package/dist/mcp/types.d.ts +139 -0
  47. package/dist/mcp/types.d.ts.map +1 -0
  48. package/dist/mcp/types.js +7 -0
  49. package/dist/mcp/types.js.map +1 -0
  50. package/dist/pglite/workers-pglite.d.ts +13 -4
  51. package/dist/pglite/workers-pglite.d.ts.map +1 -1
  52. package/dist/pglite/workers-pglite.js +110 -5
  53. package/dist/pglite/workers-pglite.js.map +1 -1
  54. package/dist/pglite-assets/pglite.data +0 -0
  55. package/dist/pglite-assets/pglite.wasm +0 -0
  56. package/dist/worker/background-pglite-manager.d.ts +243 -0
  57. package/dist/worker/background-pglite-manager.d.ts.map +1 -0
  58. package/dist/worker/background-pglite-manager.js +528 -0
  59. package/dist/worker/background-pglite-manager.js.map +1 -0
  60. package/dist/worker/do-pglite-manager.d.ts +77 -0
  61. package/dist/worker/do-pglite-manager.d.ts.map +1 -1
  62. package/dist/worker/do-pglite-manager.js +189 -12
  63. package/dist/worker/do-pglite-manager.js.map +1 -1
  64. package/dist/worker/index.d.ts +7 -1
  65. package/dist/worker/index.d.ts.map +1 -1
  66. package/dist/worker/index.js +19 -1
  67. package/dist/worker/index.js.map +1 -1
  68. package/dist/worker/lazy-pglite-manager.d.ts +242 -0
  69. package/dist/worker/lazy-pglite-manager.d.ts.map +1 -0
  70. package/dist/worker/lazy-pglite-manager.js +463 -0
  71. package/dist/worker/lazy-pglite-manager.js.map +1 -0
  72. package/package.json +16 -3
  73. package/src/client/index.ts +61 -0
  74. package/src/client/postgres-client.ts +442 -0
  75. package/src/client/types.ts +211 -0
  76. package/src/do/index.ts +18 -0
  77. package/src/do/postgres.ts +367 -0
  78. package/src/do/sql.ts +280 -0
  79. package/src/index.ts +50 -30
  80. package/src/mcp/binding.ts +236 -0
  81. package/src/mcp/index.ts +122 -0
  82. package/src/mcp/server.ts +361 -0
  83. package/src/mcp/tools.ts +464 -0
  84. package/src/mcp/types.ts +148 -0
  85. package/src/pglite/workers-pglite.ts +141 -12
  86. package/src/pglite-assets/pglite.data +0 -0
  87. package/src/pglite-assets/pglite.wasm +0 -0
  88. package/src/worker/background-pglite-manager.ts +680 -0
  89. package/src/worker/do-pglite-manager.ts +235 -19
  90. package/src/worker/index.ts +71 -1
  91. package/src/worker/lazy-pglite-manager.ts +595 -0
  92. package/dist/iceberg/duckdb-wasm.d.ts +0 -447
  93. package/dist/iceberg/duckdb-wasm.d.ts.map +0 -1
  94. package/dist/iceberg/duckdb-wasm.js +0 -600
  95. package/dist/iceberg/duckdb-wasm.js.map +0 -1
  96. package/dist/iceberg/test-fixtures.d.ts +0 -151
  97. package/dist/iceberg/test-fixtures.d.ts.map +0 -1
  98. package/dist/iceberg/test-fixtures.js +0 -446
  99. package/dist/iceberg/test-fixtures.js.map +0 -1
  100. package/dist/worker/__mocks__/cloudflare-workers.d.ts +0 -31
  101. package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +0 -1
  102. package/dist/worker/__mocks__/cloudflare-workers.js +0 -33
  103. package/dist/worker/__mocks__/cloudflare-workers.js.map +0 -1
@@ -0,0 +1,464 @@
1
+ /**
2
+ * MCP Tools for PostgresDO
3
+ *
4
+ * Implements the three core MCP tools: search, fetch, and do.
5
+ */
6
+
7
+ import type {
8
+ MCPSearchResult,
9
+ MCPFetchResult,
10
+ ToolResponse,
11
+ SearchInput,
12
+ FetchInput,
13
+ DoInput,
14
+ MCPAuthContext,
15
+ } from './types.js'
16
+ import type { QueryExecutor } from './binding.js'
17
+ import { createPGBinding, PG_BINDING_TYPES } from './binding.js'
18
+
19
+ /**
20
+ * Tool definition for MCP protocol
21
+ */
22
+ export interface Tool {
23
+ name: string
24
+ description: string
25
+ inputSchema: {
26
+ type: string
27
+ properties: Record<string, unknown>
28
+ required: string[]
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Search tool definition
34
+ */
35
+ export const searchTool: Tool = {
36
+ name: 'search',
37
+ description:
38
+ 'Search the PostgreSQL database. Supports SQL queries, table listing, and schema introspection.',
39
+ inputSchema: {
40
+ type: 'object',
41
+ properties: {
42
+ query: {
43
+ type: 'string',
44
+ description:
45
+ 'Search query. Can be: SQL query (SELECT ...), "tables" to list tables, or "schema:<table>" to get table schema',
46
+ },
47
+ limit: {
48
+ type: 'number',
49
+ description: 'Maximum number of results to return',
50
+ },
51
+ },
52
+ required: ['query'],
53
+ },
54
+ }
55
+
56
+ /**
57
+ * Fetch tool definition
58
+ */
59
+ export const fetchTool: Tool = {
60
+ name: 'fetch',
61
+ description:
62
+ 'Fetch a specific resource from the database. Format: "table/id" or "schema/table/column"',
63
+ inputSchema: {
64
+ type: 'object',
65
+ properties: {
66
+ resource: {
67
+ type: 'string',
68
+ description:
69
+ 'Resource identifier. Format: "table/id" to get a row, or "schema/table" for table schema',
70
+ },
71
+ },
72
+ required: ['resource'],
73
+ },
74
+ }
75
+
76
+ /**
77
+ * Do tool definition
78
+ */
79
+ export const doTool: Tool = {
80
+ name: 'do',
81
+ description: `Execute TypeScript/JavaScript code with access to the PostgreSQL database via the 'pg' binding.
82
+
83
+ Available APIs:
84
+ ${PG_BINDING_TYPES}`,
85
+ inputSchema: {
86
+ type: 'object',
87
+ properties: {
88
+ code: {
89
+ type: 'string',
90
+ description: 'TypeScript/JavaScript code to execute',
91
+ },
92
+ },
93
+ required: ['code'],
94
+ },
95
+ }
96
+
97
+ /**
98
+ * Create the search tool handler
99
+ */
100
+ export function createSearchHandler(
101
+ executor: QueryExecutor
102
+ ): (input: SearchInput) => Promise<ToolResponse> {
103
+ return async (input: SearchInput): Promise<ToolResponse> => {
104
+ try {
105
+ const { query, limit = 100 } = input
106
+
107
+ // Handle special commands
108
+ if (query.toLowerCase() === 'tables') {
109
+ const result = await executor.rpcQuery(`
110
+ SELECT
111
+ table_name as name,
112
+ table_schema as schema,
113
+ table_type as type
114
+ FROM information_schema.tables
115
+ WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
116
+ ORDER BY table_schema, table_name
117
+ LIMIT $1
118
+ `, [limit])
119
+
120
+ const results: MCPSearchResult[] = result.rows.map((row) => ({
121
+ id: `${row.schema}.${row.name}`,
122
+ title: row.name as string,
123
+ snippet: `${row.type} in schema ${row.schema}`,
124
+ metadata: { schema: row.schema, type: row.type },
125
+ }))
126
+
127
+ return {
128
+ content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
129
+ }
130
+ }
131
+
132
+ // Handle schema introspection: "schema:tablename"
133
+ if (query.toLowerCase().startsWith('schema:')) {
134
+ const tableName = query.slice(7).trim()
135
+
136
+ // Validate table name
137
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
138
+ return {
139
+ content: [{ type: 'text', text: JSON.stringify({ error: 'Invalid table name' }) }],
140
+ isError: true,
141
+ }
142
+ }
143
+
144
+ const result = await executor.rpcQuery(
145
+ `
146
+ SELECT
147
+ column_name as name,
148
+ data_type as type,
149
+ is_nullable,
150
+ column_default
151
+ FROM information_schema.columns
152
+ WHERE table_name = $1
153
+ AND table_schema NOT IN ('pg_catalog', 'information_schema')
154
+ ORDER BY ordinal_position
155
+ `,
156
+ [tableName]
157
+ )
158
+
159
+ const results: MCPSearchResult[] = result.rows.map((row) => ({
160
+ id: `${tableName}.${row.name}`,
161
+ title: row.name as string,
162
+ snippet: `${row.type}${row.is_nullable === 'NO' ? ' NOT NULL' : ''}${row.column_default ? ` DEFAULT ${row.column_default}` : ''}`,
163
+ metadata: {
164
+ table: tableName,
165
+ type: row.type,
166
+ nullable: row.is_nullable === 'YES',
167
+ default: row.column_default,
168
+ },
169
+ }))
170
+
171
+ return {
172
+ content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
173
+ }
174
+ }
175
+
176
+ // Execute SQL query
177
+ // Add LIMIT if not present and query is a SELECT
178
+ let sql = query.trim()
179
+ const isSelect = sql.toLowerCase().startsWith('select')
180
+
181
+ if (isSelect && !sql.toLowerCase().includes('limit')) {
182
+ sql = `${sql} LIMIT ${limit}`
183
+ }
184
+
185
+ const result = await executor.rpcQuery(sql)
186
+
187
+ const results: MCPSearchResult[] = result.rows.map((row, index) => {
188
+ // Try to find an id-like field
189
+ const idField = Object.keys(row).find(
190
+ (k) => k === 'id' || k.endsWith('_id') || k === 'uuid'
191
+ )
192
+ const id = idField ? String(row[idField]) : String(index)
193
+
194
+ // Create a title from the first non-id field
195
+ const titleField = Object.keys(row).find(
196
+ (k) => k !== idField && typeof row[k] === 'string'
197
+ )
198
+ const title = titleField ? String(row[titleField]) : `Row ${index + 1}`
199
+
200
+ return {
201
+ id,
202
+ title,
203
+ snippet: JSON.stringify(row),
204
+ metadata: row as Record<string, unknown>,
205
+ }
206
+ })
207
+
208
+ return {
209
+ content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
210
+ }
211
+ } catch (error) {
212
+ const message = error instanceof Error ? error.message : 'Unknown error'
213
+ return {
214
+ content: [{ type: 'text', text: JSON.stringify({ error: message }) }],
215
+ isError: true,
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Create the fetch tool handler
223
+ */
224
+ export function createFetchHandler(
225
+ executor: QueryExecutor
226
+ ): (input: FetchInput) => Promise<ToolResponse> {
227
+ return async (input: FetchInput): Promise<ToolResponse> => {
228
+ try {
229
+ const { resource } = input
230
+ const parts = resource.split('/')
231
+
232
+ // Handle schema fetch: "schema/tablename"
233
+ if (parts[0].toLowerCase() === 'schema' && parts.length === 2) {
234
+ const tableName = parts[1]
235
+
236
+ // Validate table name
237
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
238
+ return {
239
+ content: [{ type: 'text', text: JSON.stringify({ error: 'Invalid table name' }) }],
240
+ isError: true,
241
+ }
242
+ }
243
+
244
+ const result = await executor.rpcQuery(
245
+ `
246
+ SELECT
247
+ column_name as name,
248
+ data_type as type,
249
+ is_nullable = 'YES' as nullable,
250
+ column_default as "default"
251
+ FROM information_schema.columns
252
+ WHERE table_name = $1
253
+ AND table_schema NOT IN ('pg_catalog', 'information_schema')
254
+ ORDER BY ordinal_position
255
+ `,
256
+ [tableName]
257
+ )
258
+
259
+ const fetchResult: MCPFetchResult = {
260
+ content: JSON.stringify(result.rows, null, 2),
261
+ contentType: 'application/json',
262
+ metadata: {
263
+ table: tableName,
264
+ columnCount: result.rows.length,
265
+ },
266
+ }
267
+
268
+ return {
269
+ content: [{ type: 'text', text: JSON.stringify(fetchResult, null, 2) }],
270
+ }
271
+ }
272
+
273
+ // Handle row fetch: "tablename/id"
274
+ if (parts.length === 2) {
275
+ const [tableName, id] = parts
276
+
277
+ // Validate table name
278
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
279
+ return {
280
+ content: [{ type: 'text', text: JSON.stringify({ error: 'Invalid table name' }) }],
281
+ isError: true,
282
+ }
283
+ }
284
+
285
+ // Try to find the primary key column
286
+ const pkResult = await executor.rpcQuery(
287
+ `
288
+ SELECT kcu.column_name
289
+ FROM information_schema.key_column_usage kcu
290
+ JOIN information_schema.table_constraints tc
291
+ ON kcu.constraint_name = tc.constraint_name
292
+ WHERE tc.constraint_type = 'PRIMARY KEY'
293
+ AND kcu.table_name = $1
294
+ LIMIT 1
295
+ `,
296
+ [tableName]
297
+ )
298
+
299
+ const pkColumn =
300
+ pkResult.rows.length > 0 ? (pkResult.rows[0].column_name as string) : 'id'
301
+
302
+ // Fetch the row
303
+ const result = await executor.rpcQuery(
304
+ `SELECT * FROM "${tableName}" WHERE "${pkColumn}" = $1 LIMIT 1`,
305
+ [id]
306
+ )
307
+
308
+ if (result.rows.length === 0) {
309
+ return {
310
+ content: [
311
+ {
312
+ type: 'text',
313
+ text: JSON.stringify({ error: `Row not found: ${resource}` }),
314
+ },
315
+ ],
316
+ isError: true,
317
+ }
318
+ }
319
+
320
+ const fetchResult: MCPFetchResult = {
321
+ content: JSON.stringify(result.rows[0], null, 2),
322
+ contentType: 'application/json',
323
+ metadata: {
324
+ table: tableName,
325
+ primaryKey: pkColumn,
326
+ id,
327
+ },
328
+ }
329
+
330
+ return {
331
+ content: [{ type: 'text', text: JSON.stringify(fetchResult, null, 2) }],
332
+ }
333
+ }
334
+
335
+ return {
336
+ content: [
337
+ {
338
+ type: 'text',
339
+ text: JSON.stringify({
340
+ error:
341
+ 'Invalid resource format. Use "table/id" for rows or "schema/table" for schema',
342
+ }),
343
+ },
344
+ ],
345
+ isError: true,
346
+ }
347
+ } catch (error) {
348
+ const message = error instanceof Error ? error.message : 'Unknown error'
349
+ return {
350
+ content: [{ type: 'text', text: JSON.stringify({ error: message }) }],
351
+ isError: true,
352
+ }
353
+ }
354
+ }
355
+ }
356
+
357
+ /**
358
+ * Create the do tool handler
359
+ */
360
+ export function createDoHandler(
361
+ executor: QueryExecutor,
362
+ options: { timeout?: number; authContext?: MCPAuthContext } = {}
363
+ ): (input: DoInput) => Promise<ToolResponse> {
364
+ const { timeout = 5000 } = options
365
+
366
+ return async (input: DoInput): Promise<ToolResponse> => {
367
+ const startTime = Date.now()
368
+ const logs: Array<[string, string]> = []
369
+
370
+ try {
371
+ const { code } = input
372
+
373
+ // Create the pg binding
374
+ const pg = createPGBinding(executor)
375
+
376
+ // Create sandbox console that captures logs
377
+ const sandboxConsole = {
378
+ log: (...args: unknown[]) => logs.push(['log', args.map(String).join(' ')]),
379
+ error: (...args: unknown[]) => logs.push(['error', args.map(String).join(' ')]),
380
+ warn: (...args: unknown[]) => logs.push(['warn', args.map(String).join(' ')]),
381
+ info: (...args: unknown[]) => logs.push(['info', args.map(String).join(' ')]),
382
+ }
383
+
384
+ // Create and execute function with sandbox
385
+ // Note: In production, use ai-evaluate for proper V8 isolation
386
+ const fn = new Function('pg', 'console', `
387
+ return (async () => {
388
+ ${code}
389
+ })()
390
+ `)
391
+
392
+ // Execute with timeout
393
+ const result = await Promise.race([
394
+ fn(pg, sandboxConsole),
395
+ new Promise((_, reject) =>
396
+ setTimeout(() => reject(new Error('Execution timeout')), timeout)
397
+ ),
398
+ ])
399
+
400
+ const duration = Date.now() - startTime
401
+
402
+ return {
403
+ content: [
404
+ {
405
+ type: 'text',
406
+ text: JSON.stringify(
407
+ {
408
+ success: true,
409
+ value: result,
410
+ logs: logs.map(([level, msg]) => ({ level, message: msg })),
411
+ duration,
412
+ },
413
+ null,
414
+ 2
415
+ ),
416
+ },
417
+ ],
418
+ }
419
+ } catch (error) {
420
+ const duration = Date.now() - startTime
421
+ const message = error instanceof Error ? error.message : 'Unknown error'
422
+
423
+ return {
424
+ content: [
425
+ {
426
+ type: 'text',
427
+ text: JSON.stringify(
428
+ {
429
+ success: false,
430
+ error: message,
431
+ logs: logs.map(([level, msg]) => ({ level, message: msg })),
432
+ duration,
433
+ },
434
+ null,
435
+ 2
436
+ ),
437
+ },
438
+ ],
439
+ isError: true,
440
+ }
441
+ }
442
+ }
443
+ }
444
+
445
+ /**
446
+ * Get all tool definitions
447
+ */
448
+ export function getToolDefinitions(): Tool[] {
449
+ return [searchTool, fetchTool, doTool]
450
+ }
451
+
452
+ /**
453
+ * Create all tool handlers
454
+ */
455
+ export function createToolHandlers(
456
+ executor: QueryExecutor,
457
+ options: { timeout?: number; authContext?: MCPAuthContext } = {}
458
+ ): Record<string, (input: unknown) => Promise<ToolResponse>> {
459
+ return {
460
+ search: createSearchHandler(executor) as (input: unknown) => Promise<ToolResponse>,
461
+ fetch: createFetchHandler(executor) as (input: unknown) => Promise<ToolResponse>,
462
+ do: createDoHandler(executor, options) as (input: unknown) => Promise<ToolResponse>,
463
+ }
464
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * MCP Server Types for PostgresDO
3
+ *
4
+ * Type definitions for the MCP (Model Context Protocol) server implementation.
5
+ */
6
+
7
+ /**
8
+ * Query result from pg.query()
9
+ */
10
+ export interface QueryResult<T = Record<string, unknown>> {
11
+ rows: T[]
12
+ rowCount: number
13
+ fields: Array<{
14
+ name: string
15
+ dataTypeID: number
16
+ }>
17
+ }
18
+
19
+ /**
20
+ * Table information from pg.tables()
21
+ */
22
+ export interface TableInfo {
23
+ name: string
24
+ schema: string
25
+ type: 'table' | 'view' | 'materialized_view'
26
+ rowCount?: number
27
+ }
28
+
29
+ /**
30
+ * Column schema from pg.schema()
31
+ */
32
+ export interface ColumnInfo {
33
+ name: string
34
+ type: string
35
+ nullable: boolean
36
+ default?: string
37
+ primaryKey: boolean
38
+ }
39
+
40
+ /**
41
+ * Search result for MCP search tool
42
+ */
43
+ export interface MCPSearchResult {
44
+ id: string
45
+ title: string
46
+ snippet?: string
47
+ score?: number
48
+ metadata?: Record<string, unknown>
49
+ }
50
+
51
+ /**
52
+ * Fetch result for MCP fetch tool
53
+ */
54
+ export interface MCPFetchResult {
55
+ content: string
56
+ contentType?: string
57
+ metadata?: Record<string, unknown>
58
+ }
59
+
60
+ /**
61
+ * The pg binding exposed to the do tool
62
+ */
63
+ export interface PGBinding {
64
+ /**
65
+ * Execute a SQL query with optional parameters
66
+ */
67
+ query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>>
68
+
69
+ /**
70
+ * Execute a SQL statement (INSERT, UPDATE, DELETE)
71
+ */
72
+ execute(sql: string, params?: unknown[]): Promise<{ rowCount: number }>
73
+
74
+ /**
75
+ * Execute multiple statements in a transaction
76
+ */
77
+ transaction<T>(fn: (tx: PGTransaction) => Promise<T>): Promise<T>
78
+
79
+ /**
80
+ * List all tables in the database
81
+ */
82
+ tables(): Promise<TableInfo[]>
83
+
84
+ /**
85
+ * Get schema information for a table
86
+ */
87
+ schema(tableName: string): Promise<ColumnInfo[]>
88
+ }
89
+
90
+ /**
91
+ * Transaction context for pg.transaction()
92
+ */
93
+ export interface PGTransaction {
94
+ query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>>
95
+ execute(sql: string, params?: unknown[]): Promise<{ rowCount: number }>
96
+ }
97
+
98
+ /**
99
+ * MCP tool response format
100
+ */
101
+ export interface ToolResponse {
102
+ content: Array<{ type: string; text: string }>
103
+ isError?: boolean
104
+ }
105
+
106
+ /**
107
+ * Search tool input
108
+ */
109
+ export interface SearchInput {
110
+ query: string
111
+ limit?: number
112
+ }
113
+
114
+ /**
115
+ * Fetch tool input
116
+ */
117
+ export interface FetchInput {
118
+ resource: string
119
+ }
120
+
121
+ /**
122
+ * Do tool input
123
+ */
124
+ export interface DoInput {
125
+ code: string
126
+ }
127
+
128
+ /**
129
+ * Auth context from oauth.do JWT
130
+ */
131
+ export interface MCPAuthContext {
132
+ userId: string
133
+ email?: string
134
+ scopes?: string[]
135
+ metadata?: Record<string, unknown>
136
+ }
137
+
138
+ /**
139
+ * MCP Server configuration
140
+ */
141
+ export interface MCPServerConfig {
142
+ /** Database ID for the PostgresDO instance */
143
+ databaseId: string
144
+ /** Optional auth context from JWT */
145
+ authContext?: MCPAuthContext
146
+ /** Timeout for code execution in ms (default: 5000) */
147
+ timeout?: number
148
+ }