Skip to content

Commit 064d6a1

Browse files
authored
feat(cli): added experiment mcp server to genkit start command (#3132)
1 parent 35f6a51 commit 064d6a1

29 files changed

+807
-94
lines changed

genkit-tools/cli/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,16 @@
2626
"directory": "genkit-tools/cli"
2727
},
2828
"dependencies": {
29-
"@genkit-ai/tools-common": "workspace:*",
3029
"@genkit-ai/telemetry-server": "workspace:*",
30+
"@genkit-ai/tools-common": "workspace:*",
31+
"@modelcontextprotocol/sdk": "^1.13.1",
3132
"axios": "^1.7.7",
3233
"colorette": "^2.0.20",
3334
"commander": "^11.1.0",
3435
"extract-zip": "^2.0.1",
35-
"open": "^6.3.0",
36-
"inquirer": "^8.2.0",
3736
"get-port": "5.1.1",
37+
"inquirer": "^8.2.0",
38+
"open": "^6.3.0",
3839
"ora": "^5.4.1"
3940
},
4041
"devDependencies": {

genkit-tools/cli/src/cli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { evalFlow } from './commands/eval-flow';
2828
import { evalRun } from './commands/eval-run';
2929
import { flowBatchRun } from './commands/flow-batch-run';
3030
import { flowRun } from './commands/flow-run';
31+
import { mcp } from './commands/mcp';
3132
import { getPluginCommands, getPluginSubCommand } from './commands/plugins';
3233
import { start } from './commands/start';
3334
import { uiStart } from './commands/ui-start';
@@ -50,6 +51,7 @@ const commands: Command[] = [
5051
evalFlow,
5152
config,
5253
start,
54+
mcp,
5355
];
5456

5557
/** Main entry point for CLI. */

genkit-tools/cli/src/commands/eval-extract-data.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type {
2020
TraceData,
2121
} from '@genkit-ai/tools-common';
2222
import {
23+
findProjectRoot,
2324
generateTestCaseId,
2425
getEvalExtractors,
2526
logger,
@@ -45,7 +46,7 @@ export const evalExtractData = new Command('eval:extractData')
4546
.option('--maxRows <maxRows>', 'maximum number of rows', '100')
4647
.option('--label [label]', 'label flow run in this batch')
4748
.action(async (flowName: string, options: EvalDatasetOptions) => {
48-
await runWithManager(async (manager) => {
49+
await runWithManager(await findProjectRoot(), async (manager) => {
4950
const extractors = await getEvalExtractors(`/flow/${flowName}`);
5051

5152
logger.info(`Extracting trace data '/flow/${flowName}'...`);
@@ -105,7 +106,7 @@ export const evalExtractData = new Command('eval:extractData')
105106
);
106107
} else {
107108
logger.info(`Results will not be written to file.`);
108-
console.log(`Results: ${JSON.stringify(dataset, undefined, ' ')}`);
109+
logger.info(`Results: ${JSON.stringify(dataset, undefined, ' ')}`);
109110
}
110111
});
111112
});

genkit-tools/cli/src/commands/eval-flow.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
} from '@genkit-ai/tools-common/eval';
3232
import {
3333
confirmLlmUse,
34+
findProjectRoot,
3435
hasAction,
3536
loadInferenceDatasetFile,
3637
logger,
@@ -90,7 +91,7 @@ export const evalFlow = new Command('eval:flow')
9091
.option('-f, --force', 'Automatically accept all interactive prompts')
9192
.action(
9293
async (flowName: string, data: string, options: EvalFlowRunCliOptions) => {
93-
await runWithManager(async (manager) => {
94+
await runWithManager(await findProjectRoot(), async (manager) => {
9495
const actionRef = `/flow/${flowName}`;
9596
if (!data && !options.input) {
9697
throw new Error(

genkit-tools/cli/src/commands/eval-run.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
} from '@genkit-ai/tools-common/eval';
2525
import {
2626
confirmLlmUse,
27+
findProjectRoot,
2728
loadEvaluationDatasetFile,
2829
logger,
2930
} from '@genkit-ai/tools-common/utils';
@@ -66,7 +67,7 @@ export const evalRun = new Command('eval:run')
6667
)
6768
.option('--force', 'Automatically accept all interactive prompts')
6869
.action(async (dataset: string, options: EvalRunCliOptions) => {
69-
await runWithManager(async (manager) => {
70+
await runWithManager(await findProjectRoot(), async (manager) => {
7071
if (!dataset) {
7172
throw new Error(
7273
'No input data passed. Specify input data using [data] argument'

genkit-tools/cli/src/commands/flow-batch-run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { logger } from '@genkit-ai/tools-common/utils';
17+
import { findProjectRoot, logger } from '@genkit-ai/tools-common/utils';
1818
import { Command } from 'commander';
1919
import { readFile, writeFile } from 'fs/promises';
2020
import { runWithManager } from '../utils/manager-utils';
@@ -43,7 +43,7 @@ export const flowBatchRun = new Command('flow:batchRun')
4343
fileName: string,
4444
options: FlowBatchRunOptions
4545
) => {
46-
await runWithManager(async (manager) => {
46+
await runWithManager(await findProjectRoot(), async (manager) => {
4747
const inputData = JSON.parse(await readFile(fileName, 'utf8')) as any[];
4848
let input = inputData;
4949
if (inputData.length === 0) {

genkit-tools/cli/src/commands/flow-run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { logger } from '@genkit-ai/tools-common/utils';
17+
import { findProjectRoot, logger } from '@genkit-ai/tools-common/utils';
1818
import { Command } from 'commander';
1919
import { writeFile } from 'fs/promises';
2020
import { runWithManager } from '../utils/manager-utils';
@@ -39,7 +39,7 @@ export const flowRun = new Command('flow:run')
3939
'name of the output file to store the extracted data'
4040
)
4141
.action(async (flowName: string, data: string, options: FlowRunOptions) => {
42-
await runWithManager(async (manager) => {
42+
await runWithManager(await findProjectRoot(), async (manager) => {
4343
logger.info(`Running '/flow/${flowName}' (stream=${options.stream})...`);
4444
const result = (
4545
await manager.runAction(
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { findProjectRoot, forceStderr } from '@genkit-ai/tools-common/utils';
18+
import { Command } from 'commander';
19+
import { startMcpServer } from '../mcp/server';
20+
import { startManager } from '../utils/manager-utils';
21+
22+
interface McpOptions {
23+
projectRoot?: string;
24+
}
25+
26+
/** Command to run MCP server. */
27+
export const mcp = new Command('mcp')
28+
.option('--project-root [projectRoot]', 'Project root')
29+
.description('run MCP stdio server (EXPERIMENTAL, subject to change)')
30+
.action(async (options: McpOptions) => {
31+
forceStderr();
32+
const manager = await startManager(
33+
options.projectRoot ?? (await findProjectRoot()),
34+
true
35+
);
36+
await startMcpServer(manager);
37+
});

genkit-tools/cli/src/commands/start.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import type { RuntimeManager } from '@genkit-ai/tools-common/manager';
1818
import { startServer } from '@genkit-ai/tools-common/server';
19-
import { logger } from '@genkit-ai/tools-common/utils';
19+
import { findProjectRoot, logger } from '@genkit-ai/tools-common/utils';
2020
import { spawn } from 'child_process';
2121
import { Command } from 'commander';
2222
import getPort, { makeRange } from 'get-port';
@@ -37,7 +37,10 @@ export const start = new Command('start')
3737
.option('-o, --open', 'Open the browser on UI start up')
3838
.action(async (options: RunOptions) => {
3939
// Always start the manager.
40-
let managerPromise: Promise<RuntimeManager> = startManager(true);
40+
let managerPromise: Promise<RuntimeManager> = startManager(
41+
await findProjectRoot(),
42+
true
43+
);
4144
if (!options.noui) {
4245
let port: number;
4346
if (options.port) {
@@ -81,7 +84,7 @@ async function startRuntime(telemetryServerUrl?: string) {
8184
process.stdin?.pipe(appProcess.stdin);
8285

8386
appProcess.on('error', (error): void => {
84-
console.log(`Error in app process: ${error}`);
87+
logger.error(`Error in app process: ${error}`);
8588
reject(error);
8689
process.exitCode = 1;
8790
});

genkit-tools/cli/src/commands/ui-start.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
import {
18+
findProjectRoot,
1819
findServersDir,
1920
isValidDevToolsInfo,
2021
logger,
@@ -53,7 +54,7 @@ export const uiStart = new Command('ui:start')
5354
} else {
5455
port = await getPort({ port: makeRange(4000, 4099) });
5556
}
56-
const serversDir = await findServersDir();
57+
const serversDir = await findServersDir(await findProjectRoot());
5758
const toolsJsonPath = path.join(serversDir, 'tools.json');
5859
try {
5960
const toolsJsonContent = await fs.readFile(toolsJsonPath, 'utf-8');

0 commit comments

Comments
 (0)