MCP (Model Context Protocol)
MCP는 Hermes Agent가 Hermes 밖에 있는 외부 도구 서버에 연결할 수 있게 합니다. GitHub, 데이터베이스, 파일 시스템, 브라우저 스택, 내부 API 등 이미 다른 곳에 존재하는 도구를 에이전트가 사용할 수 있습니다.
Hermes가 외부에 이미 존재하는 도구를 쓰게 만들고 싶다면, MCP가 보통 가장 깔끔한 방법입니다.
MCP가 제공하는 것
- 네이티브 Hermes 도구를 먼저 작성하지 않고 외부 도구 생태계에 접근
- 로컬 stdio 서버와 원격 HTTP MCP 서버를 같은 설정에서 사용
- 시작 시 자동 도구 검색 및 등록
- 서버가 지원할 경우 MCP 리소스와 프롬프트를 위한 유틸리티 래퍼 제공
- 서버별 필터링으로 Hermes가 실제로 봐야 하는 MCP 도구만 노출
빠른 시작
- MCP 지원을 설치합니다. 표준 설치 스크립트를 사용했다면 이미 포함되어 있습니다.
cd ~/.hermes/hermes-agent
uv pip install -e ".[mcp]"
~/.hermes/config.yaml에 MCP 서버를 추가합니다.
mcp_servers:
filesystem:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
- Hermes를 시작합니다.
hermes chat
- Hermes에게 MCP 기반 기능을 사용하라고 요청합니다.
예:
/home/user/projects의 파일을 나열하고 저장소 구조를 요약해 줘.
Hermes는 MCP 서버의 도구를 검색하고 다른 도구와 같은 방식으로 사용합니다.
MCP 서버의 두 종류
Stdio 서버
Stdio 서버는 로컬 하위 프로세스로 실행되며 stdin/stdout으로 통신합니다.
mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
다음 경우 stdio 서버를 사용합니다.
- 서버가 로컬에 설치되어 있음
- 로컬 리소스에 낮은 지연 시간으로 접근해야 함
- MCP 서버 문서가
command,args,env를 사용하는 예제를 보여 줌
HTTP 서버
HTTP MCP 서버는 Hermes가 직접 연결하는 원격 엔드포인트입니다.
mcp_servers:
remote_api:
url: "https://mcp.example.com/mcp"
headers:
Authorization: "Bearer ***"
다음 경우 HTTP 서버를 사용합니다.
- MCP 서버가 다른 곳에 호스팅되어 있음
- 조직이 내부 MCP 엔드포인트를 노출함
- 해당 통합을 위해 Hermes가 로컬 하위 프로세스를 생성하지 않게 하고 싶음
기본 설정 참조
Hermes는 ~/.hermes/config.yaml의 mcp_servers 아래에서 MCP 설정을 읽습니다.
공통 키
| 키 | 유형 | 의미 |
|---|---|---|
command | string | stdio MCP 서버 실행 파일 |
args | list | stdio 서버 인수 |
env | mapping | stdio 서버에 전달할 환경 변수 |
url | string | HTTP MCP 엔드포인트 |
headers | mapping | 원격 서버용 HTTP 헤더 |
timeout | number | 도구 호출 제한 시간 |
connect_timeout | number | 초기 연결 제한 시간 |
enabled | bool | false이면 Hermes가 서버를 완전히 건너뜁니다. |
supports_parallel_tool_calls | bool | true이면 이 서버의 도구를 동시에 실행할 수 있습니다. |
tools | mapping | 서버별 도구 필터링 및 유틸리티 정책 |
최소 stdio 예제
mcp_servers:
filesystem:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
최소 HTTP 예제
mcp_servers:
company_api:
url: "https://mcp.internal.example.com"
headers:
Authorization: "Bearer ***"
Hermes가 MCP 도구를 등록하는 방식
Hermes는 MCP 도구 이름 앞에 접두사를 붙여 내장 이름과 충돌하지 않게 합니다.
mcp_<server_name>_<tool_name>
예:
| 서버 | MCP 도구 | 등록 이름 |
|---|---|---|
filesystem | read_file | mcp_filesystem_read_file |
github | create-issue | mcp_github_create_issue |
my-api | query.data | mcp_my_api_query_data |
실무에서는 접두사가 붙은 이름을 수동으로 호출할 필요가 거의 없습니다. Hermes가 도구를 보고 일반 추론 과정에서 선택합니다.
MCP 유틸리티 도구
지원되는 경우 Hermes는 MCP 리소스와 프롬프트를 다루는 유틸리티 도구도 등록합니다.
list_resourcesread_resourcelist_promptsget_prompt
이 유틸리티 도구는 서버별로 같은 접두사 패턴을 사용해 등록됩니다. 예:
mcp_github_list_resourcesmcp_github_get_prompt
중요
이 유틸리티 도구들은 이제 서버 기능을 확인한 뒤 등록됩니다.
- MCP 세션이 리소스 작업을 실제로 지원할 때만 Hermes가 리소스 유틸리티를 등록합니다.
- MCP 세션이 프롬프트 작업을 실제로 지원할 때만 Hermes가 프롬프트 유틸리티를 등록합니다.
따라서 호출 가능한 도구는 있지만 리소스/프롬프트가 없는 서버에는 추가 래퍼가 생기지 않습니다.
서버별 필터링
각 MCP 서버가 Hermes에 제공하는 도구를 제어할 수 있습니다. 이렇게 하면 도구 네임스페이스를 세밀하게 관리할 수 있습니다.
서버 완전히 비활성화
mcp_servers:
legacy:
url: "https://mcp.legacy.internal"
enabled: false
enabled: false이면 Hermes는 해당 서버를 완전히 건너뛰며 연결도 시도하지 않습니다.
서버 도구 허용 목록
mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
tools:
include: [create_issue, list_issues]
지정한 MCP 서버 도구만 등록됩니다.
서버 도구 차단 목록
mcp_servers:
stripe:
url: "https://mcp.stripe.com"
tools:
exclude: [delete_customer]
제외한 도구를 빼고 모든 서버 도구가 등록됩니다.
우선순위 규칙
둘 다 있으면:
tools:
include: [create_issue]
exclude: [create_issue, delete_issue]
include가 우선합니다.
유틸리티 도구도 필터링
Hermes가 추가하는 유틸리티 래퍼도 따로 비활성화할 수 있습니다.
mcp_servers:
docs:
url: "https://mcp.docs.example.com"
tools:
prompts: false
resources: false
의미:
tools.resources: false는list_resources와read_resource를 비활성화합니다.tools.prompts: false는list_prompts와get_prompt를 비활성화합니다.
전체 예제
mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
tools:
include: [create_issue, list_issues, search_code]
prompts: false
stripe:
url: "https://mcp.stripe.com"
headers:
Authorization: "Bearer ***"
tools:
exclude: [delete_customer]
resources: false
legacy:
url: "https://mcp.legacy.internal"
enabled: false
모든 것이 필터링되면 어떻게 되나요?
설정이 호출 가능한 도구를 모두 필터링하고, 지원되는 유틸리티도 모두 비활성화하거나 생략했다면 Hermes는 해당 서버에 대해 빈 런타임 MCP 툴셋을 만들지 않습니다.
도구 목록을 깔끔하게 유지하기 위한 동작입니다.
런타임 동작
검색 시점
Hermes는 시작 시 MCP 서버를 검색하고 해당 도구를 일반 도구 레지스트리에 등록합니다.
동적 도구 검색
MCP 서버는 런타임에 사용 가능한 도구가 바뀌면 notifications/tools/list_changed 알림을 보내 Hermes에 알릴 수 있습니다. Hermes가 이 알림을 받으면 서버의 도구 목록을 자동으로 다시 가져오고 레지스트리를 업데이트합니다. 수동 /reload-mcp는 필요 없습니다.
이는 기능이 동적으로 바뀌는 MCP 서버에 유용합니다. 예를 들어 새 데이터베이스 스키마가 로드될 때 도구를 추가하거나, 서비스가 오프라인이 되면 도구를 제거하는 서버가 여기에 해당합니다.
새로고침은 lock으로 보호됩니다. 같은 서버에서 알림이 빠르게 여러 번 와도 겹치는 새로고침이 발생하지 않습니다. 프롬프트와 리소스 변경 알림(prompts/list_changed, resources/list_changed)은 수신하지만 아직 동작에 반영하지 않습니다.
다시 로드
MCP 설정을 바꿨다면 다음을 사용합니다.
/reload-mcp
이 명령은 설정에서 MCP 서버를 다시 로드하고 사용 가능한 도구 목록을 새로고침합니다. 서버가 런타임 도구 변경을 직접 푸시하는 경우는 위의 동적 도구 검색을 참고하세요.
툴셋
설정된 MCP 서버가 하나 이상의 등록된 도구를 제공하면 런타임 툴셋도 생성됩니다.
mcp-<server>
툴셋 수준에서 MCP 서버를 더 쉽게 이해할 수 있게 하기 위한 동작입니다.
보안 모델
Stdio 환경 변수 필터링
stdio 서버의 경우 Hermes는 사용자의 전체 셸 환경을 무조건 넘기지 않습니다.
명시적으로 설정한 env와 안전한 기본값만 전달합니다. 이렇게 하면 비밀값이 우발적으로 새는 위험을 줄일 수 있습니다.
설정 수준 노출 제어
새 필터링 지원은 보안 제어이기도 합니다.
- 모델에게 보이면 안 되는 위험한 도구 비활성화
- 민감한 서버에는 최소 허용 목록만 노출
- 노출하고 싶지 않은 리소스/프롬프트 래퍼 비활성화
사용 사례 예제
최소 이슈 관리 표면을 가진 GitHub 서버
mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
tools:
include: [list_issues, create_issue, update_issue]
prompts: false
resources: false
사용 예:
bug 라벨이 붙은 열린 이슈를 보여 주고, 불안정한 MCP 재연결 동작에 대한 새 이슈 초안을 작성해 줘.
위험한 작업을 제거한 Stripe 서버
mcp_servers:
stripe:
url: "https://mcp.stripe.com"
headers:
Authorization: "Bearer ***"
tools:
exclude: [delete_customer, refund_payment]
사용 예:
최근 실패한 결제 10건을 조회하고 공통 실패 원인을 요약해 줘.
단일 프로젝트 루트용 Filesystem 서버
mcp_servers:
project_fs:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/my-project"]
사용 예:
프로젝트 루트를 검사하고 디렉터리 구성을 설명해 줘.
문제 해결
MCP 서버가 연결되지 않음
확인할 것:
# MCP 의존성이 설치되어 있는지 확인합니다(표준 설치에는 이미 포함됨).
cd ~/.hermes/hermes-agent && uv pip install -e ".[mcp]"
node --version
npx --version
그런 다음 설정을 확인하고 Hermes를 재시작합니다.
도구가 나타나지 않음
가능한 원인:
- 서버 연결 실패
- 검색 실패
- 필터 설정이 도구를 제외함
- 해당 서버에 유틸리티 기능이 없음
- 서버가
enabled: false로 비활성화됨
의도적으로 필터링 중이라면 정상입니다.
리소스 또는 프롬프트 유틸리티가 왜 나타나지 않나요?
Hermes는 이제 다음 두 조건이 모두 참일 때만 래퍼를 등록합니다.
- 설정이 해당 유틸리티를 허용함
- 서버 세션이 실제로 기능을 지원함
이는 의도된 동작이며 도구 목록을 실제 기능과 일치하게 유지합니다.
병렬 도구 호출
기본적으로 MCP 도구는 하나씩 순차 실행됩니다. MCP 서버가 동시에 실행해도 안전한 도구를 제공한다면(예: 읽기 전용 쿼리, 독립 API 호출), 병렬 실행을 옵트인할 수 있습니다.
mcp_servers:
docs:
command: "docs-server"
supports_parallel_tool_calls: true
supports_parallel_tool_calls가 true이면 Hermes는 내장 읽기 전용 도구(web_search, read_file 등)처럼 한 도구 호출 배치 안에서 해당 서버의 여러 도구를 동시에 실행할 수 있습니다.
동시에 실행해도 안전한 MCP 서버에만 병렬 호출을 켜세요. 도구가 공유 상태, 파일, 데이터베이스, 외부 리소스를 읽고 쓴다면 이 설정을 켜기 전에 읽기/쓰기 경쟁 조건을 검토해야 합니다.
MCP Sampling 지원
MCP 서버는 sampling/createMessage 프로토콜을 통해 Hermes에 LLM 추론을 요청할 수 있습니다. 이를 통해 MCP 서버는 자체 모델 접근 권한이 없어도 Hermes에게 텍스트 생성을 대신 요청할 수 있습니다.
sampling은 MCP SDK가 지원하는 경우 모든 MCP 서버에 대해 기본으로 활성화됩니다. 서버별로 sampling 키 아래에서 설정합니다.
mcp_servers:
my_server:
command: "my-mcp-server"
sampling:
enabled: true # sampling 활성화(기본값: true)
model: "openai/gpt-4o" # sampling 요청에 사용할 모델 재정의(선택)
max_tokens_cap: 4096 # sampling 응답당 최대 토큰 수(기본값: 4096)
timeout: 30 # 요청당 제한 시간(초, 기본값: 30)
max_rpm: 10 # 속도 제한: 분당 최대 요청 수(기본값: 10)
max_tool_rounds: 5 # sampling 루프에서 도구 사용 최대 라운드(기본값: 5)
allowed_models: [] # 서버가 요청할 수 있는 모델 이름 허용 목록(비어 있으면 제한 없음)
log_level: "info" # 감사 로그 수준: debug, info, warning(기본값: info)
sampling 핸들러에는 폭주 사용량을 막기 위해 슬라이딩 윈도우 레이트 리미터, 요청별 제한 시간, 도구 루프 깊이 제한이 포함됩니다. 지표(request count, errors, tokens used)는 서버 인스턴스별로 추적됩니다.
특정 서버에서 sampling을 비활성화하려면:
mcp_servers:
untrusted_server:
url: "https://mcp.example.com"
sampling:
enabled: false
Hermes를 MCP 서버로 실행
Hermes는 MCP 서버에 연결할 뿐 아니라, 자체적으로 MCP 서버가 될 수도 있습니다. 이 기능을 사용하면 Claude Code, Cursor, Codex 또는 다른 MCP 지원 에이전트가 Hermes의 메시징 기능을 사용할 수 있습니다. 대화 목록을 보고, 메시지 기록을 읽고, 연결된 모든 플랫폼으로 메시지를 보낼 수 있습니다.
사용할 때
- Claude Code, Cursor 또는 다른 코딩 에이전트가 Hermes를 통해 Telegram/Discord/Slack 메시지를 읽고 보내게 하고 싶음
- Hermes에 연결된 모든 메시징 플랫폼으로 브리지하는 단일 MCP 서버가 필요함
- 연결된 플랫폼이 있는 Hermes 게이트웨이가 이미 실행 중임
빠른 시작
hermes mcp serve
이 명령은 stdio MCP 서버를 시작합니다. 프로세스 생명주기는 사용자가 아니라 MCP 클라이언트가 관리합니다.
MCP 클라이언트 설정
Hermes를 MCP 클라이언트 설정에 추가합니다. 예를 들어 Claude Code의 ~/.claude/claude_desktop_config.json:
{
"mcpServers": {
"hermes": {
"command": "hermes",
"args": ["mcp", "serve"]
}
}
}
Hermes를 특정 위치에 설치했다면:
{
"mcpServers": {
"hermes": {
"command": "/home/user/.hermes/hermes-agent/venv/bin/hermes",
"args": ["mcp", "serve"]
}
}
}
사용 가능한 도구
MCP 서버는 OpenClaw의 채널 브리지 인터페이스에 Hermes 전용 채널 브라우저를 더한 10개 도구를 노출합니다.
| 도구 | 설명 |
|---|---|
conversations_list | 활성 메시징 대화를 나열합니다. 플랫폼으로 필터링하거나 이름으로 검색할 수 있습니다. |
conversation_get | 세션 키로 특정 대화의 상세 정보를 가져옵니다. |
messages_read | 대화의 최근 메시지 기록을 읽습니다. |
attachments_fetch | 특정 메시지에서 텍스트가 아닌 첨부파일(image, media)을 추출합니다. |
events_poll | 커서 위치 이후의 새 대화 이벤트를 폴링합니다. |
events_wait | 다음 이벤트가 올 때까지 long-poll/block합니다(준실시간). |
messages_send | 플랫폼을 통해 메시지를 보냅니다. 예: telegram:123456, discord:#general |
channels_list | 모든 플랫폼에서 사용 가능한 메시징 대상을 나열합니다. |
permissions_list_open | 이 브리지 세션에서 관찰된 대기 중인 승인 요청을 나열합니다. |
permissions_respond | 대기 중인 승인 요청을 allow 또는 deny합니다. |
이벤트 시스템
MCP 서버에는 Hermes 세션 데이터베이스에서 새 메시지를 폴링하는 실시간 이벤트 브리지가 포함되어 있습니다. 이를 통해 MCP 클라이언트는 들어오는 대화를 거의 실시간으로 인식할 수 있습니다.
# 새 이벤트를 폴링합니다(논블로킹).
events_poll(after_cursor=0)
# 다음 이벤트를 기다립니다(제한 시간까지 블로킹).
events_wait(after_cursor=42, timeout_ms=30000)
이벤트 유형: message, approval_requested, approval_resolved
이벤트 큐는 인메모리이며 브리지가 연결될 때 시작됩니다. 이전 메시지는 messages_read로 접근할 수 있습니다.
옵션
hermes mcp serve # 일반 모드
hermes mcp serve --verbose # stderr에 디버그 로그 출력
동작 방식
MCP 서버는 Hermes 세션 저장소(~/.hermes/sessions/sessions.json 및 SQLite 데이터베이스)에서 대화 데이터를 직접 읽습니다. 백그라운드 스레드가 데이터베이스에서 새 메시지를 폴링하고 인메모리 이벤트 큐를 유지합니다. 메시지 전송에는 Hermes 에이전트 자체와 같은 send_message 인프라를 사용합니다.
게이트웨이는 읽기 작업(conversation listing, 기록 읽기, 이벤트 폴링)에는 실행 중일 필요가 없습니다. 전송 작업에는 플랫폼 어댑터의 활성 연결이 필요하므로 게이트웨이가 실행 중이어야 합니다.
현재 제한
- stdio transport만 지원(아직 HTTP MCP transport 없음)
- mtime 최적화 DB 폴링으로 약 200ms 간격 이벤트 폴링(file이 바뀌지 않으면 작업을 건너뜀)
- 아직
claude/channel푸시 알림 프로토콜 없음 - 텍스트 전송만 지원(
messages_send로 미디어/첨부파일 전송 불가)