본문 바로가기

AI Agent

Firebase Genkit + MCP 완전 가이드 — Gemini에 외부 툴을 붙이는 Google 공식 방법

반응형

LangChain으로 Gemini 붙이려다 Firebase 생태계랑 안 맞아서 결국 두 배 코드 짠 적 있으시죠. Genkit은 Firebase Functions, Firestore, Cloud Trace를 네이티브로 연결하면서 MCP 서버까지 한 줄로 붙입니다.

[핵심 요약]
→ Genkit: AI 앱 개발용 Google 공식 오픈소스 프레임워크 (JS/TS, Go, Python)
→ MCP 통합: createMcpHost / createMcpClient로 외부 MCP 서버 툴 자동 등록
→ 양방향 지원: MCP 클라이언트(외부 툴 소비) + MCP 서버(내 툴 외부 노출) 모두 가능
→ Firebase Functions 위에서 에이전트 플로우 실행 → Cloud Trace 자동 추적
→ 모델 무관: Gemini, Claude, OpenAI, Ollama, DeepSeek 전부 지원
→ 툴 자동 네임스페이스: fs/read_file, memory/store처럼 서버명으로 자동 분리

 


Genkit이 LangChain 대신인 이유

LangChain + Firebase:
→ Firebase Functions에 LangChain 올리면 콜드스타트 느림
→ Firestore 연동 별도 어댑터 필요
→ Cloud Trace 연동 수동 설정
→ Gemini 모델 업데이트 추적 직접 관리

Genkit + Firebase:
→ Firebase Functions 네이티브 지원 (onCallGenkit 한 줄)
→ Firestore retriever 내장
→ Cloud Trace 자동 연동 (플로우 전 구간 추적)
→ Google AI 모델 플러그인 공식 관리
→ Gemini CLI, Claude Code에서 MCP로 직접 연결 가능

실전 1 — 설치 및 기본 세팅

# 프로젝트 초기화
mkdir genkit-mcp-app && cd genkit-mcp-app
npm init -y
npm install typescript @types/node --save-dev

# Genkit 핵심 패키지
npm install genkit @genkit-ai/google-genai

# MCP 플러그인 (두 가지 중 선택)
npm install @genkit-ai/mcp        # 공식 패키지 (최신)
# 또는
npm install genkitx-mcp           # 커뮤니티 패키지 (레거시)

# Firebase Functions 함께 쓸 경우
npm install firebase-functions firebase-admin
// src/index.ts — 기본 Genkit 세팅
import { genkit } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';

export const ai = genkit({
  plugins: [
    googleAI({ apiKey: process.env.GOOGLE_GENAI_API_KEY }),
  ],
  model: 'googleai/gemini-2.5-flash',  // 기본 모델
});
[Genkit 지원 모델 플러그인]
→ @genkit-ai/google-genai: Gemini 전 시리즈
→ @genkit-ai/anthropic: Claude (Vertex AI 경유)
→ @genkit-ai/ollama: Gemma, Llama, DeepSeek 로컬 실행
→ @genkit-ai/openai: GPT 시리즈
→ 모델 전환: model 파라미터 하나만 바꾸면 됨

실전 2 — MCP 클라이언트: 외부 툴 가져오기

MCP 서버의 툴을 Genkit 에이전트에서 바로 씁니다. 툴은 서버명으로 자동 네임스페이싱됩니다.

단일 서버 연결 (createMcpClient)

import { genkit } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';
import { createMcpClient } from '@genkit-ai/mcp';

// Filesystem MCP 서버 연결
const fsClient = createMcpClient({
  name: 'fs',  // 네임스페이스: fs/read_file, fs/write_file ...
  mcpServer: {
    command: 'npx',
    args: ['-y', '@modelcontextprotocol/server-filesystem', process.cwd()],
  },
});

const ai = genkit({
  plugins: [googleAI()],
});

