Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions genkit-tools/cli/context/GENKIT.go.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,55 @@ 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.

## Project Setup

### Project Initialization

- If the directory is empty:
```bash
go mod init <module-name>
```
- 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()
}
```

## 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.
Expand Down
52 changes: 52 additions & 0 deletions genkit-tools/cli/context/GENKIT.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,58 @@ 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.

## Project Setup

### 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
curl -sL cli.genkit.dev | bash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For Node.js projects, it's more idiomatic to install the Genkit CLI via npm. This is also consistent with the instructions in genkit-tools/cli/src/mcp/prompts/init.ts for Node.js setup. Using a package manager for CLI tools is generally preferred over curl | bash for better version management and security.

Suggested change
curl -sL cli.genkit.dev | 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()],
});

// Your flows and logic here
```

## 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.
Expand Down
4 changes: 3 additions & 1 deletion genkit-tools/cli/src/mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ The following tools allow MCP-aware environments to interact with the Genkit ser
| Tool Name | Description |
| :--- | :--- |
| **`get_usage_guide`** | Fetches the Genkit AI framework usage guide (specifiable by language). Intended for AI assistants. |
| **`lookup_genkit_docs`** | Retrieves Genkit documentation (specifiable by language and files). |
| **`list_genkit_docs`** | Lists all available Genkit documentation files for discovery. |
| **`search_genkit_docs`** | Searches Genkit documentation using keywords. |
| **`read_genkit_docs`** | Reads the content of specific Genkit documentation files. |
| **`list_flows`** | Discovers and lists all defined Genkit flows with their input schemas. |
| **`run_flow`** | Executes a specified Genkit flow, requiring `flowName` and a JSON `input` conforming to the flow's schema. |
| **`get_trace`** | Retrieves the detailed execution trace for a flow using a `traceId`. |
Expand Down
186 changes: 148 additions & 38 deletions genkit-tools/cli/src/mcp/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,58 +72,168 @@ export async function defineDocsTool(server: McpServer) {
) as Record<string, Doc>;

server.registerTool(
'lookup_genkit_docs',
'list_genkit_docs',
{
title: 'Genkit Docs',
title: 'List Genkit Docs',
description:
'Use this to look up documentation for the Genkit AI framework.',
'Use this to see a list of available Genkit documentation files. Returns `filePaths` that can be passed to `read_genkit_docs`.',
inputSchema: {
language: z
.enum(['js', 'go', 'python'])
.describe('which language these docs are for (default js).')
.describe(
'Which language to list docs for (default js); type: string.'
)
.default('js'),
files: z
.array(z.string())
},
},
async ({ language }) => {
await record(new McpRunToolEvent('list_genkit_docs'));
const lang = language || 'js';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The language parameter has a .default('js') in its Zod schema. This means Zod ensures language will always be a string and never falsy within the tool's execution context. Therefore, this fallback to 'js' is redundant and can be removed.

Suggested change
const lang = language || 'js';
const lang = language;


const fileList = Object.keys(documents)
.filter((file) => file.startsWith(lang))
.sort();

const output =
`Genkit Documentation Index (${lang}):\n\n` +
fileList
.map((file) => {
const doc = documents[file];
let summary = ` - FilePath: ${file}\n Title: ${doc.title}\n`;
if (doc.description) {
summary += ` Description: ${doc.description}\n`;
}
if (doc.headers) {
summary += ` Headers:\n ${doc.headers.split('\n').join('\n ')}\n`;
}
return summary;
})
.join('\n') +
`\n\nUse 'search_genkit_docs' to find specific topics. Copy the 'FilePath' values to 'read_genkit_docs' to read content.`;

return {
content: [{ type: 'text', text: output }],
};
}
);

