이 글은 Gemini 기반 MCP 서버 및 클라이언트를 개발하는 방법을 간략히 보여준다.
MCP의 개념과 상세한 동작 방식은 다음 글을 참고한다.
개요
MCP는 클라이언트-서버 구조를 따른다. 클라이언트는 서버의 MCP 도구를 사용하는 AI 앱이나 LLM을 의미한다. 서버는 MCP 도구를 공급하고, API, 데이터소스 인터페이스를 제공한다. 
MCP를 통해 LLM이 해결하지 못하는 작업은 외부 시스템과 연결해 서비스 받을 수 있다.
MCP서버는 파일 시스템 조작, 웹 검색, 데이터베이스 조작, 버전 관리 등 다양한 도구를 제공할 수 있다. 
제미니 LLM 기반 MCP 구조
다음은 제미니 LLM 기반 MCP 구조 예시를 보여준다. 이 예는 비행기 예약 유스케이스를 구현한다.
- MCP 호스트가 사용자 명령 입력. 예) 내일 인천에서 애틀란타 가는 비행편 찾기
 - 클라이언트 스크립트가 입력을 처리(CLIENT.PY)
 - 클라이언트가 MCP 서버 프로세스 시작(MCP-FLIGHT-SEARCH). STDIO 통신 채널 연결 및 관련 도구 검색
 - 클라이언트가 사용자 명령에 대한 함수 호출 방법을 수신함
 - 클라리언트가 함수 호출 방법에 대한 정확한 함수 호출 형식을 GEMINI에서 획득. 함수 호출 형식에 부합하는 적절한 MCP 도구를 서버에 호출. 서버의 도구 함수 호출 결과를 리턴
 - MCP 서버가 구글 항공편 검색을 위한 SerpAPI를 호출. 구글 항공편 데이터 질의.
 - 구글 항공편 정보 리턴
 - 서버에서 클라이언트로 해당 정보 리턴
 - 클라이언트가 호스로 해당 정보 전달
 
개발 환경
개발을 위한 최소한의 환경은 파이썬 3.8+이다. 이외 다음을 준비한다.- Claude 데스크탑 설치
 
- Google Cloud 에서 Project 생성
 
- Google Gemini API 키 획득
 
- SerpAPI 키 획득
 
다음 종속성을 터미널에서 설치한다. google-genai는 google 생성AI 라이브러리이며, mcp는 MCP 서버 통신을 위한 파이썬 SDK이다. 
pip install google-genai mcp
환경변수를 설정한다. 
export GEMINI_API_KEY="your-google-api-key"
export SERP_API_KEY="your-serpapi-key"
항공편 검색 MCP 서버 설치
MCP 프로토콜 공개 이후로 많은 MCP 서버가 개발되었다. 우리는 항공편 검색 MCP 서버 오픈소스인 mcp-flgiht-search 를 사용한다. 다음을 설치한다.
pip install mcp-flight-search
코딩해보기
다음과 같이 client.py를 코딩한다. 
import os, sys, time, asyncio
from google import genai
from google.genai import types
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from dotenv import load_dotenv
load_dotenv()
gemini_api_key = os.getenv("GEMINI_API_KEY")
serp_api_key = os.getenv("SERP_API_KEY")
client = genai.Client(api_key=gemini_api_key)
server_params = StdioServerParameters(
    command="mcp-flight-search",
    args=["--connection_type", "stdio"],
    env={"SERP_API_KEY": serp_api_key},
)
async def run():
    async with stdio_client(server_params) as (read, write):  # 항공 예약 검색 도구 등록
        async with ClientSession(read, write) as session:
            prompt = f"Find Flights from Atlanta to Las Vegas 2025-08-15"  # 사용자 질의 명령
            await session.initialize()
            mcp_tools = await session.list_tools()  # 도구 리스트 획득
            tools = [
                types.Tool(
                    function_declarations=[
                        {
                            "name": tool.name,
                            "description": tool.description,
                            "parameters": {
                                k: v
                                for k, v in tool.inputSchema.items()
                                if k not in ["additionalProperties", "$schema"]
                            },
                        }
                    ]  # 해당 도구 함수 선언 생성
                )
                for tool in mcp_tools.tools
            ]
            response = client.models.generate_content(
                model="gemini-2.5-pro-exp-03-25",
                contents=prompt,
                config=types.GenerateContentConfig(
                    temperature=0,
                    tools=tools,
                ),  # LLM 모델에 프롬프트 전달.
            )
            if response.candidates[0].content.parts[0].function_call:
                function_call = response.candidates[0].content.parts[0].function_call # 함수호출정보
                result = await session.call_tool(
                    function_call.name, arguments=dict(function_call.args)
                )  # 도구 함수 호출
                print("--- Formatted Result ---") # Add header for clarity
                try:
                    flight_data = json.loads(result.content[0].text)
                    print(json.dumps(flight_data, indent=2))
                except json.JSONDecodeError:
                    print("MCP server returned non-JSON response:")
                    print(result.content[0].text)
                except (IndexError, AttributeError):
                     print("Unexpected result structure from MCP server:")
                     print(result)
            else:
                print("No function call was generated by the model.")
                if response.text:
                     print("Model response:")
                     print(response.text)
asyncio.run(run()) # 클라이언트 실행
실행한다. 그럼 프롬프트에 대해 LLM이 적절한 도구와 파라메터를 확인해 함수 호출 정보를 생성한다. 이를 call_tool로 호출한 결과가 표시된다 
레퍼런스
- Introducing Graphite — An Event Driven AI Agent Framework | by Craig Li, Ph.D | Binome | Apr, 2025 | Medium
 - Model Context Protocol(MCP) with Google Gemini 2.5 Pro - Deep Dive , Google Cloud Gen AI | Google Cloud - Community
 - Model Context Protocol (MCP) with Gemini 2.5 Pro. Convert conversational queries into flight searches using Gemini's function calling capabilities and MCP's flight search tools
 
댓글 없음:
댓글 쓰기