(async () => {
  await fsClient.ready();  // 서버 연결 대기

  // MCP 툴 자동 탐색 후 모델에 주입
  const tools = await fsClient.getActiveTools(ai);

  const { text } = await ai.generate({
    model: 'googleai/gemini-2.5-flash',
    prompt: '현재 디렉토리의 파일 목록 보여줘',
    tools,  // fs/list_directory, fs/read_file 등 자동 포함
  });

  console.log(text);
  await fsClient.disable();
})();

다중 서버 연결 (createMcpHost)

import { createMcpHost } from '@genkit-ai/mcp';

// 여러 MCP 서버 동시 연결
const mcpHost = createMcpHost({
  name: 'myAgentTools',
  mcpServers: {
    // 키 이름이 네임스페이스
    fs: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-filesystem', process.cwd()],
    },
    memory: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-memory'],
    },
    github: {
      url: 'https://api.githubcopilot.com/mcp/',  // 원격 MCP 서버
      env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! },
    },
  },
});

const ai = genkit({ plugins: [googleAI()] });

(async () => {
  const { text } = await ai.generate({
    model: 'googleai/gemini-2.5-flash',
    prompt: 'README.md 읽고 GitHub 이슈로 등록해줘',
    tools: await mcpHost.getActiveTools(ai),
    // → fs/read_file, memory/store, github/create_issue 전부 사용 가능
  });

  console.log(text);
  await mcpHost.close();
})();
[createMcpClient vs createMcpHost]
→ createMcpClient: 서버 1개 연결, 단순 케이스
→ createMcpHost: 서버 N개 동시 관리, 런타임 연결/해제 지원
→ 네임스페이스: fs/read_file, github/create_issue처럼 서버명 자동 prefix
→ 원격 서버: url 옵션으로 HTTP MCP 서버 연결 가능
→ 로컬 서버: command + args로 subprocess 실행

실전 3 — MCP 서버: 내 Genkit 툴을 외부에 노출

Firestore 데이터 조회, 내부 API 호출 같은 툴을 MCP 서버로 노출합니다. Gemini CLI, Claude Code, Cursor에서 바로 붙여 쓸 수 있습니다.

import { genkit, z } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';
import { mcpServer } from '@genkit-ai/mcp';
import * as admin from 'firebase-admin';

admin.initializeApp();
const db = admin.firestore();

const ai = genkit({ plugins: [googleAI()] });

// Firestore 조회 툴 정의
ai.defineTool(
  {
    name: 'getOrder',
    description: '주문 ID로 주문 정보 조회',
    inputSchema: z.object({
      orderId: z.string().describe('조회할 주문 ID'),
    }),
    outputSchema: z.object({
      orderId: z.string(),
      status: z.string(),
      amount: z.number(),
      createdAt: z.string(),
    }).optional(),
  },
  async ({ orderId }) => {
    const doc = await db.collection('orders').doc(orderId).get();
    if (!doc.exists) return undefined;
    return { orderId: doc.id, ...doc.data() } as any;
  }
);

// 주문 상태 업데이트 툴
ai.defineTool(
  {
    name: 'updateOrderStatus',
    description: '주문 상태 업데이트',
    inputSchema: z.object({
      orderId: z.string(),
      status: z.enum(['pending', 'processing', 'shipped', 'delivered']),
    }),
    outputSchema: z.boolean(),
  },
  async ({ orderId, status }) => {
    await db.collection('orders').doc(orderId).update({ status });
    return true;
  }
);

// ✅ Genkit 앱을 MCP 서버로 노출
mcpServer(ai, {
  name: 'order-management',
  version: '1.0.0',
}).start();
// → getOrder, updateOrderStatus 툴이 MCP 표준으로 노출됨

이제 Claude Code나 Gemini CLI에서 이 서버에 바로 붙을 수 있습니다.

# Claude Code에서 연결
claude mcp add-json "orders" \
  '{"command":"node","args":["dist/index.js"]}'

