@dotdo/postgres 0.1.1 → 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 (111) 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/auth.d.ts.map +1 -1
  57. package/dist/worker/auth.js +16 -6
  58. package/dist/worker/auth.js.map +1 -1
  59. package/dist/worker/background-pglite-manager.d.ts +243 -0
  60. package/dist/worker/background-pglite-manager.d.ts.map +1 -0
  61. package/dist/worker/background-pglite-manager.js +528 -0
  62. package/dist/worker/background-pglite-manager.js.map +1 -0
  63. package/dist/worker/do-pglite-manager.d.ts +77 -0
  64. package/dist/worker/do-pglite-manager.d.ts.map +1 -1
  65. package/dist/worker/do-pglite-manager.js +189 -12
  66. package/dist/worker/do-pglite-manager.js.map +1 -1
  67. package/dist/worker/entry.d.ts.map +1 -1
  68. package/dist/worker/entry.js +108 -26
  69. package/dist/worker/entry.js.map +1 -1
  70. package/dist/worker/index.d.ts +7 -1
  71. package/dist/worker/index.d.ts.map +1 -1
  72. package/dist/worker/index.js +19 -1
  73. package/dist/worker/index.js.map +1 -1
  74. package/dist/worker/lazy-pglite-manager.d.ts +242 -0
  75. package/dist/worker/lazy-pglite-manager.d.ts.map +1 -0
  76. package/dist/worker/lazy-pglite-manager.js +463 -0
  77. package/dist/worker/lazy-pglite-manager.js.map +1 -0
  78. package/package.json +20 -6
  79. package/src/client/index.ts +61 -0
  80. package/src/client/postgres-client.ts +442 -0
  81. package/src/client/types.ts +211 -0
  82. package/src/do/index.ts +18 -0
  83. package/src/do/postgres.ts +367 -0
  84. package/src/do/sql.ts +280 -0
  85. package/src/index.ts +50 -30
  86. package/src/mcp/binding.ts +236 -0
  87. package/src/mcp/index.ts +122 -0
  88. package/src/mcp/server.ts +361 -0
  89. package/src/mcp/tools.ts +464 -0
  90. package/src/mcp/types.ts +148 -0
  91. package/src/pglite/workers-pglite.ts +141 -12
  92. package/src/pglite-assets/pglite.data +0 -0
  93. package/src/pglite-assets/pglite.wasm +0 -0
  94. package/src/worker/auth.ts +17 -6
  95. package/src/worker/background-pglite-manager.ts +680 -0
  96. package/src/worker/do-pglite-manager.ts +235 -19
  97. package/src/worker/entry.ts +112 -30
  98. package/src/worker/index.ts +71 -1
  99. package/src/worker/lazy-pglite-manager.ts +595 -0
  100. package/dist/iceberg/duckdb-wasm.d.ts +0 -447
  101. package/dist/iceberg/duckdb-wasm.d.ts.map +0 -1
  102. package/dist/iceberg/duckdb-wasm.js +0 -600
  103. package/dist/iceberg/duckdb-wasm.js.map +0 -1
  104. package/dist/iceberg/test-fixtures.d.ts +0 -151
  105. package/dist/iceberg/test-fixtures.d.ts.map +0 -1
  106. package/dist/iceberg/test-fixtures.js +0 -446
  107. package/dist/iceberg/test-fixtures.js.map +0 -1
  108. package/dist/worker/__mocks__/cloudflare-workers.d.ts +0 -31
  109. package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +0 -1
  110. package/dist/worker/__mocks__/cloudflare-workers.js +0 -33
  111. package/dist/worker/__mocks__/cloudflare-workers.js.map +0 -1
