← Back to article
Open article →
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
genkitand@genkit-ai/mcpinstalled without package resolution failure. - A Genkit tool declared with
inputSchemaandoutputSchemawas exposed bycreateMcpServer. - The official MCP SDK client discovered the
riskScoretool. - 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.