77 */
88
99import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' ;
10+ import { glob , readFile } from 'node:fs/promises' ;
11+ import path from 'node:path' ;
1012import { z } from 'zod' ;
1113
1214/**
@@ -18,10 +20,20 @@ import { z } from 'zod';
1820 * @param server The MCP server instance.
1921 * @param exampleDatabasePath The path to the SQLite database file containing the examples.
2022 */
21- export function registerFindExampleTool ( server : McpServer , exampleDatabasePath : string ) : void {
23+ export async function registerFindExampleTool (
24+ server : McpServer ,
25+ exampleDatabasePath : string ,
26+ ) : Promise < void > {
2227 let db : import ( 'node:sqlite' ) . DatabaseSync | undefined ;
2328 let queryStatement : import ( 'node:sqlite' ) . StatementSync | undefined ;
2429
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+
2537 server . registerTool (
2638 'find_examples' ,
2739 {
@@ -67,11 +79,11 @@ Examples of queries:
6779 } ,
6880 } ,
6981 async ( { query } ) => {
70- if ( ! db || ! queryStatement ) {
71- suppressSqliteWarning ( ) ;
72-
82+ if ( ! db ) {
7383 const { DatabaseSync } = await import ( 'node:sqlite' ) ;
7484 db = new DatabaseSync ( exampleDatabasePath , { readOnly : true } ) ;
85+ }
86+ if ( ! queryStatement ) {
7587 queryStatement = db . prepare ( 'SELECT * from examples WHERE examples MATCH ? ORDER BY rank;' ) ;
7688 }
7789
@@ -172,3 +184,27 @@ function suppressSqliteWarning() {
172184 return originalProcessEmit . apply ( process , arguments as any ) ;
173185 } ;
174186}
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