Skip to content
Effloow
← Back to article
EFFLOOW LAB LAB-RUN ·2026-05-28

Genkit 2.0 GA: Build and Deploy a TypeScript MCP Server to Cloud Run

Evidence notes document the bounded local or source-based checks behind an Effloow article. They are not product endorsements, legal advice, or benchmark claims.

Objective

Verify the local, credential-free part of the backlog topic:

  • Install current Genkit MCP packages in a temporary Node.js sandbox.
  • Define one deterministic typed Genkit tool.
  • Expose it as an MCP server with createMcpServer.
  • Connect with the official MCP SDK client and call the tool.
  • Record the deployment limitation honestly: Cloud Run deployment, Secret Manager setup, and Cloud Trace inspection were not run because they require a real Google Cloud project, billing, credentials, and production-side confirmation.

Environment

  • Date: 2026-05-28
  • Host OS: macOS
  • Sandbox directory: /tmp/effloow-genkit-mcp-poc
  • Node.js: v25.9.0
  • npm: 11.12.1
  • Network: npm registry access used for package install and metadata lookup
  • Secrets: none used
  • Google Cloud credentials: none used

Commands

rm -rf /tmp/effloow-genkit-mcp-poc
mkdir -p /tmp/effloow-genkit-mcp-poc
cd /tmp/effloow-genkit-mcp-poc
npm init -y
npm install genkit @genkit-ai/mcp @modelcontextprotocol/sdk zod
npm pkg set type=module scripts.start="node server.mjs" scripts.verify="node verify.mjs"
npm list genkit @genkit-ai/mcp @modelcontextprotocol/sdk --depth=0
node -v
npm -v
npm run verify
npm audit --omit=dev --json
npm view genkit version license time.modified
npm view @genkit-ai/mcp version license time.modified
npm view @modelcontextprotocol/sdk version license time.modified

Files Created in the Temporary Sandbox

server.mjs:

import { createMcpServer } from '@genkit-ai/mcp';
import { genkit, z } from 'genkit/beta';

const ai = genkit({});

ai.defineTool(
  {
    name: 'riskScore',
    description: 'Classify a deployment change by deterministic risk rules.',
    inputSchema: z.object({
      changedFiles: z.array(z.string()),
      touchesAuth: z.boolean().default(false),
      touchesBilling: z.boolean().default(false),
    }),
    outputSchema: z.object({
      score: z.number(),
      label: z.enum(['low', 'medium', 'high']),
      reasons: z.array(z.string()),
    }),
  },
  async ({ changedFiles, touchesAuth, touchesBilling }) => {
    const reasons = [];
    let score = Math.min(changedFiles.length * 10, 40);

    if (touchesAuth) {
      score += 35;
      reasons.push('authentication surface changed');
    }

    if (touchesBilling) {
      score += 30;
      reasons.push('billing path changed');
    }

    if (changedFiles.some((file) => file.includes('migration'))) {
      score += 20;
      reasons.push('database migration present');
    }

    const capped = Math.min(score, 100);
    const label = capped >= 70 ? 'high' : capped >= 35 ? 'medium' : 'low';

    return {
      score: capped,
      label,
      reasons: reasons.length ? reasons : ['small isolated change'],
    };
  },
);

const server = createMcpServer(ai, {
  name: 'effloow_genkit_mcp_poc',
  version: '0.0.1',
});

server.start();

verify.mjs:

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';

const transport = new StdioClientTransport({
  command: 'node',
  args: ['server.mjs'],
  cwd: process.cwd(),
});

const client = new Client({
  name: 'effloow-verifier',
  version: '0.0.1',
});

await client.connect(transport);

const tools = await client.listTools();
const toolNames = tools.tools.map((tool) => tool.name).sort();
console.log('tools:', toolNames.join(', '));

const result = await client.callTool({
  name: 'riskScore',
  arguments: {
    changedFiles: ['routes/api.ts', 'database/migration_add_invoices.sql'],
    touchesAuth: true,
    touchesBilling: false,
  },
});

console.log('riskScore result:', JSON.stringify(result.content));

await client.close();

Output

Package versions:

effloow-genkit-mcp-poc@1.0.0 /private/tmp/effloow-genkit-mcp-poc
├── @genkit-ai/mcp@1.36.0
├── @modelcontextprotocol/sdk@1.29.0
└── genkit@1.36.0

v25.9.0
11.12.1

MCP verification:

> effloow-genkit-mcp-poc@1.0.0 verify
> node verify.mjs

tools: riskScore
riskScore result: [{"type":"text","text":"{\"score\":75,\"label\":\"high\",\"reasons\":[\"authentication surface changed\",\"database migration present\"]}"}]

npm audit summary:

{
  "vulnerabilities": {
    "info": 0,
    "low": 0,
    "moderate": 16,
    "high": 7,
    "critical": 0,
    "total": 23
  },
  "dependencies": {
    "prod": 221,
    "dev": 0,
    "optional": 266,
    "peer": 52,
    "peerOptional": 0,
    "total": 486
  }
}

npm metadata:

genkit: 1.36.0, Apache-2.0, modified 2026-05-27T17:19:25.973Z
@genkit-ai/mcp: 1.36.0, Apache-2.0, modified 2026-05-27T17:20:04.886Z
@modelcontextprotocol/sdk: 1.29.0, MIT, modified 2026-03-30T16:50:43.186Z

What Worked

  • Current genkit and @genkit-ai/mcp installed without package resolution failure.
  • A Genkit tool declared with inputSchema and outputSchema was exposed by createMcpServer.
  • The official MCP SDK client discovered the riskScore tool.
  • The client successfully called the tool over stdio and received a JSON string inside MCP text content.
  • The sandbox required no LLM API key, no Gemini call, no Google Cloud account, and no production secrets.

What Failed or Was Not Attempted

  • Cloud Run deployment was not attempted.
  • Cloud Trace or Genkit Monitoring evidence was not captured.
  • Secret Manager setup was not attempted.
  • No remote Streamable HTTP MCP endpoint was tested.
  • No live model call was made.
  • npm audit reported 23 vulnerabilities in the installed dependency tree. This is a dependency-review signal, not proof of exploitability in the specific local demo.

Limitations

This note supports the claim that Effloow Lab ran a local Genkit MCP PoC. It does not support any claim that Effloow deployed the server to Cloud Run, configured Firebase/Google Cloud observability, measured production latency, tested billing behavior, or validated a public authenticated endpoint.

Read the article

This note supports the public article and records what was actually checked.

Open article →