@@ -0,0 +1,122 @@
1
+ /**
2
+ * MCP Server Module for PostgresDO
3
+ *
4
+ * Provides MCP (Model Context Protocol) server implementation for PostgreSQL
5
+ * databases running in Cloudflare Durable Objects.
6
+ *
7
+ * ## Overview
8
+ *
9
+ * This module implements the three core MCP primitives:
10
+ *
11
+ * 1. **search** - Query the database with SQL, list tables, or get schema
12
+ * 2. **fetch** - Get a specific row by table/id or table schema
13
+ * 3. **do** - Execute code with the `pg` binding for full database access
14
+ *
15
+ * ## Usage
16
+ *
17
+ * @example Basic MCP server setup
18
+ * ```typescript
19
+ * import { createMCPServer } from '@dotdo/postgres/mcp'
20
+ * import { PostgresDO } from '@dotdo/postgres/worker'
21
+ *
22
+ * // In your worker
23
+ * const stub = env.POSTGRES_DO.get(doId) as DurableObjectStub<PostgresDO>
24
+ * const mcpServer = createMCPServer(stub, { databaseId: 'mydb' })
25
+ *
26
+ * // Mount routes
27
+ * app.route('/mcp', mcpServer.routes())
28
+ * ```
29
+ *
30
+ * @example With auth context from oauth.do JWT
31
+ * ```typescript
32
+ * const mcpServer = createMCPServer(stub, {
33
+ * databaseId: 'mydb',
34
+ * authContext: {
35
+ * userId: user.id,
36
+ * email: user.email,
37
+ * scopes: ['read', 'write'],
38
+ * },
39
+ * })
40
+ * ```
41
+ *
42
+ * @example Using tools directly
43
+ * ```typescript
44
+ * // Search for tables
45
+ * const result = await mcpServer.handleRequest({
46
+ * jsonrpc: '2.0',
47
+ * id: 1,
48
+ * method: 'tools/call',
49
+ * params: {
50
+ * name: 'search',
51
+ * arguments: { query: 'tables' }
52
+ * }
53
+ * })
54
+ *
55
+ * // Fetch a row
56
+ * const row = await mcpServer.handleRequest({
57
+ * jsonrpc: '2.0',
58
+ * id: 2,
59
+ * method: 'tools/call',
60
+ * params: {
61
+ * name: 'fetch',
62
+ * arguments: { resource: 'users/123' }
63
+ * }
64
+ * })
65
+ *
66
+ * // Execute code
67
+ * const code = await mcpServer.handleRequest({
68
+ * jsonrpc: '2.0',
69
+ * id: 3,
70
+ * method: 'tools/call',
71
+ * params: {
72
+ * name: 'do',
73
+ * arguments: {
74
+ * code: `
75
+ * const users = await pg.query('SELECT * FROM users LIMIT 5')
76
+ * return users.rows
77
+ * `
78
+ * }
79
+ * }
80
+ * })
81
+ * ```
82
+ *
83
+ * @module mcp
84
+ */
85
+
86
+ // Types
87
+ export type {
88
+ QueryResult,
89
+ TableInfo,
90
+ ColumnInfo,
91
+ MCPSearchResult,
92
+ MCPFetchResult,
93
+ PGBinding,
94
+ PGTransaction,
95
+ ToolResponse,
96
+ SearchInput,
97
+ FetchInput,
98
+ DoInput,
99
+ MCPAuthContext,
100
+ MCPServerConfig,
101
+ } from './types.js'
102
+
103
+ // Binding
104
+ export { createPGBinding, PG_BINDING_TYPES } from './binding.js'
105
+ export type { QueryExecutor } from './binding.js'
106
+
107
+ // Tools
108
+ export {
109
+ searchTool,
110
+ fetchTool,
111
+ doTool,
112
+ getToolDefinitions,
113
+ createToolHandlers,
114
+ createSearchHandler,
115
+ createFetchHandler,
116
+ createDoHandler,
117
+ } from './tools.js'
118
+ export type { Tool } from './tools.js'
119
+
120
+ // Server
121
+ export { createMCPServer, createMCPRoutes } from './server.js'
122
+ export type { MCPServer } from './server.js'
@@ -0,0 +1,361 @@
1
+ /**
2
+ * MCP Server for PostgresDO
3
+ *
4
+ * Creates an MCP (Model Context Protocol) server that exposes PostgreSQL
5
+ * functionality through the search/fetch/do pattern.
6
+ */
7
+
8
+ import { Hono } from 'hono'
9
+ import type { Context as HonoContext } from 'hono'
10
+ import type { MCPServerConfig, MCPAuthContext, ToolResponse } from './types.js'
11
+ import type { QueryExecutor } from './binding.js'
12
+ import {
13
+ getToolDefinitions,
14
+ createToolHandlers,
15
+ } from './tools.js'
16
+
17
+ /**
18
+ * MCP Protocol Message Types
19
+ */
20
+ interface MCPMessage {
21
+ jsonrpc: '2.0'
22
+ id?: string | number
23
+ method?: string
24
+ params?: Record<string, unknown>
25
+ result?: unknown
26
+ error?: {
27
+ code: number
28
+ message: string
29
+ data?: unknown
30
+ }
31
+ }
32
+
33
+ /**
34
+ * MCP Server implementation
35
+ */
36
+ export interface MCPServer {
37
+ /** Handle an MCP request */
38
+ handleRequest(request: MCPMessage): Promise<MCPMessage>
39
+ /** Get the Hono routes for HTTP transport */
40
+ routes(): Hono
41
+ }
42
+
43
+ /**
44
+ * MCP Error codes
45
+ */
46
+ const MCP_ERRORS = {
47
+ PARSE_ERROR: -32700,
48
+ INVALID_REQUEST: -32600,
49
+ METHOD_NOT_FOUND: -32601,
50
+ INVALID_PARAMS: -32602,
51
+ INTERNAL_ERROR: -32603,
52
+ } as const
53
+
54
+ /**
55
+ * Create an MCP server for PostgresDO
56
+ *
57
+ * @param executor - Query executor (PostgresDO stub)
58
+ * @param config - Server configuration
59
+ * @returns MCP server instance
60
+ */
61
+ export function createMCPServer(
62
+ executor: QueryExecutor,
63
+ config: MCPServerConfig = { databaseId: 'default' }
64
+ ): MCPServer {
65
+ const { timeout = 5000, authContext } = config
66
+ const handlers = createToolHandlers(executor, { timeout, authContext })
67
+ const tools = getToolDefinitions()
68
+
69
+ /**
70
+ * Handle tools/list request
71
+ */
72
+ function handleToolsList(): MCPMessage {
73
+ return {
74
+ jsonrpc: '2.0',
75
+ result: {
76
+ tools: tools.map((tool) => ({
77
+ name: tool.name,
78
+ description: tool.description,
79
+ inputSchema: tool.inputSchema,
80
+ })),
81
+ },
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Handle tools/call request
87
+ */
88
+ async function handleToolsCall(
89
+ params: Record<string, unknown>
90
+ ): Promise<MCPMessage> {
91
+ const toolName = params.name as string
92
+ const toolArgs = (params.arguments || {}) as Record<string, unknown>
93
+
94
+ const handler = handlers[toolName]
95
+ if (!handler) {
96
+ return {
97
+ jsonrpc: '2.0',
98
+ error: {
99
+ code: MCP_ERRORS.METHOD_NOT_FOUND,
100
+ message: `Unknown tool: ${toolName}`,
101
+ },
102
+ }
103
+ }
104
+
105
+ try {
106
+ const result = await handler(toolArgs)
107
+ return {
108
+ jsonrpc: '2.0',
109
+ result,
110
+ }
111
+ } catch (error) {
112
+ const message = error instanceof Error ? error.message : 'Unknown error'
113
+ return {
114
+ jsonrpc: '2.0',
115
+ error: {
116
+ code: MCP_ERRORS.INTERNAL_ERROR,
117
+ message,
118
+ },
119
+ }
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Handle initialize request
125
+ */
126
+ function handleInitialize(_params: Record<string, unknown>): MCPMessage {
127
+ return {
128
+ jsonrpc: '2.0',
129
+ result: {
130
+ protocolVersion: '2024-11-05',
131
+ capabilities: {
132
+ tools: {},
133
+ },
134
+ serverInfo: {
135
+ name: 'postgres-mcp',
136
+ version: '0.1.0',
137
+ },
138
+ },
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Handle ping request
144
+ */
145
+ function handlePing(): MCPMessage {
146
+ return {
147
+ jsonrpc: '2.0',
148
+ result: {},
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Main request handler
154
+ */
155
+ async function handleRequest(request: MCPMessage): Promise<MCPMessage> {
156
+ const { method, params = {}, id } = request
157
+
158
+ let response: MCPMessage
159
+
160
+ switch (method) {
161
+ case 'initialize':
162
+ response = handleInitialize(params)
163
+ break
164
+ case 'ping':
165
+ response = handlePing()
166
+ break
167
+ case 'tools/list':
168
+ response = handleToolsList()
169
+ break
170
+ case 'tools/call':
171
+ response = await handleToolsCall(params)
172
+ break
173
+ default:
174
+ response = {
175
+ jsonrpc: '2.0',
176
+ error: {
177
+ code: MCP_ERRORS.METHOD_NOT_FOUND,
178
+ message: `Unknown method: ${method}`,
179
+ },
180
+ }
181
+ }
182
+
183
+ // Add request ID to response
184
+ if (id !== undefined) {
185
+ response.id = id
186
+ }
187
+
188
+ return response
189
+ }
190
+
191
+ /**
192
+ * Create Hono routes for HTTP transport
193
+ */
194
+ function routes(): Hono {
195
+ const app = new Hono()
196
+
197
+ // MCP protocol endpoint (JSON-RPC over HTTP)
198
+ app.post('/mcp', async (c) => {
199
+ try {
200
+ const request = await c.req.json<MCPMessage>()
201
+
202
+ if (request.jsonrpc !== '2.0') {
203
+ return c.json(
204
+ {
205
+ jsonrpc: '2.0',
206
+ error: {
207
+ code: MCP_ERRORS.INVALID_REQUEST,
208
+ message: 'Invalid JSON-RPC version',
209
+ },
210
+ },
211
+ 400
212
+ )
213
+ }
214
+
215
+ const response = await handleRequest(request)
216
+ return c.json(response)
217
+ } catch (error) {
218
+ const message = error instanceof Error ? error.message : 'Parse error'
219
+ return c.json(
220
+ {
221
+ jsonrpc: '2.0',
222
+ error: {
223
+ code: MCP_ERRORS.PARSE_ERROR,
224
+ message,
225
+ },
226
+ },
227
+ 400
228
+ )
229
+ }
230
+ })
231
+
232
+ // Well-known MCP discovery endpoint
233
+ app.get('/.well-known/mcp', (c) => {
234
+ return c.json({
235
+ name: 'postgres-mcp',
236
+ version: '0.1.0',
237
+ protocol_version: '2024-11-05',
238
+ capabilities: {
239
+ tools: true,
240
+ },
241
+ endpoints: {
242
+ mcp: '/mcp',
243
+ sse: '/mcp/sse',
244
+ },
245
+ })
246
+ })
247
+
248
+ // SSE endpoint for streaming transport
249
+ app.get('/mcp/sse', async (c) => {
250
+ // SSE transport - to be implemented
251
+ return c.text('SSE transport not yet implemented', 501)
252
+ })
253
+
254
+ // Direct tool endpoints for convenience
255
+ app.post('/mcp/search', async (c) => {
256
+ try {
257
+ const input = await c.req.json()
258
+ const result = await handlers.search(input)
259
+ return c.json(result)
260
+ } catch (error) {
261
+ const message = error instanceof Error ? error.message : 'Unknown error'
262
+ return c.json({ error: message }, 500)
263
+ }
264
+ })
265
+
266
+ app.post('/mcp/fetch', async (c) => {
267
+ try {
268
+ const input = await c.req.json()
269
+ const result = await handlers.fetch(input)
270
+ return c.json(result)
271
+ } catch (error) {
272
+ const message = error instanceof Error ? error.message : 'Unknown error'
273
+ return c.json({ error: message }, 500)
274
+ }
275
+ })
276
+
277
+ app.post('/mcp/do', async (c) => {
278
+ try {
279
+ const input = await c.req.json()
280
+ const result = await handlers.do(input)
281
+ return c.json(result)
282
+ } catch (error) {
283
+ const message = error instanceof Error ? error.message : 'Unknown error'
284
+ return c.json({ error: message }, 500)
285
+ }
286
+ })
287
+
288
+ // Tool definitions endpoint
289
+ app.get('/mcp/tools', (c) => {
290
+ return c.json({
291
+ tools: tools.map((tool) => ({
292
+ name: tool.name,
293
+ description: tool.description,
294
+ inputSchema: tool.inputSchema,
295
+ })),
296
+ })
297
+ })
298
+
299
+ // Health check
300
+ app.get('/mcp/health', (c) => {
301
+ return c.json({
302
+ status: 'healthy',
303
+ server: 'postgres-mcp',
304
+ version: '0.1.0',
305
+ timestamp: new Date().toISOString(),
306
+ })
307
+ })
308
+
309
+ return app
310
+ }
311
+
312
+ return {
313
+ handleRequest,
314
+ routes,
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Variables stored in Hono context for MCP routes
320
+ */
321
+ interface MCPVariables {
322
+ mcpServer: MCPServer
323
+ }
324
+
325
+ /**
326
+ * Create MCP routes for integration with PostgresDO worker
327
+ */
328
+ export function createMCPRoutes(
329
+ getExecutor: (c: HonoContext) => QueryExecutor,
330
+ getConfig?: (c: HonoContext) => MCPServerConfig
331
+ ): Hono<{ Variables: MCPVariables }> {
332
+ const app = new Hono<{ Variables: MCPVariables }>()
333
+
334
+ // Middleware to create MCP server per request
335
+ app.use('*', async (c, next) => {
336
+ const executor = getExecutor(c as unknown as HonoContext)
337
+ const config = getConfig?.(c as unknown as HonoContext) || { databaseId: 'default' }
338
+ const mcpServer = createMCPServer(executor, config)
339
+
340
+ // Store in context
341
+ c.set('mcpServer', mcpServer)
342
+
343
+ await next()
344
+ })
345
+
346
+ // Forward to MCP server routes
347
+ app.all('*', async (c) => {
348
+ const mcpServer = c.get('mcpServer')
349
+ const routes = mcpServer.routes()
350
+ return routes.fetch(c.req.raw)
351
+ })
352
+
353
+ return app
354
+ }
355
+
356
+ /**
357
+ * Re-export types and tools
358
+ */
359
+ export { getToolDefinitions, createToolHandlers }
360
+ export type { Tool } from './tools.js'
361
+ export type { MCPServerConfig, MCPAuthContext, ToolResponse }