Skip to main content
Glama

Genkit MCP

Official
by firebase
localFileEvalStore.ts5.13 kB
/** * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import fs from 'fs'; import { readFile, unlink, writeFile } from 'fs/promises'; import path from 'path'; import { createInterface } from 'readline'; import type { ListEvalKeysRequest, ListEvalKeysResponse } from '../types/apis'; import { EvalRunKeySchema, EvalRunSchema, type EvalRun, type EvalRunKey, type EvalStore, } from '../types/eval'; import { logger } from '../utils/logger'; /** * A local, file-based EvalStore implementation. */ export class LocalFileEvalStore implements EvalStore { private storeRoot: string = ''; private indexFile: string = ''; private static cachedEvalStore: LocalFileEvalStore | null = null; private async init() { this.storeRoot = this.generateRootPath(); this.indexFile = await this.resolveIndexFile(); fs.mkdirSync(this.storeRoot, { recursive: true }); if (!fs.existsSync(this.indexFile)) { fs.writeFileSync(path.resolve(this.indexFile), JSON.stringify({})); } logger.debug( `Initialized local file eval store at root: ${this.storeRoot}` ); } static async getEvalStore() { if (!this.cachedEvalStore) { this.cachedEvalStore = new LocalFileEvalStore(); await this.cachedEvalStore.init(); } return this.cachedEvalStore; } static reset() { this.cachedEvalStore = null; } async save(evalRun: EvalRun): Promise<void> { const fileName = this.resolveEvalFilename(evalRun.key.evalRunId); logger.debug( `Saving EvalRun ${evalRun.key.evalRunId} to ` + path.resolve(this.storeRoot, fileName) ); await writeFile( path.resolve(this.storeRoot, fileName), JSON.stringify(evalRun) ); const index = await this.getEvalsIndex(); index[evalRun.key.evalRunId] = evalRun.key; await writeFile( path.resolve(this.indexFile), JSON.stringify(index, null, 2) ); } async load(evalRunId: string): Promise<EvalRun | undefined> { const filePath = path.resolve( this.storeRoot, this.resolveEvalFilename(evalRunId) ); if (!fs.existsSync(filePath)) { return undefined; } return await readFile(filePath, 'utf8').then((data) => EvalRunSchema.parse(JSON.parse(data)) ); } async list( query?: ListEvalKeysRequest | undefined ): Promise<ListEvalKeysResponse> { logger.debug(`Listing keys for filter: ${JSON.stringify(query)}`); let keys = await this.getEvalsIndex().then((index) => Object.values(index)); if (query?.filter?.actionRef) { keys = keys.filter((key) => key.actionRef === query?.filter?.actionRef); } return { evalRunKeys: keys, }; } async delete(evalRunId: string): Promise<void> { const filePath = path.resolve( this.storeRoot, this.resolveEvalFilename(evalRunId) ); if (fs.existsSync(filePath)) { await unlink(filePath); const index = await this.getEvalsIndex(); delete index[evalRunId]; await writeFile( path.resolve(this.indexFile), JSON.stringify(index, null, 2) ); } } private resolveEvalFilename(evalRunId: string): string { return `${evalRunId}.json`; } private async resolveIndexFile(): Promise<string> { const txtPath = path.resolve(this.storeRoot, 'index.txt'); const jsonPath = path.resolve(this.storeRoot, 'index.json'); if (fs.existsSync(txtPath)) { // Copy over index, delete txt file const keys = await this.processLineByLine(txtPath); await writeFile(path.resolve(jsonPath), JSON.stringify(keys, null, 2)); await unlink(txtPath); } return jsonPath; } private async processLineByLine(filePath: string) { const fileStream = fs.createReadStream(filePath); const keys: Record<string, EvalRunKey> = {}; const rl = createInterface({ input: fileStream, crlfDelay: Infinity, }); for await (const line of rl) { try { const entry = JSON.parse(line); const runKey = EvalRunKeySchema.parse(entry); keys[runKey.evalRunId] = runKey; } catch (e) { logger.debug(`Error parsing ${line}:\n`, JSON.stringify(e)); } } return keys; } private generateRootPath(): string { return path.resolve(process.cwd(), '.genkit', 'evals'); } private async getEvalsIndex(): Promise<Record<string, EvalRunKey>> { if (!fs.existsSync(this.indexFile)) { return Promise.resolve({} as any); } return await readFile(path.resolve(this.indexFile), 'utf8').then((data) => JSON.parse(data) ); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/firebase/genkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server