# Gemini CLI에서 연결
# .gemini/settings.json
{
  "mcpServers": {
    "orders": {
      "command": "node",
      "args": ["dist/index.js"]
    }
  }
}
[MCP 서버 노출 시 주의점]
→ inputSchema는 객체 타입만 가능 (MCP 스펙 제한)
→ 복잡한 중첩 객체는 JSON 직렬화해서 string으로 전달
→ 원격 노출 시 HTTPS + API 키 인증 필수 (MCP 자체 보안 없음)
→ 버전 관리: mcpServer version 필드로 브레이킹 체인지 관리

실전 4 — Firebase Functions 배포 + Cloud Trace

에이전트 플로우를 Firebase Functions 위에 올리고 Cloud Trace로 전 구간 추적합니다.

import { genkit, z } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';
import { createMcpHost } from '@genkit-ai/mcp';
import { onCallGenkit } from 'firebase-functions/https';
import { defineSecret } from 'firebase-functions/params';

// Secret Manager에서 API 키 로드
const geminiKey = defineSecret('GOOGLE_GENAI_API_KEY');
const githubToken = defineSecret('GITHUB_TOKEN');

const mcpHost = createMcpHost({
  name: 'agentTools',
  mcpServers: {
    github: {
      url: 'https://api.githubcopilot.com/mcp/',
      env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! },
    },
  },
});

const ai = genkit({
  plugins: [googleAI()],
});

// 에이전트 플로우 정의
const codeReviewFlow = ai.defineFlow(
  {
    name: 'codeReviewFlow',
    inputSchema: z.object({
      prUrl: z.string(),
      focusArea: z.string().optional(),
    }),
    outputSchema: z.object({
      review: z.string(),
      suggestions: z.array(z.string()),
    }),
  },
  async ({ prUrl, focusArea }) => {
    const tools = await mcpHost.getActiveTools(ai);

    const { output } = await ai.generate({
      model: 'googleai/gemini-2.5-flash',
      prompt: `PR ${prUrl}을 리뷰해줘. ${focusArea ? `특히 ${focusArea} 위주로.` : ''}`,
      tools,
      output: {
        schema: z.object({
          review: z.string(),
          suggestions: z.array(z.string()),
        }),
      },
    });

    return output!;
  }
);

// ✅ Firebase Functions로 배포
export const codeReview = onCallGenkit(
  {
    secrets: [geminiKey, githubToken],
    region: 'asia-northeast3',  // 서울
    cors: true,
  },
  codeReviewFlow
);
[Firebase Functions + Genkit 핵심]
→ onCallGenkit: 플로우를 Callable Function으로 한 줄 배포
→ Secret Manager: defineSecret으로 API 키 안전 관리
→ Cloud Trace: 플로우 실행 전 구간 자동 추적 (별도 설정 불필요)
→ Firebase Console → Genkit → Monitoring에서 트레이스 조회
→ 리전: asia-northeast3 (서울) 선택 시 레이턴시 최소화

마무리

✅ Genkit + MCP 써야 하는 경우
→ Firebase 생태계(Firestore, Auth, Functions) 메인으로 쓰는 팀
→ Gemini 모델 기반 앱에 외부 MCP 툴 붙이고 싶을 때
→ 내부 Firestore/API 툴을 Claude Code나 Gemini CLI에 노출하고 싶을 때
→ Cloud Trace로 에이전트 실행 흐름 추적이 필요한 프로덕션 환경
→ Flutter/Android 앱 백엔드에 AI 에이전트 붙이는 경우

❌ Genkit이 맞지 않는 경우
→ AWS나 Azure 생태계 메인인 팀 (Firebase 연동 이점 없음)
→ LangGraph처럼 복잡한 상태 머신 기반 에이전트가 필요한 경우
→ Python 메인 팀 (Python SDK는 아직 알파)
→ Anthropic/OpenAI API만 쓰고 Google 생태계 아예 안 쓰는 팀

 

반응형