안녕하세요,
최근 다양한 오픈소스 언어 모델들이 등장하면서, AI 모델을 로컬 환경이나 경량 디바이스에서 직접 실행하는 사례가 점점 늘어나고 있습니다. 하지만 로컬에서 실행되는 모델은 종종 단순한 텍스트 생성기에 머무르기 쉬우며, 외부 도구나 시스템과의 연동에는 제약이 따르는 경우가 많습니다.
이번 포스팅은 로컬에서 실행되는 AI 모델과 MCP 서버가 실제로 연동 가능한지 확인하고, 두 시스템이 문제 없이 호환될 수 있다는 점을 직접 검증하는 것에 있습니다. 이를 통해 로컬 AI 모델도 클라우드 기반 에이전트처럼 외부 도구와 상호작용할 수 있다는 가능성을 확인해볼 수 있습니다.
그럼 지금부터 로컬 AI 모델과 MCP 서버를 연동하는 방법을 함께 살펴보겠습니다.
개요
이 글에서는 구글이 개발한 경량 오픈소스 모델 Gemma3와, Anthropic이 제안한 오픈 표준 프로토콜 MCP (Model Context Protocol)를 연동하는 방법을 소개합니다. MCP는 AI 모델이 외부 리소스나 도구와 안전하게 상호작용할 수 있도록 설계된 통신 프로토콜로, 이를 통해 AI 모델이 단순한 텍스트 생성기를 넘어, 실제 기능을 수행하는 에이전트로 확장될 수 있습니다.
이번 포스팅에서는 Gemma3 모델을 로컬 환경에 설치하고, 간단한 MCP 서버를 구성하여 Gemma3를 통해 해당 MCP 서버 호출 및 결과값을 보는 과정으로 진행하겠습니다.
실행 환경
- 운영체제 : Windows 11
- uv : 0.6.14
- python : 3.10.17
- accelerate : 1.7.0
- torch : 2.6.0+cu126
- mcp : 1.9.3
- numpy : 1.24.4
전체 구성
로컬 환경에서 Gemma3 모델을 실행하고, 이를 통해 MCP 서버와 연동하여 도구 호출 결과를 확인하는 전체 과정을 단계별로 소개합니다. 각 단계는 다음과 같이 구성됩니다.
- 환경 설정
프로젝트에 필요한 Python 패키지와 가상 환경 관리 도구인 uv를 설치하고, 기본적인 개발 환경을 구성합니다. - 모델 다운로드
구글에서 배포한 Gemma3 모델(gemma-3-4b-it)을 로컬에 다운로드합니다. - 코드 작성
MCP 서버, Gemma3 모델 실행 코드를 구성해줍니다. - Gemma3 ↔ MCP 연동 및 실행 테스트
Gemma3 모델이 MCP 서버와 연동되어 도구를 호출하는 전체 흐름을 테스트합니다. 모델이 도구 호출 요청을 생성하고, MCP 서버가 이를 처리한 후 응답을 반환하는 전 과정을 실행하며 결과를 확인합니다.
1. 환경 설정
Gemma3와 MCP 서버를 연동하기 위해, Python 기반의 개발 환경을 먼저 준비합니다. 이 단계에서는 패키지 관리 도구인 uv를 설치하고, 가상환경을 생성한 뒤 필요한 패키지들을 설치합니다.
[uv 설치]
MCP 서버를 Python 환경에서 구성하려면, 먼저 패키지 및 가상환경 관리를 위한 도구인 uv를 설치해야 합니다. uv는 pip과 venv를 대체할 수 있는 빠르고 효율적인 패키지 관리 도구입니다. 아래 명령어를 통해 설치할 수 있습니다.
- uv 깃허브 : https://github.com/astral-sh/uv
# Windows PowerShell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
[가상 환경 생성] (선택사항)
uv 설치가 완료되면, 프로젝트 디렉토리를 초기화하고 가상환경을 생성한 뒤 필요한 패키지를 설치합니다. 가상환경을 사용하는 것을 권장하며, 아래 명령어를 순서대로 실행합니다.
# Windows PowerShell
cd \path\to\mcp-server # 1. 원하는 작업 디렉토리로 이동 (예: D:\mcp-server)
uv init mcp-test # 2. 'mcp-test'라는 이름의 프로젝트 초기화
cd mcp-test # 3. 생성된 프로젝트 폴더로 이동
uv venv --python=python3.10 # 4. Python 3.10 기반 가상환경 생성 (.venv 디렉토리 생성)
uv add mcp[cli] transformers accelerate # 5. MCP, Transformers, Accelerate 패키지 설치
uv pip install torch==2.6.0 --index-url https://download.pytorch.org/whl/cu126 # 6. CUDA 버전 Torch 설치
.venv\Scripts\activate # 7. 가상환경 활성화 (Windows 기준)
⚠️ 참고사항
- torch==2.6.0은 CUDA 12.6 버전에 최적화되어 있으므로, 해당 버전을 지원하는 GPU 드라이버가 설치되어 있어야 합니다.
- CUDA가 설치되어 있지 않은 경우 6번(torch 설치) 명령어는 생략하고 CPU 버전 Torch를 자동 설치해도 무방합니다.
- 위 단계는 선택 사항이지만, 프로젝트별 환경 격리를 위해 사용하는 것을 권장합니다.
2. 모델 다운로드
구글에서 제공하는 "gemma-3-4b-it" 모델을 허깅페이스에서 다운로드합니다. 아래 링크에 접속하여 모델 디렉토리 내의 모든 파일을 다운로드합니다.
3. 코드 작성
간단한 계산기 기능을 수행하는 MCP 서버를 구성하고, Gemma3 모델을 불러와 해당 서버와 연동될 수 있도록 코드를 작성합니다.
작성한 코드는 앞서 생성한 uv 프로젝트 내에 포함하여 구성합니다.
이 코드는 사용자의 질문에 대해 Gemma3가 상황에 따라 도구 호출을 결정하고, MCP 서버와의 연동을 통해 실제 기능을 수행할 수 있도록 구현된 예제입니다.
[MCP 서버 코드 - mcp_server.py]
# Python
from mcp.server.fastmcp import FastMCP
# MCP 서버 초기화
mcp = FastMCP("Simple Adder")
# MCP 도구(tool) 등록
@mcp.tool(name="calculator")
def calculator(operation: str, numbers: list[int]) -> int:
if operation == "+":
return sum(numbers)
elif operation == "-":
return numbers[0] - sum(numbers[1:])
elif operation == "*":
result = 1
for n in numbers:
result *= n
return result
elif operation == "/":
result = numbers[0]
for n in numbers[1:]:
result /= n
return result
else:
raise ValueError(f"Unsupported operation: {operation}")
# 서버 실행
if __name__ == "__main__":
mcp.run()
[Gemma3 실행 코드 - gemma_client.py]
# Python
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
import json
import asyncio
from mcp import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
# --- 1. Gemma 모델 로딩 ---
model_path = "/path/to/gemma-3-4b-it" # 사용자 경로에 맞게 수정 (gemma3 모델 위치)
print(f"Gemma 3 모델을 로딩 중... 경로: {model_path}")
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path, device_map="auto")
print("Gemma 모델 로딩 완료!")
def gemma_generate(prompt: str) -> str:
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=100)
input_length = inputs["input_ids"].shape[1]
new_tokens = outputs[0][input_length:]
return tokenizer.decode(new_tokens, skip_special_tokens=True)
# --- 2. Gemma + MCP 통합 실행 ---
async def run_gemma_mcp():
server_params = StdioServerParameters(
command="python",
args=["mcp_server.py"], # MCP 서버 코드 (uv 프로젝트 위치)
env={"PYTHONPATH": "/path/to/mcp-server"}, # 사용자 경로에 맞게 수정 (uv 프로젝트 위치)
cwd="/path/to/mcp-server" # 사용자 경로에 맞게 수정 (uv 프로젝트 위치)
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
print("MCP 연결 완료")
tools = await session.list_tools()
print("MCP 등록 도구:", tools)
# 사용자 입력
user_command = input("명령을 입력하세요: ")
# 1차 프롬프트: Gemma에게 직접 물어봄
messages = [
{
"role": "system",
"content": (
"You are an assistant that can either respond directly in natural language "
"or decide to call a tool by returning a JSON object with 'method' and 'parameters'.\n"
"If a tool call is needed, ONLY return the JSON. Otherwise, respond naturally."
"'{\"method\": \"calculator\", \"parameters\": {\"operation\": \"+\", \"numbers\": [3, 5]}}'"
)
},
{"role": "user", "content": user_command}
]
prompt_str = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
gemma_response = gemma_generate(prompt_str)
print("Gemma 응답:", gemma_response)
# MCP tool 호출 여부 판단
if "method" in gemma_response:
print("MCP tool 호출 시작")
else:
print("Gemma 내부 추론으로 응답 생성됨 (MCP 호출 생략)")
# JSON 파싱
try:
json_str = gemma_response[gemma_response.find("{"):gemma_response.rfind("}") + 1]
call = json.loads(json_str)
method = call["method"]
args = call["parameters"]
print(f"MCP Tool 호출 중: {method}({args})")
result = await session.call_tool(method, arguments=args)
content = result.content[0] if isinstance(result.content, list) else result.content
tool_result = content.text
print(f"MCP Tool 응답: {tool_result}")
# 결과를 Gemma에게 다시 전달해 자연어로 응답 요청
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": f"질문: {user_command}"},
{"role": "tool", "content": f"{method}의 결과는 {tool_result}입니다."},
{"role": "user", "content": "위 내용을 바탕으로 자연스럽게 설명해줘."}
]
followup_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
final_response = gemma_generate(followup_prompt)
print(f"최종 응답: {final_response}")
except (json.JSONDecodeError, KeyError):
# 툴 호출이 아닌 일반 응답이면 그대로 출력
print(f"최종 응답: {gemma_response}")
if __name__ == "__main__":
asyncio.run(run_gemma_mcp())
4. Gemma3 ↔ MCP 연동 및 실행 테스트
앞서 작성한 코드를 실행하면, Gemma3 모델과 MCP 서버가 정상적으로 연동되는지 확인할 수 있습니다. 예를 들어 사용자가 덧셈과 관련된 프롬프트 (예 : 5 + 5)와 같은 명령을 입력했을때 Gemma3는 이를 분석한 후 외부 도구 호출이 필요하다고 판단하면, MCP 서버에 등록된 calculator 도구를 호출하는 방식으로 동작합니다. 아래 이미지에서 확인할 수 있는 실행 흐름은 다음과 같습니다.
- Gemma3 모델 로딩 완료
- MCP 서버 연결 및 도구 목록 확인
- 사용자 입력: "calculator tool 사용해서 5+5 결과값 알려줘"
- Gemma3의 판단: calculator 도구 호출이 필요하다고 인식하고 JSON 응답 생성
- MCP 도구 호출: calculator 도구에 operation: "+", numbers: [5, 5]를 전달
- MCP 응답 수신: 결과값 10 반환
- Gemma3가 자연어로 최종 응답 생성 → “계산기를 사용해서 5 더하기 5를 계산하면 결과는 10입니다. 😊”
이 과정을 통해 Gemma3 모델이 MCP 서버를 통해 외부 기능을 호출하고, 그 결과를 바탕으로 자연어 응답을 생성하는 전체 흐름이 성공적으로 작동함을 확인할 수 있습니다
Gemma3가 외부 도구 호출이 필요하지 않다고 판단한 경우에는 MCP 서버를 거치지 않고, 내부 추론만으로 바로 자연어 응답을 생성하며, 출력은 다음과 같은 형태로 나타납니다.
- 사용자 입력: "구글에 대해 설명해주세요"
이번 포스팅에서는 로컬에서 실행되는 Gemma3 모델과 MCP 서버를 연동하는 기본적인 방법에 대해 살펴보았습니다.
Claude 데스크톱 환경에서는 MCP 서버만 구현하면 즉시 연동이 가능하지만, 로컬 모델에서도 동일한 방식이 적용될 수 있는지에 대한 궁금증에서 출발한 실험이었고, 그 결과 로컬 모델 역시 MCP와 충분히 연동하여 동작할 수 있음을 확인할 수 있었습니다.
이번 예제에서는 단순한 계산기 기능만 구현했지만, 실제로는 공개된 MCP 서버들 중 더 정교하고 다양한 기능을 제공하는 사례도 많습니다.
다음 포스팅에서는 이러한 고도화된 MCP 서버를 실제로 활용하여, Gemma 또는 Qwen 모델과 연동하는 방법을 다뤄보겠습니다.
읽어주셔서 감사합니다. 😊
'MCP' 카테고리의 다른 글
AI 자동화를 위한 필수 도구, MCP 서버 모음 (0) | 2025.05.13 |
---|---|
[MCP 서버] PDF 문서에서 답을 찾는 Claude AI 만들기 (0) | 2025.04.23 |
MCP를 활용해서 나만의 AI 에이전트 만들기 (데스크톱 Claude 활용) (1) | 2025.04.16 |
클로드에서 공개한 MCP(Model Context Protocol), 그 개념과 특징 (1) | 2025.03.29 |