7
7
*/
8
8
9
9
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' ;
10
+ import { glob , readFile } from 'node:fs/promises' ;
11
+ import path from 'node:path' ;
10
12
import { z } from 'zod' ;
11
13
12
14
/**
@@ -18,10 +20,20 @@ import { z } from 'zod';
18
20
* @param server The MCP server instance.
19
21
* @param exampleDatabasePath The path to the SQLite database file containing the examples.
20
22
*/
21
- export function registerFindExampleTool ( server : McpServer , exampleDatabasePath : string ) : void {
23
+ export async function registerFindExampleTool (
24
+ server : McpServer ,
25
+ exampleDatabasePath : string ,
26
+ ) : Promise < void > {
22
27
let db : import ( 'node:sqlite' ) . DatabaseSync | undefined ;
23
28
let queryStatement : import ( 'node:sqlite' ) . StatementSync | undefined ;
24
29
30
+ // Runtime directory of examples uses an in-memory database
31
+ if ( process . env [ 'NG_MCP_EXAMPLES_DIR' ] ) {
32
+ db = await setupRuntimeExamples ( process . env [ 'NG_MCP_EXAMPLES_DIR' ] ) ;
33
+ }
34
+
35
+ suppressSqliteWarning ( ) ;
36
+
25
37
server . registerTool (
26
38
'find_examples' ,
27
39
{
@@ -67,11 +79,11 @@ Examples of queries:
67
79
} ,
68
80
} ,
69
81
async ( { query } ) => {
70
- if ( ! db || ! queryStatement ) {
71
- suppressSqliteWarning ( ) ;
72
-
82
+ if ( ! db ) {
73
83
const { DatabaseSync } = await import ( 'node:sqlite' ) ;
74
84
db = new DatabaseSync ( exampleDatabasePath , { readOnly : true } ) ;
85
+ }
86
+ if ( ! queryStatement ) {
75
87
queryStatement = db . prepare ( 'SELECT * from examples WHERE examples MATCH ? ORDER BY rank;' ) ;
76
88
}
77
89
@@ -172,3 +184,27 @@ function suppressSqliteWarning() {
172
184
return originalProcessEmit . apply ( process , arguments as any ) ;
173
185
} ;
174
186
}
187
+
188
+ async function setupRuntimeExamples (
189
+ examplesPath : string ,
190
+ ) : Promise < import ( 'node:sqlite' ) . DatabaseSync > {
191
+ const { DatabaseSync } = await import ( 'node:sqlite' ) ;
192
+ const db = new DatabaseSync ( ':memory:' ) ;
193
+
194
+ db . exec ( `CREATE VIRTUAL TABLE examples USING fts5(content, tokenize = 'porter ascii');` ) ;
195
+
196
+ const insertStatement = db . prepare ( 'INSERT INTO examples(content) VALUES(?);' ) ;
197
+
198
+ db . exec ( 'BEGIN TRANSACTION' ) ;
199
+ for await ( const entry of glob ( '*.md' , { cwd : examplesPath , withFileTypes : true } ) ) {
200
+ if ( ! entry . isFile ( ) ) {
201
+ continue ;
202
+ }
203
+
204
+ const example = await readFile ( path . join ( entry . parentPath , entry . name ) , 'utf-8' ) ;
205
+ insertStatement . run ( example ) ;
206
+ }
207
+ db . exec ( 'END TRANSACTION' ) ;
208
+
209
+ return db ;
210
+ }
0 commit comments