Google ADK를 사용하여 AI 에이전트를 구축하고, 이 에이전트가 MCP 서버에 연결하여 외부 도구를 활용하도록 하는 것은 ADK의 강력한 기능 중 하나이다. 이를 통해 에이전트는 자체적으로 구현되지 않은 다양한 기능을 수행할 수 있게 된다.
A. ADK 에이전트 기본 설정 (Basic ADK Agent Setup)
LlmAgent 또는 AdkApp 초기화 (Initializing LlmAgent or AdkApp)
ADK 에이전트를 만들기 위한 기본 클래스로 LlmAgent 또는 AdkApp을 사용할 수 있다.
- LlmAgent: 거대 언어 모델(LLM)을 핵심 추론 엔진으로 사용하는 단일 에이전트를 정의하는 데 적합하다. 일반적으로 모델, 에이전트 이름, 기본 지침(instruction), 그리고 사용할 도구 목록을 인자로 받아 초기화한다.
- AdkApp: 보다 포괄적인 ADK 애플리케이션 컨테이너 역할을 하며, 세션 관리, 여러 에이전트 통합 등의 기능을 포함할 수 있다. 간단한 MCP 클라이언트 에이전트의 경우 LlmAgent로 시작하는 것이 일반적이다.
예시:
from google.adk.agents import LlmAgent
# 모델 이름은 사용 가능한 최신 모델 또는 특정 요구에 맞는 모델로 지정
# 예: "gemini-1.5-flash-preview-0514" 또는 Vertex AI에서 제공하는 다른 모델
agent = LlmAgent(
model="gemini-1.5-flash-preview-0514", # Vertex AI 모델 사용 시 GCP 프로젝트 및 위치 설정 필요
name="my_mcp_client_agent",
instruction="당신은 사용자의 요청을 이해하고, 필요한 경우 외부 도구를 사용하여 답변하는 지능형 비서입니다."
)
모델 및 기본 지침 설정 (Configuring model and basic instructions)
- 모델 설정: 에이전트가 추론 및 의사결정에 사용할 LLM 모델을 지정한다. Google Cloud 환경에서는 Vertex AI를 통해 Gemini와 같은 최신 모델을 사용할 수 있다. LlmAgent의 model 매개변수에 모델 이름을 문자열로 전달한다.
- 기본 지침 (Instruction) 설정: instruction 매개변수는 LLM에게 에이전트의 역할, 목표, 행동 방식, 그리고 특히 사용 가능한 도구들을 어떻게 활용해야 하는지에 대한 명확하고 구체적인 지침을 제공한다. 이 지침은 LLM이 MCP 서버로부터 가져온 도구들을 언제, 어떻게, 왜 사용해야 하는지 결정하는 데 결정적인 역할을 한다. MCP를 통해 외부 도구를 사용하는 에이전트의 경우, 이 instruction의 중요성은 더욱 커진다. 단순히 에이전트의 페르소나를 정의하는 것을 넘어, 사용 가능한 MCP 도구들과 그 도구들을 활용한 문제 해결 전략을 명시하는 "메타-프롬프트"로서 기능해야 한다. 예를 들어, "사용자가 특정 주제에 대한 Wikipedia 기사를 요청하면, 'extract_wikipedia_article' 도구를 사용하여 해당 URL에서 내용을 가져온 후, 그 내용을 바탕으로 사용자에게 몇 문장으로 요약해 주세요."와 같이 구체적인 도구 사용법을 포함하는 것이 좋다. 이는 LLM이 모호한 상황에서 올바른 도구를 선택하고 효과적으로 사용하는 데 큰 도움을 준다.
B. MCP 서버 연결 및 도구 연동 (Connecting to MCP Server and Integrating Tools)
MCPToolset 소개 및 사용법 (Introduction and usage of MCPToolset)
MCPToolset은 ADK 에이전트가 외부 MCP 서버에 연결하고, 해당 서버가 제공하는 도구들을 가져와 에이전트의 기능으로 통합할 수 있도록 지원하는 핵심 클래스이다. MCPToolset은 MCP 서버와의 통신 복잡성(연결 설정, 도구 목록화, 도구 호출 등)을 상당 부분 추상화하여 ADK 개발자가 MCP 도구를 마치 로컬 ADK 도구처럼 비교적 쉽게 사용할 수 있도록 한다. 이는 개발 효율성을 크게 높이는 장점이 있지만, 추상화 수준이 높을수록 세밀한 통신 제어나 MCPToolset이 직접 지원하지 않는 MCP 기능(예: MCP 사양의 '리소스'나 '프롬프트' 프리미티브에 대한 직접 접근)을 사용하기에는 한계가 있을 수 있다.
MCPToolset.from_server()를 이용한 연결 (Connecting using MCPToolset.from_server())
MCPToolset.from_server()는 비동기 메서드로서, 지정된 MCP 서버에 실제로 연결하고 해당 서버가 제공하는 도구 목록을 가져오는 주된 방법이다.
- connection_params: 이 인자를 통해 연결할 MCP 서버의 주소, 포트, 그리고 사용할 전송 프로토콜에 대한 정보를 전달한다.
- 반환 값: 성공적으로 연결되면 (tools, exit_stack) 형태의 튜플을 반환한다.
- tools: MCP 서버로부터 가져온 도구 객체들의 리스트이다. 이 도구 객체들은 ADK 에이전트가 직접 사용할 수 있는 형태로 제공된다.
- exit_stack: 연결과 관련된 리소스(예: 네트워크 연결, 백그라운드 프로세스)를 안전하게 관리하고 해제하기 위한 AsyncExitStack 객체이다. 이는 주로 async with 구문과 함께 사용되어 프로그램 종료 시 리소스가 자동으로 정리되도록 한다.
지원되는 전송 프로토콜: SSE (SseServerParams), Stdio (StdioServerParameters) (Supported transport protocols: SSE, Stdio)
MCPToolset.from_server()의 connection_params에 전달되는 객체에 따라 MCP 서버와의 통신 방식이 결정된다. 현재 Google ADK 공식 문서에서 주로 언급되는 방식은 다음과 같다 :
- SSE (SseServerParams): 원격 MCP 서버와 HTTP 기반의 Server-Sent Events를 통해 통신할 때 사용된다.
Python
from google.adk.tools.mcp_tool.mcp_toolset import SseServerParams sse_params = SseServerParams(url="http://<mcp_server_host>:<port>/sse") # 예: sse_params = SseServerParams(url="http://localhost:8001/sse")
-
- Stdio (StdioServerParameters): 로컬 시스템에서 실행 중인 MCP 서버 프로세스와 표준 입출력(stdin/stdout)을 통해 직접 통신할 때 사용된다. 이는 주로 개발 및 테스트 단계에서 로컬 MCP 서버를 연동할 때 유용하다.
Python
from google.adk.tools.mcp_tool.mcp_toolset import StdioServerParameters # 예: 로컬 파일 시스템 MCP 서버 (Node.js 기반) 실행 stdio_params = StdioServerParameters( command='npx', # 실행할 명령어 args=[ # 명령어에 전달할 인자들 "-y", "@modelcontextprotocol/server-filesystem", # MCP 파일 시스템 서버 패키지 "/path/to/accessible/folder" # 서버가 접근할 로컬 폴더 경로 (절대 경로 권장) ] )
-
- Streamable HTTP 관련 참고: 에서는 omarbenhamid/google-adk-python이라는 커뮤니티 포크(fork)에서 Streamable HTTP 전송 방식을 지원한다고 언급하고 있다. Streamable HTTP는 양방향 스트리밍에 더 적합할 수 있는 최신 MCP 전송 방식 중 하나이다. 그러나 2024년 중반 현재, Google ADK의 공식 배포판 및 문서에서는 SSE와 Stdio를 주요 지원 방식으로 명시하고 있다. 따라서 이 보고서에서는 공식 지원을 기준으로 설명하며, Streamable HTTP는 향후 공식 지원될 가능성이 있는 커뮤니티 동향으로 간주한다. 프로덕션 환경에서는 공식 지원되는 안정적인 기능을 우선적으로 고려하는 것이 좋다.
-
가져온 도구를 ADK 에이전트에 통합 (Integrating fetched tools into ADK Agent)
MCPToolset.from_server()를 통해 성공적으로 가져온 tools 리스트는 LlmAgent를 초기화할 때 tools= 인자에 전달된다. 이렇게 함으로써 ADK 에이전트는 해당 MCP 도구들을 자신의 능력 중 하나로 인식하고, LLM의 판단에 따라 필요시 호출할 수 있게 된다.
# (이전 단계에서 mcp_tools, exit_stack = await MCPToolset.from_server(...) 로 도구들을 가져왔다고 가정)
agent = LlmAgent(
model="gemini-1.5-flash-preview-0514",
name="my_mcp_client_agent",
instruction="사용자의 질문에 답하기 위해 Wikipedia 검색 도구를 활용하세요.",
tools=mcp_tools # MCP 서버로부터 가져온 도구 리스트를 전달
)
예제: Wikipedia 추출 MCP 서버에 연결하는 ADK 에이전트 구현 (Example: Implementing an ADK agent connecting to the Wikipedia extraction MCP server)
앞서 IV 섹션에서 구현한 Wikipedia 아티클 추출 MCP 서버 (server.py가 http://localhost:8001에서 실행 중이라고 가정)에 연결하여 해당 서버의 extract_wikipedia_article 도구를 사용하는 ADK 에이전트의 예제 코드는 다음과 같다.
agent_client.py (Wikipedia 추출 MCP 서버용 ADK 클라이언트)
import asyncio
import os
from dotenv import load_dotenv
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, SseServerParams
from google.adk.runners import AdkRunner, InProcessAdkRunner # Runner 추가
#.env 파일에서 환경 변수 로드 (예: GOOGLE_CLOUD_PROJECT 등)
load_dotenv()
# MCP 서버의 SSE 엔드포인트 URL
MCP_SERVER_SSE_URL = "http://localhost:8001/sse" # IV 섹션의 서버가 이 주소에서 실행 중이라고 가정
async def get_mcp_tools_async():
"""지정된 MCP 서버에 연결하여 도구들을 가져옵니다."""
print(f"'{MCP_SERVER_SSE_URL}' MCP 서버에서 도구를 가져오는 중...")
try:
tools, exit_stack = await MCPToolset.from_server(
connection_params=SseServerParams(url=MCP_SERVER_SSE_URL)
)
print(f"MCP 서버로부터 {len(tools)}개의 도구를 성공적으로 가져왔습니다.")
# 가져온 도구 정보 출력 (디버깅용)
for tool in tools:
print(f" - 도구 이름: {tool.name}, 설명: {tool.description}")
return tools, exit_stack
except Exception as e:
print(f"MCP 서버에서 도구를 가져오는 데 실패했습니다: {e}")
return, None # 실패 시 빈 리스트와 None 반환
async def create_wikipedia_agent_async():
"""MCP 도구를 사용하는 Wikipedia 요약 에이전트를 생성합니다."""
mcp_tools, exit_stack = await get_mcp_tools_async()
if not mcp_tools or exit_stack is None:
print("MCP 도구를 가져오지 못해 에이전트를 생성할 수 없습니다.")
return None, None
# 에이전트에게 MCP 도구 사용 방법을 명확히 지시
agent_instruction = (
"당신은 사용자가 제공한 Wikipedia URL의 기사 내용을 요약하는 AI 비서입니다.\n"
"사용 가능한 도구 중 'extract_wikipedia_article' 도구를 사용하여 Wikipedia 기사 내용을 가져오세요.\n"
"가져온 내용이 너무 길 경우, 핵심 내용을 중심으로 3-5 문장으로 요약하여 사용자에게 친절하게 설명해주세요.\n"
"만약 도구 사용 중 오류가 발생하면, 사용자에게 오류 상황을 알리고 다른 요청을 하도록 안내하세요."
)
root_agent = LlmAgent(
model=os.getenv("GOOGLE_GENAI_MODEL", "gemini-1.5-flash-preview-0514"), # 환경 변수 또는 기본값 사용
name="wikipedia_summary_agent",
instruction=agent_instruction,
tools=mcp_tools, # MCP 서버로부터 가져온 도구 통합
)
print("Wikipedia 요약 에이전트가 성공적으로 생성되었습니다.")
return root_agent, exit_stack
async def main():
"""에이전트를 생성하고 사용자 입력을 받아 처리하는 메인 함수입니다."""
agent, exit_stack = await create_wikipedia_agent_async()
if agent is None or exit_stack is None:
print("에이전트 초기화 실패. 프로그램을 종료합니다.")
return
# exit_stack을 사용하여 리소스 자동 정리
async with exit_stack:
runner = InProcessAdkRunner() # 간단한 인프로세스 러너 사용
print("\nWikipedia 요약 에이전트와 대화를 시작합니다. 종료하려면 'exit'을 입력하세요.")
print("예시 질문: 'https://en.wikipedia.org/wiki/Artificial_intelligence' 기사를 요약해줘.")
while True:
user_input = input("사용자: ")
if user_input.lower() == 'exit':
print("프로그램을 종료합니다.")
break
if not user_input:
continue
print("에이전트 처리 중...")
try:
# runner.run()은 AdkApp에서 주로 사용. LlmAgent는 직접 query 또는 stream_query 호출 가능
# 여기서는 LlmAgent의 stream_query를 직접 사용하는 예시를 보여줌
# 세션 관리가 필요하다면 AdkApp과 함께 사용해야 함
async for chunk in agent.stream_query(user_input):
# chunk는 보통 딕셔너리 형태이며, 'text' 키에 응답 내용이 담겨 있을 수 있음
if isinstance(chunk, dict) and "text" in chunk:
print(f"에이전트: {chunk['text']}", end="", flush=True)
elif isinstance(chunk, str): # 단순 텍스트 응답도 처리
print(f"에이전트: {chunk}", end="", flush=True)
print() # 줄바꿈
except Exception as e:
print(f"\n에이전트 처리 중 오류 발생: {e}")
if __name__ == "__main__":
# GCP 프로젝트 및 위치 설정 (Vertex AI 사용 시 필수)
# 이 정보는 환경 변수 (GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION) 또는
# google.cloud.aiplatform.init() 등을 통해 설정될 수 있음
# load_dotenv()를 통해.env 파일에서 읽어올 수 있도록 하는 것이 좋음
# 예:.env 파일 내용
# GOOGLE_CLOUD_PROJECT="your-gcp-project-id"
# GOOGLE_CLOUD_LOCATION="us-central1"
# GOOGLE_GENAI_MODEL="gemini-1.5-flash-preview-0514"
# GOOGLE_GENAI_USE_VERTEXAI="True" # ADK가 Vertex AI를 사용하도록 지시
if not os.getenv("GOOGLE_CLOUD_PROJECT") or not os.getenv("GOOGLE_CLOUD_LOCATION"):
print("경고: GOOGLE_CLOUD_PROJECT 또는 GOOGLE_CLOUD_LOCATION 환경 변수가 설정되지 않았습니다.")
print("Vertex AI 모델 사용 시 오류가 발생할 수 있습니다.")
asyncio.run(main())
코드 설명:
- 환경 설정 및 Import: 필요한 라이브러리( asyncio, LlmAgent, MCPToolset, SseServerParams 등)를 가져오고, dotenv를 사용하여 .env 파일에 저장된 환경 변수(예: Google Cloud 프로젝트 ID, 위치, 사용할 모델명)를 로드한다.
- get_mcp_tools_async(): MCPToolset.from_server()를 호출하여 지정된 MCP_SERVER_SSE_URL (여기서는 http://localhost:8001/sse)로 MCP 서버에 연결하고, 서버가 제공하는 도구 목록과 exit_stack을 가져온다. 도구 정보를 간단히 출력하여 확인한다.
- create_wikipedia_agent_async(): get_mcp_tools_async()를 호출하여 MCP 도구들을 가져온 후, LlmAgent를 생성한다.
- model: 사용할 LLM 모델을 지정한다 (환경 변수 GOOGLE_GENAI_MODEL 또는 기본값 사용).
- name: 에이전트의 이름을 부여한다.
- instruction: 에이전트의 역할과 함께, MCP 서버로부터 가져온 extract_wikipedia_article 도구를 어떻게 사용해야 하는지에 대한 명확한 지침을 제공한다.
- tools: get_mcp_tools_async()를 통해 가져온 mcp_tools 리스트를 전달하여 에이전트가 해당 도구들을 사용할 수 있도록 한다.
- main(): 에이전트를 생성하고, async with exit_stack: 구문을 사용하여 MCP 연결 관련 리소스가 프로그램 종료 시 자동으로 정리되도록 한다. InProcessAdkRunner (또는 직접 agent.stream_query)를 사용하여 사용자 입력을 받아 에이전트에게 전달하고, 에이전트의 응답을 스트리밍 형태로 출력한다.
- 실행: 스크립트 실행 시, 필요한 환경 변수(특히 Vertex AI 사용 시 GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION)가 설정되어 있는지 확인하는 로직을 추가했다.
이 에이전트를 실행하고 "https://en.wikipedia.org/wiki/Artificial_intelligence 기사를 요약해줘."와 같은 질문을 하면, 에이전트는 LLM의 판단에 따라 extract_wikipedia_article MCP 도구를 호출하여 Wikipedia 서버로부터 해당 URL의 내용을 가져온 후, 그 내용을 바탕으로 사용자에게 요약된 답변을 제공할 것이다.
ADK는 adk web이라는 명령어를 통해 개발자용 웹 UI를 제공하여, 에이전트와의 상호작용, 도구 호출 과정, 내부 상태 등을 시각적으로 확인하며 테스트할 수 있는 편리한 기능을 제공한다. 이를 활용하면 MCP 클라이언트 에이전트의 개발 및 디버깅 효율을 높일 수 있다.
'에이전트' 카테고리의 다른 글
구조화된 출력이 활성화된 경우 도구 호출 기능은 비활성화 되는 문제 해결 방안. (0) | 2025.05.20 |
---|---|
ADK를 이용한 MCP의 효율적인 개발을 위한 고급 고려 사항 (Advanced Considerations for Efficient Development) (0) | 2025.05.20 |
Google ADK 및 MCP를 활용한 효율적인 MCP 서버 및 클라이언트 구축 가이드 (1) | 2025.05.20 |
LangGraph 기초 (1) | 2025.05.19 |
Langgraph 기반 시스템 개발 베스트 프랙티스 (0) | 2025.05.14 |