Gemini와 MCP 공식 라이브러리로 구현한 Obsidian Agent 연동기

소개

Obsidian에 스스로 연결되는 에이전트를 만들고 싶어서 시작한 실험이었습니다. 원래는 Claude와의 연동을 생각했지만, Gemini에서도 MCP 사용이 가능하다는 이야기를 듣고 "어떻게 가능한 거지?"라는 궁금증이 생겨 시도하게 되었습니다.

진행 방법

사용 도구 및 환경

  • Gemini API

  • MCP Python SDK (@mcp)

  • Obsidian MCP 플러그인

  • dotenv, asyncio 기반 환경 구성

예상과 다른 전개

처음에는 Gemini SDK의 MCP 관련 기능을 쓰는 줄 알고 시작했지만, 알고 보니 제가 잘못 이해한 것이었고, 결국 공식 MCP Python SDK를 직접 사용해서 구현하게 되었습니다. 결과적으로 Gemini SDK는 사용하지 않고, MCP 라이브러리로 저수준부터 통합을 진행하게 되었어요.


MCP Python SDK를 활용한 Obsidian 통합 개발 과정

현재 진행 중인 프로젝트는 Model Context Protocol(MCP) Python SDK를 활용하여 Gemini AI와 Obsidian을 통합하는 클라이언트 애플리케이션입니다. 다음은 개발 과정과 구현된 주요 기능입니다:

1. MCP 클라이언트 구현

from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
  • MCP 클라이언트 세션: ClientSession 클래스를 활용하여 Obsidian MCP 서버와 통신합니다.

  • 표준 입출력 기반 통신: stdio_clientStdioServerParameters를 사용하여 Obsidian MCP 서버와의 통신을 설정합니다.

2. 서버 연결 설정

MCP_SERVER_CONFIG = {
    "command": "npx",
    "args": args
}

npx 명령어를 통해 Obsidian MCP 서버를 시작하고, 환경 변수에서 로드한 볼트 경로를 인자로 전달합니다.

3. 비동기 통신 구현

async with stdio_client(server_params) as (read_stream, write_stream):
    async with ClientSession(read_stream, write_stream) as session:
        await session.initialize()

MCP SDK의 비동기 통신 패턴을 활용하여 서버와의 통신을 구현했습니다.

4. 도구 및 볼트 관리

# 사용 가능한 도구 확인
tools_result = await session.list_tools()
tools = tools_result.tools

# 사용 가능한 볼트 확인
vault_result = await session.call_tool("list-available-vaults", {})

5. Gemini API 통합

client = genai.Client(api_key=GEMINI_API_KEY)
analysis_response = client.models.generate_content(
    model=MODEL_NAME,
    contents=contents
)

6. 동적 도구 선택 및 매개변수 검증

if "vault" in parameters:
    if not parameters["vault"] or parameters["vault"] not in [v['id'] for v in available_vaults]:
        old_vault_id = parameters["vault"]
        # ...

7. 오류 처리 및 예외 관리

try:
    tool_result = await session.call_tool(selected_tool, parameters)
except Exception as e:
    print(f"\n도구 실행 중 오류 발생: {e}")

8. 환경 변수 관리

load_dotenv(override=True)
VAULT_ID_1 = os.getenv("VAULT_ID_1", "")

개발 과정에서 해결한 문제들

  1. 볼트 ID 처리 문제: 문자열 리터럴로 처리되지 않아 템플릿 변수로 오동작하던 문제 해결

  2. 매개변수 검증 강화: 누락 시 기본값 설정

  3. JSON 직렬화 문제: MCP 도구 결과 객체의 직렬화 문제 해결

  4. 환경 변수 로드 타이밍: 실행 중 환경 변수가 올바르게 반영되도록 개선

결과와 배운 점

  • Gemini SDK가 아닌, MCP 공식 라이브러리 기반의 저수준 연동이었음

  • 생애 첫 Agent 구현이었지만 3시간 내 구현 완료 🎉

  • 졸린 상태에서도 할 수 있을 만큼 복잡하지 않았고, 재미있는 경험이었음

  • Obsidian과 Gemini의 연동 가능성을 확인함

도움 받은 글

MCP의 세 가지 기능(프롬프트, 리소스, 도구) 중 도구(Tools) 기능을 중심으로 활용함

1

👉 이 게시글도 읽어보세요