@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.
- package/README.md +73 -1
- package/dist/client/index.d.ts +47 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +47 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/postgres-client.d.ts +273 -0
- package/dist/client/postgres-client.d.ts.map +1 -0
- package/dist/client/postgres-client.js +389 -0
- package/dist/client/postgres-client.js.map +1 -0
- package/dist/client/types.d.ts +167 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +7 -0
- package/dist/client/types.js.map +1 -0
- package/dist/do/index.d.ts +18 -0
- package/dist/do/index.d.ts.map +1 -0
- package/dist/do/index.js +18 -0
- package/dist/do/index.js.map +1 -0
- package/dist/do/postgres.d.ts +110 -0
- package/dist/do/postgres.d.ts.map +1 -0
- package/dist/do/postgres.js +266 -0
- package/dist/do/postgres.js.map +1 -0
- package/dist/do/sql.d.ts +92 -0
- package/dist/do/sql.d.ts.map +1 -0
- package/dist/do/sql.js +204 -0
- package/dist/do/sql.js.map +1 -0
- package/dist/index.d.ts +25 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -30
- package/dist/index.js.map +1 -1
- package/dist/mcp/binding.d.ts +47 -0
- package/dist/mcp/binding.d.ts.map +1 -0
- package/dist/mcp/binding.js +183 -0
- package/dist/mcp/binding.js.map +1 -0
- package/dist/mcp/index.d.ts +92 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +91 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +62 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +278 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +58 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +356 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +139 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +7 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/pglite/workers-pglite.d.ts +13 -4
- package/dist/pglite/workers-pglite.d.ts.map +1 -1
- package/dist/pglite/workers-pglite.js +110 -5
- package/dist/pglite/workers-pglite.js.map +1 -1
- package/dist/pglite-assets/pglite.data +0 -0
- package/dist/pglite-assets/pglite.wasm +0 -0
- package/dist/worker/auth.d.ts.map +1 -1
- package/dist/worker/auth.js +16 -6
- package/dist/worker/auth.js.map +1 -1
- package/dist/worker/background-pglite-manager.d.ts +243 -0
- package/dist/worker/background-pglite-manager.d.ts.map +1 -0
- package/dist/worker/background-pglite-manager.js +528 -0
- package/dist/worker/background-pglite-manager.js.map +1 -0
- package/dist/worker/do-pglite-manager.d.ts +77 -0
- package/dist/worker/do-pglite-manager.d.ts.map +1 -1
- package/dist/worker/do-pglite-manager.js +189 -12
- package/dist/worker/do-pglite-manager.js.map +1 -1
- package/dist/worker/entry.d.ts.map +1 -1
- package/dist/worker/entry.js +108 -26
- package/dist/worker/entry.js.map +1 -1
- package/dist/worker/index.d.ts +7 -1
- package/dist/worker/index.d.ts.map +1 -1
- package/dist/worker/index.js +19 -1
- package/dist/worker/index.js.map +1 -1
- package/dist/worker/lazy-pglite-manager.d.ts +242 -0
- package/dist/worker/lazy-pglite-manager.d.ts.map +1 -0
- package/dist/worker/lazy-pglite-manager.js +463 -0
- package/dist/worker/lazy-pglite-manager.js.map +1 -0
- package/package.json +20 -6
- package/src/client/index.ts +61 -0
- package/src/client/postgres-client.ts +442 -0
- package/src/client/types.ts +211 -0
- package/src/do/index.ts +18 -0
- package/src/do/postgres.ts +367 -0
- package/src/do/sql.ts +280 -0
- package/src/index.ts +50 -30
- package/src/mcp/binding.ts +236 -0
- package/src/mcp/index.ts +122 -0
- package/src/mcp/server.ts +361 -0
- package/src/mcp/tools.ts +464 -0
- package/src/mcp/types.ts +148 -0
- package/src/pglite/workers-pglite.ts +141 -12
- package/src/pglite-assets/pglite.data +0 -0
- package/src/pglite-assets/pglite.wasm +0 -0
- package/src/worker/auth.ts +17 -6
- package/src/worker/background-pglite-manager.ts +680 -0
- package/src/worker/do-pglite-manager.ts +235 -19
- package/src/worker/entry.ts +112 -30
- package/src/worker/index.ts +71 -1
- package/src/worker/lazy-pglite-manager.ts +595 -0
- package/dist/iceberg/duckdb-wasm.d.ts +0 -447
- package/dist/iceberg/duckdb-wasm.d.ts.map +0 -1
- package/dist/iceberg/duckdb-wasm.js +0 -600
- package/dist/iceberg/duckdb-wasm.js.map +0 -1
- package/dist/iceberg/test-fixtures.d.ts +0 -151
- package/dist/iceberg/test-fixtures.d.ts.map +0 -1
- package/dist/iceberg/test-fixtures.js +0 -446
- package/dist/iceberg/test-fixtures.js.map +0 -1
- package/dist/worker/__mocks__/cloudflare-workers.d.ts +0 -31
- package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +0 -1
- package/dist/worker/__mocks__/cloudflare-workers.js +0 -33
- package/dist/worker/__mocks__/cloudflare-workers.js.map +0 -1
package/src/mcp/index.ts
ADDED
|
@@ -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 }
|