server.registerTool(
'search_genkit_docs',
{
title: 'Search Genkit Docs',
description:
'Use this to search the Genkit documentation using keywords. Returns ranked results with `filePaths` for `read_genkit_docs`. Warning: Generic terms (e.g. "the", "and") may return false positives; use specific technical terms (e.g. "rag", "firebase", "context").',
inputSchema: {
query: z
.string()
.describe('Keywords to search for in documentation; type: string.'),
language: z
.enum(['js', 'go', 'python'])
.describe(
'Specific docs files to look up. If empty or not specified an index will be returned. Always lookup index first for exact file names.'
'Which language to search docs for (default js); type: string.'
)
.optional(),
.default('js'),
},
},
async ({ language, files }) => {
await record(new McpRunToolEvent('lookup_genkit_docs'));
async ({ query, language }) => {
await record(new McpRunToolEvent('search_genkit_docs'));
const lang = language || 'js';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The language parameter has a .default('js') in its Zod schema. This means Zod ensures language will always be a string and never falsy within the tool's execution context. Therefore, this fallback to 'js' is redundant and can be removed.

Suggested change
const lang = language || 'js';
const lang = language;

const terms = query
.toLowerCase()
.split(/\s+/)
.filter((t) => t.length > 2); // Filter out short words to reduce noise

const results = Object.keys(documents)
.filter((file) => file.startsWith(lang))
.map((file) => {
const doc = documents[file];
let score = 0;
const title = doc.title.toLowerCase();
const desc = (doc.description || '').toLowerCase();
const headers = (doc.headers || '').toLowerCase();

terms.forEach((term) => {
if (title.includes(term)) score += 10;
if (desc.includes(term)) score += 5;
if (headers.includes(term)) score += 3;
if (file.includes(term)) score += 5;
});

return { file, doc, score };
})
.filter((r) => r.score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, 10); // Top 10

if (results.length === 0) {
return {
content: [
{
type: 'text',
text: `No results found for "${query}" in ${lang} docs. Try broader keywords or use 'list_genkit_docs' to see all files.`,
},
],
};
}

const output =
`Found ${results.length} matching documents for "${query}":\n\n` +
results
.map((r) => {
let summary = `### ${r.doc.title}\n**FilePath**: ${r.file}\n`;
if (r.doc.description)
summary += `**Description**: ${r.doc.description}\n`;
return summary;
})
.join('\n') +
`\n\nCopy the 'FilePath' values to 'read_genkit_docs' to read content.`;

return {
content: [{ type: 'text', text: output }],
};
}
);

server.registerTool(
'read_genkit_docs',
{
title: 'Read Genkit Docs',
description:
'Use this to read the full content of specific Genkit documentation files. You must provide `filePaths` from the list/search tools.',
inputSchema: {
filePaths: z
.array(z.string())
.describe(
'The `filePaths` of the docs to read. Obtain these exactly from `list_genkit_docs` or `search_genkit_docs` (e.g. "js/overview.md"); type: string[].'
),
},
},
async ({ filePaths }) => {
await record(new McpRunToolEvent('read_genkit_docs'));

const content = [] as ContentBlock[];
if (!language) {
language = 'js';

// filePaths is required by Zod schema, but check length just in case
if (!filePaths || !filePaths.length) {
return {
content: [
{
type: 'text',
text: 'No filePaths provided. Please provide an array of file paths.',
},
],
isError: true,
};
}

if (!files || !files.length) {
content.push({
type: 'text',
text:
Object.keys(documents)
.filter((file) => file.startsWith(language))
.map((file) => {
let fileSummary = ` - File: ${file}\n Title: ${documents[file].title}\n`;
if (documents[file].description) {
fileSummary += ` Description: ${documents[file].description}\n`;
}
if (documents[file].headers) {
fileSummary += ` Headers:\n ${documents[file].headers.split('\n').join('\n ')}\n`;
}
return fileSummary;
})
.join('\n') +
`\n\nIMPORTANT: if doing anything more than basic model calling, look up "${language}/models.md" file, it contains important details about how to work with models.\n\n`,
});
} else {
for (const file of files) {
if (documents[file]) {
content.push({ type: 'text', text: documents[file]?.text });
} else {
content.push({ type: 'text', text: `${file} not found` });
}
for (const file of filePaths) {
if (documents[file]) {
content.push({ type: 'text', text: documents[file].text });
} else {
content.push({
type: 'text',
text: `Document not found: ${file}. Please check the path using list_genkit_docs.`,
});
}
}

Expand Down
4 changes: 2 additions & 2 deletions genkit-tools/cli/src/mcp/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ export function defineFlowTools(server: McpServer, options: McpToolOptions) {
title: 'Run Flow',
description: 'Runs the flow with the provided input',
inputSchema: getCommonSchema(options.explicitProjectRoot, {
flowName: z.string().describe('name of the flow'),
flowName: z.string().describe('name of the flow; type: string'),
input: z
.string()
.describe(
'Flow input as JSON object encoded as string (it will be passed through `JSON.parse`). Must conform to the schema.'
'Flow input as JSON object encoded as string (it will be passed through `JSON.parse`). Must conform to the schema; type: string.'
)
.optional(),
}),
Expand Down
2 changes: 1 addition & 1 deletion genkit-tools/cli/src/mcp/prompts/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { z } from 'zod';

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.
- ALWAYS refer to documentation when available. Use tools like \`get_usage_guide\`, \`list_genkit_docs\`, \`search_genkit_docs\`, or \`read_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.
Expand Down
4 changes: 2 additions & 2 deletions genkit-tools/cli/src/mcp/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ export function defineRuntimeTools(server: McpServer, options: McpToolOptions) {
{command: "npm", args: ["run", "dev"]}
{command: "npm", args: ["run", "dev"], projectRoot: "path/to/project"}`,
inputSchema: getCommonSchema(options.explicitProjectRoot, {
command: z.string().describe('The command to run'),
command: z.string().describe('The command to run; type: string'),
args: z
.array(z.string())
.describe(
'The array of string args for the command to run. Eg: `["run", "dev"]`.'
'The array of string args for the command to run. Eg: `["run", "dev"]`; type: string[].'
),
}),
},
Expand Down
4 changes: 2 additions & 2 deletions genkit-tools/cli/src/mcp/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ export function defineTraceTools(server: McpServer, options: McpToolOptions) {
'get_trace',
{
title: 'Get Genkit Trace',
description: 'Returns the trace details',
description: 'Returns the trace details.',
inputSchema: getCommonSchema(options.explicitProjectRoot, {
traceId: z
.string()
.describe(
'trace id (typically returned after running a flow or other actions)'
'trace id (typically returned after running a flow or other actions); type: string'
),
}),
},
Expand Down
4 changes: 2 additions & 2 deletions genkit-tools/cli/src/mcp/usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ export async function defineUsageGuideTool(server: McpServer) {
{
title: 'Genkit Instructions',
description:
'Use this tool to look up the Genkit usage guide before implementing any AI feature',
'Use this tool to look up the official Genkit usage guide, including project setup instructions and API best practices. ALWAYS call this before implementing Genkit features.',
inputSchema: {
language: z
.enum(['js', 'go'])
.describe('which language this usage guide is for')
.describe('which language this usage guide is for; type: string')
.default('js')
.optional(),
},
Expand Down
Loading
Loading