From ce029b097f21bebb2a2abf92fb8f1c5f1a561354 Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Tue, 2 Dec 2025 11:50:58 -0500 Subject: [PATCH 1/4] add init prompt --- genkit-tools/cli/context/GENKIT.go.md | 44 -------- genkit-tools/cli/context/GENKIT.js.md | 35 ------- genkit-tools/cli/src/mcp/prompts/init.ts | 122 +++++++++++++++++++++++ genkit-tools/cli/src/mcp/server.ts | 3 + 4 files changed, 125 insertions(+), 79 deletions(-) create mode 100644 genkit-tools/cli/src/mcp/prompts/init.ts diff --git a/genkit-tools/cli/context/GENKIT.go.md b/genkit-tools/cli/context/GENKIT.go.md index 80e7fabf1f..d82fd51d4a 100644 --- a/genkit-tools/cli/context/GENKIT.go.md +++ b/genkit-tools/cli/context/GENKIT.go.md @@ -14,50 +14,6 @@ This document provides rules and examples for building with the Genkit API in Go NOTE: For the sake of brevity, the snippets below use the Google AI plugin, but you should follow the user's preference as mentioned above. -## Core Setup - -1. **Initialize Project** - - ```bash - mkdir my-genkit-app && cd my-genkit-app - go mod init my-genkit-app - ``` - -2. **Install Dependencies** - - ```bash - go get github.com/firebase/genkit/go/genkit - go get github.com/firebase/genkit/go/plugins/googlegenai - go get github.com/firebase/genkit/go/ai - go get google.golang.org/genai - ``` - -3. **Install Genkit CLI** - - ```bash - curl -sL cli.genkit.dev | bash - ``` - -4. **Configure Genkit** - - All code should be in a single `main.go` file or properly structured Go package. - - ```go - package main - - import ( - "context" - "github.com/firebase/genkit/go/genkit" - "github.com/firebase/genkit/go/plugins/googlegenai" - ) - - func main() { - ctx := context.Background() - g := genkit.Init(ctx, genkit.WithPlugins(&googlegenai.GoogleAI{})) - // Your flows and logic here - <-ctx.Done() - } - ``` ## Best Practices diff --git a/genkit-tools/cli/context/GENKIT.js.md b/genkit-tools/cli/context/GENKIT.js.md index 5a39be8359..4c391ba617 100644 --- a/genkit-tools/cli/context/GENKIT.js.md +++ b/genkit-tools/cli/context/GENKIT.js.md @@ -14,41 +14,6 @@ This document provides rules and examples for building with the Genkit API in No NOTE: For the sake of brevity, the snippets below use the Google AI plugin, but you should follow the user's preference as mentioned above. -## Core Setup - -1. **Initialize Project** - - ```bash - mkdir my-genkit-app && cd my-genkit-app - npm init -y - npm install -D typescript tsx \@types/node - ``` - -2. **Install Dependencies** - - ```bash - npm install genkit \@genkit-ai/google-genai data-urls node-fetch - ``` - -3. **Install Genkit CLI** - - ```bash - npm install -g genkit-cli - ``` - -4. **Configure Genkit** - - All code should be in a single `src/index.ts` file. - - ```ts - // src/index.ts - import { genkit, z } from 'genkit'; - import { googleAI } from '@genkit-ai/google-genai'; - - export const ai = genkit({ - plugins: [googleAI()], - }); - ``` ## Best Practices diff --git a/genkit-tools/cli/src/mcp/prompts/init.ts b/genkit-tools/cli/src/mcp/prompts/init.ts new file mode 100644 index 0000000000..a98ebc09d1 --- /dev/null +++ b/genkit-tools/cli/src/mcp/prompts/init.ts @@ -0,0 +1,122 @@ +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; + +export function defineInitPrompt(server: McpServer) { + server.registerPrompt( + 'genkit:init', + { + title: 'Initialize Genkit', + description: 'Initializes a new Genkit project', + }, + () => ({ + messages: [ + { + role: 'user', + content: { + type: 'text', + text: `You are a Genkit expert. Help the user initialize a Genkit project. + +Follow these rules based on the user's environment and preference: + +## General Guidelines +- ALWAYS refer to documentation when available. Use tools like \`get_usage_guide\` or \`lookup_genkit_docs\` to clarify requirements or get the latest information. +- Recommend and use the provider that the user prefers. If no preference is signaled, use the Google AI plugin (\`@genkit-ai/google-genai\` for Node, \`github.com/firebase/genkit/go/plugins/googlegenai\` for Go). +- ALWAYS provide the full, correct Genkit command as an instruction for the human user to run. Do not run Genkit commands yourself. +- Do NOT modify parts of the project unrelated to Genkit initialization. +- Respect the user's existing tooling (package manager, language version, project structure). +- Check if Genkit CLI is already installed before recommending installation. + +## Node.js Setup +If the user wants to use Node.js: + +### Project Initialization +- If the directory is empty: + Initialize a new project: + \`\`\`bash + npm init -y + npm install -D typescript tsx @types/node + \`\`\` +- If the directory is not empty (existing project): + - Adhere to the current project structure. + - Detect the package manager in use (npm, pnpm, yarn, bun) and use the corresponding commands. + - Detect if the project is ESM (\`"type": "module"\` in package.json) or CJS. + - For ESM: Use \`import\` syntax. + - For CJS: Use \`require\` syntax. + - IMPORTANT: Do NOT refactor the project (e.g., converting to TypeScript or ESM) solely for Genkit. Work with the existing setup. + +### Dependencies +Install core dependencies (adjust command for the user's package manager): +\`\`\`bash +npm install genkit @genkit-ai/google-genai +\`\`\` +(Add other plugins as requested) + +### Genkit CLI +If the Genkit CLI is not already installed: +\`\`\`bash +npm install -g genkit-cli +\`\`\` + +### Configuration +Create a single \`src/index.ts\` (or \`src/index.js\` for JS) file. + +\`\`\`ts +// src/index.ts +import { genkit, z } from 'genkit'; +import { googleAI } from '@genkit-ai/google-genai'; + +export const ai = genkit({ + plugins: [googleAI()], +}); +\`\`\` + +## Go Setup +If the user wants to use Go: + +### Project Initialization +- If the directory is empty: + \`\`\`bash + go mod init + \`\`\` +- If the directory is not empty: + Adhere to the current project structure. + +### Dependencies +\`\`\`bash +go get github.com/firebase/genkit/go/genkit +go get github.com/firebase/genkit/go/plugins/googlegenai +go get github.com/firebase/genkit/go/ai +go get google.golang.org/genai +\`\`\` + +### Genkit CLI +If the Genkit CLI is not already installed: +\`\`\`bash +curl -sL cli.genkit.dev | bash +\`\`\` + +### Configuration +Create a \`main.go\` file: + +\`\`\`go +package main + +import ( + "context" + "github.com/firebase/genkit/go/genkit" + "github.com/firebase/genkit/go/plugins/googlegenai" +) + +func main() { + ctx := context.Background() + g := genkit.Init(ctx, genkit.WithPlugins(&googlegenai.GoogleAI{})) + // Your flows and logic here + <-ctx.Done() +} +\`\`\` +`, + }, + }, + ], + }) + ); +} diff --git a/genkit-tools/cli/src/mcp/server.ts b/genkit-tools/cli/src/mcp/server.ts index 3fbab0f208..edb51418a8 100644 --- a/genkit-tools/cli/src/mcp/server.ts +++ b/genkit-tools/cli/src/mcp/server.ts @@ -20,6 +20,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' import { defineDocsTool } from '../mcp/docs'; import { defineFlowTools } from './flows'; import { defineTraceTools } from './trace'; +import {defineInitPrompt } from './prompts/init'; import { defineUsageGuideTool } from './usage'; import { lazyLoadManager } from './util'; @@ -33,6 +34,8 @@ export async function startMcpServer(projectRoot: string) { await defineDocsTool(server); await defineUsageGuideTool(server); + defineInitPrompt(server); + defineFlowTools(server, manager); defineTraceTools(server, manager); From 8bb2b81dd29ba43b1d615d41156078be3955560d Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Tue, 2 Dec 2025 14:49:50 -0500 Subject: [PATCH 2/4] Add runtime tools --- genkit-tools/cli/context/GENKIT.go.md | 26 +++---- genkit-tools/cli/context/GENKIT.js.md | 32 ++++---- genkit-tools/cli/src/mcp/prompts/init.ts | 7 ++ genkit-tools/cli/src/mcp/runtime.ts | 99 ++++++++++++++++++++++++ genkit-tools/cli/src/mcp/server.ts | 4 +- genkit-tools/cli/src/mcp/util.ts | 16 +++- 6 files changed, 149 insertions(+), 35 deletions(-) create mode 100644 genkit-tools/cli/src/mcp/runtime.ts diff --git a/genkit-tools/cli/context/GENKIT.go.md b/genkit-tools/cli/context/GENKIT.go.md index d82fd51d4a..5f94562422 100644 --- a/genkit-tools/cli/context/GENKIT.go.md +++ b/genkit-tools/cli/context/GENKIT.go.md @@ -172,24 +172,24 @@ func main() { ## Running and Inspecting Flows -1. **Start Genkit**: Run this command from your terminal to start the Genkit Developer UI. +**Start Genkit**: Genkit can be started locally by using the `genkit start` command, along with the process startup command: - ```bash - genkit start -- - ``` - - For Go applications: +```bash +genkit start -- +``` - ```bash - # Running a Go application directly - genkit start -- go run main.go +For e.g.: - # Running a compiled binary - genkit start -- ./my-genkit-app - ``` +```bash +genkit start -- go run main.go +``` - The command should output a URL for the Genkit Dev UI. Direct the user to visit this URL to run and inspect their Genkit app. +You can can automate starting genkit using the following steps: +1. Identify the command to start the user's project's (e.g., `go run main.go`) +2. Use the `start_runtime` tool to start the runtime process. This is required for Genkit to discover flows. + - Example: If the project uses `go run main.go`, call `start_runtime` with `{ command: "go", args: ["run", "main.go"] }`. +3. After starting the runtime, instruct the user to run `genkit start` in their terminal to launch the Developer UI. ## Suggested Models Here are suggested models to use for various task types. This is NOT an exhaustive list. diff --git a/genkit-tools/cli/context/GENKIT.js.md b/genkit-tools/cli/context/GENKIT.js.md index 4c391ba617..5d5547721b 100644 --- a/genkit-tools/cli/context/GENKIT.js.md +++ b/genkit-tools/cli/context/GENKIT.js.md @@ -14,7 +14,6 @@ This document provides rules and examples for building with the Genkit API in No NOTE: For the sake of brevity, the snippets below use the Google AI plugin, but you should follow the user's preference as mentioned above. - ## Best Practices 1. **Single File Structure**: All Genkit code, including plugin initialization, flows, and helpers, must be placed in a single `src/index.ts` file. This ensures all components are correctly registered with the Genkit runtime. @@ -254,29 +253,24 @@ export const videoGenerationFlow = ai.defineFlow( ## Running and Inspecting Flows -1. **Start Genkit**: Run this command from your terminal to start the Genkit Developer UI. - - ```bash - genkit start -- - ``` +**Start Genkit**: Genkit can be started locally by using the `genkit start` command, along with the process startup command: - The will vary based on the project’s setup and - the file you want to execute. For e.g.: +```bash +genkit start -- +``` - ```bash - # Running a typical development server - genkit start -- npm run dev +For e.g.: - # Running a TypeScript file directly - genkit start -- npx tsx --watch src/index.ts +```bash +genkit start -- npm run dev +``` - # Running a JavaScript file directly - genkit start -- node --watch src/index.js - ``` +You can can automate starting genkit using the following steps: - Analyze the users project and build tools to use the right command for the - project. The command should output a URL for the Genkit Dev UI. Direct the - user to visit this URL to run and inspect their Genkit app. +1. Identify the command to start the user's project's (e.g., `npm run dev`) +2. Use the `start_runtime` tool to start the runtime process. This is required for Genkit to discover flows. + - Example: If the project uses `npm run dev`, call `start_runtime` with `{ command: "npm", args: ["run", "dev"] }`. +3. After starting the runtime, instruct the user to run `genkit start` in their terminal to launch the Developer UI. ## Suggested Models diff --git a/genkit-tools/cli/src/mcp/prompts/init.ts b/genkit-tools/cli/src/mcp/prompts/init.ts index a98ebc09d1..6e1c86af47 100644 --- a/genkit-tools/cli/src/mcp/prompts/init.ts +++ b/genkit-tools/cli/src/mcp/prompts/init.ts @@ -113,6 +113,13 @@ func main() { <-ctx.Done() } \`\`\` + +## Running the Project +After setting up the project: +1. Identify the command to run the project's runtime (e.g., \`npm run dev\`, \`go run main.go\`). +2. Use the \`start_runtime\` tool to start the runtime process. This is required for Genkit to discover flows. + - Example: If the project uses \`npm run dev\`, call \`start_runtime\` with \`{ command: "npm", args: ["run", "dev"] }\`. +3. After starting the runtime, instruct the user to run \`genkit start\` in their terminal to launch the Developer UI. `, }, }, diff --git a/genkit-tools/cli/src/mcp/runtime.ts b/genkit-tools/cli/src/mcp/runtime.ts new file mode 100644 index 0000000000..68702983ad --- /dev/null +++ b/genkit-tools/cli/src/mcp/runtime.ts @@ -0,0 +1,99 @@ +/** + * Copyright 2025 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 { record } from '@genkit-ai/tools-common/utils'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; +import { z } from 'zod'; +import { McpRunToolEvent } from './analytics.js'; +import { lazyLoadManager } from './util.js'; + +export function defineRuntimeTools( + server: McpServer, + manager: ReturnType +) { + server.registerTool( + 'start_runtime', + { + title: 'Starts a Genkit runtime process', + description: + 'Use this to start a Genkit runtime process. This will be picked up by the `genkit start` command to power the Dev UI features like model and flow playgrounds. The inputSchema for this tool matches the function prototype for `NodeJS.child_process.spawn`', + inputSchema: { + command: z.string(), + args: z.array(z.string()), + }, + }, + async ({ command, args }) => { + await record(new McpRunToolEvent('start_runtime')); + await manager.initManagerWithDevProcess(command, args); + + return { + content: [{ type: 'text', text: `Done.` }], + }; + } + ); + + server.registerTool( + 'kill_runtime', + { + title: 'Kills any existing Genkit runtime process', + description: + 'Use this to stop an existing runtime that was started using the `start_runtime` tool', + }, + async () => { + await record(new McpRunToolEvent('kill_runtime')); + const runtimeManager = await manager.getManager(); + if (!runtimeManager.processManager) { + return { + isError: true, + content: [ + { type: 'text', text: `No runtime process currently running.` }, + ], + }; + } + + await runtimeManager.processManager?.kill(); + return { + content: [{ type: 'text', text: `Done.` }], + }; + } + ); + + server.registerTool( + 'restart_runtime', + { + title: 'Restarts any existing Genkit runtime process', + description: + 'Use this to restart an existing runtime that was started using the `start_runtime` tool', + }, + async () => { + await record(new McpRunToolEvent('restart_runtime')); + const runtimeManager = await manager.getManager(); + if (!runtimeManager.processManager) { + return { + isError: true, + content: [ + { type: 'text', text: `No runtime process currently running.` }, + ], + }; + } + + await runtimeManager.processManager?.restart(); + return { + content: [{ type: 'text', text: `Done.` }], + }; + } + ); +} diff --git a/genkit-tools/cli/src/mcp/server.ts b/genkit-tools/cli/src/mcp/server.ts index edb51418a8..fe3c4275e6 100644 --- a/genkit-tools/cli/src/mcp/server.ts +++ b/genkit-tools/cli/src/mcp/server.ts @@ -19,8 +19,9 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { defineDocsTool } from '../mcp/docs'; import { defineFlowTools } from './flows'; +import { defineInitPrompt } from './prompts/init'; +import { defineRuntimeTools } from './runtime'; import { defineTraceTools } from './trace'; -import {defineInitPrompt } from './prompts/init'; import { defineUsageGuideTool } from './usage'; import { lazyLoadManager } from './util'; @@ -35,6 +36,7 @@ export async function startMcpServer(projectRoot: string) { await defineDocsTool(server); await defineUsageGuideTool(server); defineInitPrompt(server); + defineRuntimeTools(server, manager); defineFlowTools(server, manager); defineTraceTools(server, manager); diff --git a/genkit-tools/cli/src/mcp/util.ts b/genkit-tools/cli/src/mcp/util.ts index 0ced95e63e..1335d9997d 100644 --- a/genkit-tools/cli/src/mcp/util.ts +++ b/genkit-tools/cli/src/mcp/util.ts @@ -15,7 +15,7 @@ */ import { RuntimeManager } from '@genkit-ai/tools-common/manager'; -import { startManager } from '../utils/manager-utils'; +import { startDevProcessManager, startManager } from '../utils/manager-utils'; /** Lazy loader for RuntimeManager to defer `.genkit/` creation. */ export function lazyLoadManager(projectRoot: string) { @@ -23,9 +23,21 @@ export function lazyLoadManager(projectRoot: string) { return { async getManager() { if (!manager) { - manager = await startManager(projectRoot, true); + manager = await startManager(projectRoot, true /* manageHealth */); } return manager; }, + async initManagerWithDevProcess(command: string, args: string[]) { + if (manager) { + await manager.processManager?.kill(); + } + const devManager = await startDevProcessManager( + projectRoot, + command, + args + ); + manager = devManager.manager; + return manager; + }, }; } From 684933b0763315e58d66308f347ac550e94d93ff Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Wed, 3 Dec 2025 11:03:12 -0500 Subject: [PATCH 3/4] probable fix? --- genkit-tools/cli/context/GENKIT.go.md | 2 +- genkit-tools/cli/src/mcp/flows.ts | 7 +-- genkit-tools/cli/src/mcp/prompts/init.ts | 16 +++++++ genkit-tools/cli/src/mcp/runtime.ts | 6 +-- genkit-tools/cli/src/mcp/server.ts | 23 +++++++-- genkit-tools/cli/src/mcp/trace.ts | 4 +- genkit-tools/cli/src/mcp/util.ts | 56 +++++++++++++--------- genkit-tools/common/src/manager/manager.ts | 19 +++++++- 8 files changed, 96 insertions(+), 37 deletions(-) diff --git a/genkit-tools/cli/context/GENKIT.go.md b/genkit-tools/cli/context/GENKIT.go.md index 5f94562422..a9417b6cb5 100644 --- a/genkit-tools/cli/context/GENKIT.go.md +++ b/genkit-tools/cli/context/GENKIT.go.md @@ -14,7 +14,6 @@ This document provides rules and examples for building with the Genkit API in Go NOTE: For the sake of brevity, the snippets below use the Google AI plugin, but you should follow the user's preference as mentioned above. - ## Best Practices 1. **Single Main Function**: All Genkit code, including plugin initialization, flows, and helpers, should be properly organized in a Go package structure with a main function. @@ -190,6 +189,7 @@ You can can automate starting genkit using the following steps: 2. Use the `start_runtime` tool to start the runtime process. This is required for Genkit to discover flows. - Example: If the project uses `go run main.go`, call `start_runtime` with `{ command: "go", args: ["run", "main.go"] }`. 3. After starting the runtime, instruct the user to run `genkit start` in their terminal to launch the Developer UI. + ## Suggested Models Here are suggested models to use for various task types. This is NOT an exhaustive list. diff --git a/genkit-tools/cli/src/mcp/flows.ts b/genkit-tools/cli/src/mcp/flows.ts index 793db9fb6c..5b4f5a8d96 100644 --- a/genkit-tools/cli/src/mcp/flows.ts +++ b/genkit-tools/cli/src/mcp/flows.ts @@ -18,12 +18,9 @@ import { record } from '@genkit-ai/tools-common/utils'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import z from 'zod'; import { McpRunToolEvent } from './analytics.js'; -import { lazyLoadManager } from './util.js'; +import { McpRuntimeManager } from './util.js'; -export function defineFlowTools( - server: McpServer, - manager: ReturnType -) { +export function defineFlowTools(server: McpServer, manager: McpRuntimeManager) { server.registerTool( 'list_flows', { diff --git a/genkit-tools/cli/src/mcp/prompts/init.ts b/genkit-tools/cli/src/mcp/prompts/init.ts index 6e1c86af47..e3e14801ec 100644 --- a/genkit-tools/cli/src/mcp/prompts/init.ts +++ b/genkit-tools/cli/src/mcp/prompts/init.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2025 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 { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; export function defineInitPrompt(server: McpServer) { diff --git a/genkit-tools/cli/src/mcp/runtime.ts b/genkit-tools/cli/src/mcp/runtime.ts index 68702983ad..d0a9d5713b 100644 --- a/genkit-tools/cli/src/mcp/runtime.ts +++ b/genkit-tools/cli/src/mcp/runtime.ts @@ -18,11 +18,11 @@ import { record } from '@genkit-ai/tools-common/utils'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import { z } from 'zod'; import { McpRunToolEvent } from './analytics.js'; -import { lazyLoadManager } from './util.js'; +import { McpRuntimeManager } from './util.js'; export function defineRuntimeTools( server: McpServer, - manager: ReturnType + manager: McpRuntimeManager ) { server.registerTool( 'start_runtime', @@ -37,7 +37,7 @@ export function defineRuntimeTools( }, async ({ command, args }) => { await record(new McpRunToolEvent('start_runtime')); - await manager.initManagerWithDevProcess(command, args); + await manager.getManagerWithDevProcess(command, args); return { content: [{ type: 'text', text: `Done.` }], diff --git a/genkit-tools/cli/src/mcp/server.ts b/genkit-tools/cli/src/mcp/server.ts index fe3c4275e6..6aecf2a218 100644 --- a/genkit-tools/cli/src/mcp/server.ts +++ b/genkit-tools/cli/src/mcp/server.ts @@ -23,7 +23,7 @@ import { defineInitPrompt } from './prompts/init'; import { defineRuntimeTools } from './runtime'; import { defineTraceTools } from './trace'; import { defineUsageGuideTool } from './usage'; -import { lazyLoadManager } from './util'; +import { McpRuntimeManager } from './util'; export async function startMcpServer(projectRoot: string) { const server = new McpServer({ @@ -31,7 +31,7 @@ export async function startMcpServer(projectRoot: string) { version: '0.0.2', }); - const manager = lazyLoadManager(projectRoot); + const manager = new McpRuntimeManager(projectRoot); await defineDocsTool(server); await defineUsageGuideTool(server); @@ -43,9 +43,26 @@ export async function startMcpServer(projectRoot: string) { return new Promise(async (resolve) => { const transport = new StdioServerTransport(); - transport.onclose = () => { + const cleanup = async () => { + try { + await manager.kill(); + } catch (e) { + // ignore + } resolve(undefined); + process.exit(0); }; + transport.onclose = async () => { + try { + await manager.kill(); + } catch (e) { + // ignore + } + resolve(undefined); + process.exit(0); + }; + process.on('SIGINT', cleanup); + process.on('SIGTERM', cleanup); await server.connect(transport); logger.info('Genkit MCP Server running on stdio'); }); diff --git a/genkit-tools/cli/src/mcp/trace.ts b/genkit-tools/cli/src/mcp/trace.ts index 0a3ea5d091..7e8520cf40 100644 --- a/genkit-tools/cli/src/mcp/trace.ts +++ b/genkit-tools/cli/src/mcp/trace.ts @@ -18,11 +18,11 @@ import { record } from '@genkit-ai/tools-common/utils'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import z from 'zod'; import { McpRunToolEvent } from './analytics.js'; -import { lazyLoadManager } from './util.js'; +import { McpRuntimeManager } from './util.js'; export function defineTraceTools( server: McpServer, - manager: ReturnType + manager: McpRuntimeManager ) { server.registerTool( 'get_trace', diff --git a/genkit-tools/cli/src/mcp/util.ts b/genkit-tools/cli/src/mcp/util.ts index 1335d9997d..f39ac569bf 100644 --- a/genkit-tools/cli/src/mcp/util.ts +++ b/genkit-tools/cli/src/mcp/util.ts @@ -17,27 +17,39 @@ import { RuntimeManager } from '@genkit-ai/tools-common/manager'; import { startDevProcessManager, startManager } from '../utils/manager-utils'; -/** Lazy loader for RuntimeManager to defer `.genkit/` creation. */ -export function lazyLoadManager(projectRoot: string) { - let manager: RuntimeManager | undefined; - return { - async getManager() { - if (!manager) { - manager = await startManager(projectRoot, true /* manageHealth */); - } - return manager; - }, - async initManagerWithDevProcess(command: string, args: string[]) { - if (manager) { - await manager.processManager?.kill(); - } - const devManager = await startDevProcessManager( - projectRoot, - command, - args +/** Genkit Runtime manager specifically for the MCP server. Allows lazy + * initialization and dev process manangement. */ +export class McpRuntimeManager { + private manager: RuntimeManager | undefined; + + constructor(private projectRoot: string) {} + + async getManager() { + if (!this.manager) { + this.manager = await startManager( + this.projectRoot, + true /* manageHealth */ ); - manager = devManager.manager; - return manager; - }, - }; + } + return this.manager; + } + + async getManagerWithDevProcess(command: string, args: string[]) { + if (this.manager) { + await this.manager.stop(); + } + const devManager = await startDevProcessManager( + this.projectRoot, + command, + args + ); + this.manager = devManager.manager; + return this.manager; + } + + async kill() { + if (this.manager) { + await this.manager.stop(); + } + } } diff --git a/genkit-tools/common/src/manager/manager.ts b/genkit-tools/common/src/manager/manager.ts index b166095939..82ee715b17 100644 --- a/genkit-tools/common/src/manager/manager.ts +++ b/genkit-tools/common/src/manager/manager.ts @@ -68,6 +68,8 @@ export class RuntimeManager { private filenameToDevUiMap: Record = {}; private idToFileMap: Record = {}; private eventEmitter = new EventEmitter(); + private watchers: chokidar.FSWatcher[] = []; + private healthCheckInterval?: NodeJS.Timeout; private constructor( readonly telemetryServerUrl: string | undefined, @@ -91,7 +93,7 @@ export class RuntimeManager { await manager.setupRuntimesWatcher(); await manager.setupDevUiWatcher(); if (manager.manageHealth) { - setInterval( + manager.healthCheckInterval = setInterval( async () => await manager.performHealthChecks(), HEALTH_CHECK_INTERVAL ); @@ -99,6 +101,19 @@ export class RuntimeManager { return manager; } + /** + * Stops the runtime manager and cleans up resources. + */ + async stop() { + if (this.healthCheckInterval) { + clearInterval(this.healthCheckInterval); + } + await Promise.all(this.watchers.map((watcher) => watcher.close())); + if (this.processManager) { + await this.processManager.kill(); + } + } + /** * Lists all active runtimes */ @@ -368,6 +383,7 @@ export class RuntimeManager { persistent: true, ignoreInitial: false, }); + this.watchers.push(watcher); watcher.on('add', (filePath) => this.handleNewRuntime(filePath)); if (this.manageHealth) { watcher.on('unlink', (filePath) => this.handleRemovedRuntime(filePath)); @@ -392,6 +408,7 @@ export class RuntimeManager { persistent: true, ignoreInitial: false, }); + this.watchers.push(watcher); watcher.on('add', (filePath) => this.handleNewDevUi(filePath)); if (this.manageHealth) { watcher.on('unlink', (filePath) => this.handleRemovedDevUi(filePath)); From 1d8a8cde305f9d326e64f49241d958b30b7acef7 Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Thu, 4 Dec 2025 10:48:31 -0500 Subject: [PATCH 4/4] feedback --- genkit-tools/cli/src/mcp/prompts/init.ts | 73 ++++++++++++++++-------- genkit-tools/cli/src/mcp/runtime.ts | 7 ++- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/genkit-tools/cli/src/mcp/prompts/init.ts b/genkit-tools/cli/src/mcp/prompts/init.ts index e3e14801ec..b4908ef829 100644 --- a/genkit-tools/cli/src/mcp/prompts/init.ts +++ b/genkit-tools/cli/src/mcp/prompts/init.ts @@ -15,32 +15,18 @@ */ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; +import { z } from 'zod'; -export function defineInitPrompt(server: McpServer) { - server.registerPrompt( - 'genkit:init', - { - title: 'Initialize Genkit', - description: 'Initializes a new Genkit project', - }, - () => ({ - messages: [ - { - role: 'user', - content: { - type: 'text', - text: `You are a Genkit expert. Help the user initialize a Genkit project. - -Follow these rules based on the user's environment and preference: - +const GENERAL_GUIDELINES = ` ## General Guidelines - ALWAYS refer to documentation when available. Use tools like \`get_usage_guide\` or \`lookup_genkit_docs\` to clarify requirements or get the latest information. - Recommend and use the provider that the user prefers. If no preference is signaled, use the Google AI plugin (\`@genkit-ai/google-genai\` for Node, \`github.com/firebase/genkit/go/plugins/googlegenai\` for Go). - ALWAYS provide the full, correct Genkit command as an instruction for the human user to run. Do not run Genkit commands yourself. - Do NOT modify parts of the project unrelated to Genkit initialization. - Respect the user's existing tooling (package manager, language version, project structure). -- Check if Genkit CLI is already installed before recommending installation. +- Check if Genkit CLI is already installed before recommending installation.`; +const NODE_SETUP = ` ## Node.js Setup If the user wants to use Node.js: @@ -83,8 +69,9 @@ import { googleAI } from '@genkit-ai/google-genai'; export const ai = genkit({ plugins: [googleAI()], }); -\`\`\` +\`\`\``; +const GO_SETUP = ` ## Go Setup If the user wants to use Go: @@ -128,18 +115,56 @@ func main() { // Your flows and logic here <-ctx.Done() } -\`\`\` +\`\`\``; +const RUNNING_THE_PROJECT = ` ## Running the Project After setting up the project: 1. Identify the command to run the project's runtime (e.g., \`npm run dev\`, \`go run main.go\`). 2. Use the \`start_runtime\` tool to start the runtime process. This is required for Genkit to discover flows. - Example: If the project uses \`npm run dev\`, call \`start_runtime\` with \`{ command: "npm", args: ["run", "dev"] }\`. 3. After starting the runtime, instruct the user to run \`genkit start\` in their terminal to launch the Developer UI. -`, +`; + +export function defineInitPrompt(server: McpServer) { + server.registerPrompt( + 'genkit:init', + { + title: 'Initialize Genkit', + description: 'Initializes a new Genkit project', + argsSchema: { + lang: z.enum(['js', 'go']).optional(), + }, + }, + ({ lang }) => { + let content = `You are a Genkit expert. Help the user initialize a Genkit project. + +Follow these rules based on the user's environment and preference:`; + + content += GENERAL_GUIDELINES; + + if (lang === 'js') { + content += NODE_SETUP; + } else if (lang === 'go') { + content += GO_SETUP; + } else { + content += NODE_SETUP; + content += GO_SETUP; + } + + content += RUNNING_THE_PROJECT; + + return { + messages: [ + { + role: 'user', + content: { + type: 'text', + text: content, + }, }, - }, - ], - }) + ], + }; + } ); } diff --git a/genkit-tools/cli/src/mcp/runtime.ts b/genkit-tools/cli/src/mcp/runtime.ts index d0a9d5713b..daa52e622d 100644 --- a/genkit-tools/cli/src/mcp/runtime.ts +++ b/genkit-tools/cli/src/mcp/runtime.ts @@ -28,8 +28,11 @@ export function defineRuntimeTools( 'start_runtime', { title: 'Starts a Genkit runtime process', - description: - 'Use this to start a Genkit runtime process. This will be picked up by the `genkit start` command to power the Dev UI features like model and flow playgrounds. The inputSchema for this tool matches the function prototype for `NodeJS.child_process.spawn`', + description: `Use this to start a Genkit runtime process (This is typically the entry point to the users app). Once started, the runtime will be picked up by the \`genkit start\` command to power the Dev UI features like model and flow playgrounds. The inputSchema for this tool matches the function prototype for \`NodeJS.child_process.spawn\`. + + Examples: + {command: 'go', args: ['run', 'main.go']} + {command: 'npm', args: ['run', 'dev']}`, inputSchema: { command: z.string(), args: z.array(z.string()),