๐ค ํ ์ค์ฆ๊ถ ๊ณต์ open api ๋ฅผ ์ฌ์ฉํ๋ mcp ์๋ฒ
TossInvest MCP
ํ ์ค์ฆ๊ถ ๊ณต์ Open API๋ฅผ Hermes Agent ๊ฐ์ MCP ํด๋ผ์ด์ธํธ์์ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ ์คํ์์ค MCP ์๋ฒ์ ๋๋ค.
๊ตญ๋ดยท๋ฏธ๊ตญ ์ฃผ์์ ์ข ๋ชฉ ์ ๋ณด์ ์์ธ, ๊ณ์ข ์์ฐ, ์ฃผ๋ฌธ ๋ด์ญ์ ์กฐํํ ์ ์์ต๋๋ค. ์ฃผ๋ฌธ ๊ธฐ๋ฅ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊บผ์ ธ ์์ผ๋ฉฐ, ๋ณ๋๋ก ํ์ฑํํ ๊ฒฝ์ฐ์๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ MCP ์ฑ๋ ๋ฐ์ ์ฌ๋ ์น์ธ ์ ์ฐจ๋ฅผ ํต๊ณผํด์ผ ์ฃผ๋ฌธ ์์ฑยท์ ์ ยท์ทจ์๊ฐ ์คํ๋ฉ๋๋ค.
์ด ํ๋ก์ ํธ๋ ํ ์ค์ฆ๊ถ์ ๊ณต์ ์ ํ์ด ์๋ ๋ ๋ฆฝ ์คํ์์ค ํ๋ก์ ํธ์ ๋๋ค. ํฌ์ ์กฐ์ธ์ ์ ๊ณตํ์ง ์์ผ๋ฉฐ, ์ด ์๋ฒ๋ฅผ ํตํด ์คํํ ์ฃผ๋ฌธ๊ณผ ๊ทธ ๊ฒฐ๊ณผ์ ๋ํ ์ฑ ์์ ์ฌ์ฉ์์๊ฒ ์์ต๋๋ค.
๋ชฉ์ฐจ
- ์ฃผ์ ํน์ง
- ๋์ ๊ตฌ์กฐ
- ๋น ๋ฅธ ์์
- ํ ์ค์ฆ๊ถ API ์ธ์ฆ ์ ๋ณด ์ค๋น
- ํ๊ฒฝ๋ณ์ ์ค์
- Docker๋ก ์คํ
- Hermes Agent ์ฐ๊ฒฐ
- Hermes Skill ์ค์น
- ์ ๊ณต ๋๊ตฌ
- ์ฃผ๋ฌธ ๊ธฐ๋ฅ ํ์ฑํ
- ์ฃผ๋ฌธ ์์ ์ฅ์น
- ์๋ต๊ณผ ์ค๋ฅ ํ์
- ์ด์๊ณผ ๋ณด์
- ๋ก์ปฌ ๊ฐ๋ฐ
- ๋ฌธ์ ํด๊ฒฐ
- ํ์ฌ ์ ํ์ฌํญ
์ฃผ์ ํน์ง
- ํ ์ค์ฆ๊ถ Open API v1.1.1์ ๋ชจ๋ ์กฐํ operation ์ง์
- OAuth 2.0 Client Credentials ํ ํฐ ์๋ ๋ฐ๊ธ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ์บ์
- ํ ํฐ ๋ง๋ฃ 60์ด ์ ์ ์ ๊ฐฑ์ ๊ณผ ๋์ ๊ฐฑ์ ๋ฐฉ์ง
- ๊ณต์ API ๊ทธ๋ฃน๋ณ ๋ก์ปฌ rate limit ์ ์ฉ
- ์กฐํ ์์ฒญ์
429 Too Many Requests๋ง ์ ํ์ ์ผ๋ก ์ฌ์๋ - ์ฃผ๋ฌธ ์์ฑยท์ ์ ยท์ทจ์ ์์ฒญ์ ์ด๋ค ๊ฒฝ์ฐ์๋ ์๋ ์ฌ์๋ํ์ง ์์
- ๊ณ์ข๋ฒํธ์ account sequence๋ฅผ MCP ์๋ต์์ ์ ๊ฑฐ
- ๊ธฐ๋ณธ ์กฐํ ์ ์ฉ ๋ชจ๋
- ์ฃผ๋ฌธ ์์ฑยท์ ์ ยท์ทจ์์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ โ ๋ณ๋ ์ฌ๋ ์น์ธ โ ์คํ ํ๋ฆ
- ์์ด์ ํธ token๊ณผ ๋ถ๋ฆฌ๋ ์ฌ๋ ์ ์ฉ ์น์ธ token
- 2๋ถ ํ ๋ง๋ฃ๋๋ ์ผํ์ฉ ์ฃผ๋ฌธ ์น์ธ ์ํ
- ์ํยท๋ฌ๋ฌ ์ฃผ๋ฌธ ํ๋์ 1์ต์ ์ด์ ์ฃผ๋ฌธ์ ๊ฐ์ ์ฐจ๋จ
- ๊ตญ๋ด ์์ฅ๊ฐ ์ฃผ๋ฌธ์ ํ์ฌ๊ฐ๊ฐ ์๋ ๊ณต์ ์ํ๊ฐ ๊ธฐ์ค์ผ๋ก ๋ณด์์ ์ผ๋ก ๊ฒ์ฌ
- ๋งค์ ๊ฐ๋ฅ ๊ธ์ก๊ณผ ํ๋งค ๊ฐ๋ฅ ์๋์ ์ฃผ๋ฌธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋จ๊ณ์์ ๊ฒ์ฆ
- Bearer ์ธ์ฆ๊ณผ Origin ๊ฒ์ฌ๊ฐ ์ ์ฉ๋ Streamable HTTP MCP
- ์กฐํยท๋ฏธ๋ฆฌ๋ณด๊ธฐยท์คํ ์ํ๋๋ฅผ ๊ตฌ๋ถํ๋ MCP Tool annotation๊ณผ ๊ตฌ์กฐํ๋ ์๋ต schema
- non-root, read-only filesystem, capability ์ ๊ฑฐ๊ฐ ์ ์ฉ๋ Docker ๊ตฌ์ฑ
- ์กฐํ ์ ์ฉ๊ณผ ๊ฑฐ๋ ์ ์ฐจ๋ฅผ ๋ถ๋ฆฌํ Hermes Agent Skill ์ ๊ณต
๋์ ๊ตฌ์กฐ
flowchart LR
U["์ฌ์ฉ์"] --> H["Hermes Agent"]
H -->|"MCP Streamable HTTP<br/>Bearer ์ธ์ฆ"| M["TossInvest MCP"]
U -->|"๋ณ๋ ์น์ธ ํ์ด์ง<br/>์ฌ๋ ์ ์ฉ token"| M
M --> A["OAuth ํ ํฐ ์บ์"]
M --> R["Rate Limiter"]
M --> S["์ฃผ๋ฌธ ์์ ์ฅ์น"]
A --> T["ํ ์ค์ฆ๊ถ Open API"]
R --> T
S --> T
TossInvest MCP๋ ํ ์ค์ฆ๊ถ ์ธ์ฆ ์ ๋ณด๋ฅผ Hermes์ ์ ๋ฌํ์ง ์์ต๋๋ค. ์๋ฒ๊ฐ ๋ด๋ถ์ ์ผ๋ก OAuth ํ ํฐ์ ๋ฐ๊ธํ๊ณ , Hermes์๋ ํ์ํ MCP ๋๊ตฌ์ ์ ์ ๋ ๊ฒฐ๊ณผ๋ง ๋ ธ์ถํฉ๋๋ค.
๊ธฐ๋ณธ ์คํ ์ฃผ์:
| ์ฉ๋ | ์ฃผ์ |
| --- | --- |
| MCP endpoint | http://127.0.0.1:8000/mcp |
| ํ๋ก์ธ์ค ์ํ | http://127.0.0.1:8000/healthz |
| ํ ์ค API ์ธ์ฆ ์ค๋น ์ํ | http://127.0.0.1:8000/readyz |
๋น ๋ฅธ ์์
์ค๋น๋ฌผ
- ํ ์ค์ฆ๊ถ Open API
client_id,client_secret - Docker ๋ฐ Docker Compose
- Hermes Agent
- ์ค์ ํ์ผ์ ํธ์งํ ์ ์๋ ๊ธฐ๋ณธ์ ์ธ ํฐ๋ฏธ๋ ํ๊ฒฝ
1. ์ ์ฅ์ ๋ฐ๊ธฐ
git clone https://github.com/cha2hyun/tossinvest-mcp.git
cd tossinvest-mcp
2. ํ๊ฒฝ๋ณ์ ํ์ผ ๋ง๋ค๊ธฐ
cp .env.example .env
openssl rand -hex 32
์ถ๋ ฅ๋ ์์ ๋ฌธ์์ด์ .env์ MCP_AUTH_TOKEN์ ๋ฃ์ต๋๋ค. ์ด ๊ฐ์
TOSSINVEST_CLIENT_SECRET๊ณผ ๋ฐ๋์ ๋ฌ๋ผ์ผ ํฉ๋๋ค.
์ต์ ์ค์ ์์:
TOSSINVEST_CLIENT_ID=๋ฐ๊ธ๋ฐ์_client_id
TOSSINVEST_CLIENT_SECRET=๋ฐ๊ธ๋ฐ์_client_secret
TOSSINVEST_ACCOUNT_SEQ=1
MCP_AUTH_TOKEN=openssl๋ก_์์ฑํ_์ถฉ๋ถํ_๊ธด_์์_๋ฌธ์์ด
MCP_PUBLISHED_PORT=8000
LOG_LEVEL=INFO
TOSSINVEST_ACCOUNT_SEQ์ ์ค์ ๊ฐ์ ๊ณ์ข๋ง๋ค ๋ค๋ฅผ ์ ์์ต๋๋ค. ํ์ธ ๋ฐฉ๋ฒ์
๊ณ์ข sequence ํ์ธ์ ์ฐธ๊ณ ํ์ธ์.
3. ์๋ฒ ์คํ
docker compose up -d --build
4. ์ํ ํ์ธ
curl http://127.0.0.1:8000/healthz
curl http://127.0.0.1:8000/readyz
docker compose ps
docker compose logs -f tossinvest-mcp
์ ์ ์ํ ์์:
{"status":"ok","service":"tossinvest-mcp"}
readyz๋ ํ ์ค์ฆ๊ถ OAuth ํ ํฐ ๋ฐ๊ธ๊น์ง ํ์ธํ๋ฏ๋ก ์ธ์ฆ ์ ๋ณด๊ฐ ์๋ชป๋ ๊ฒฝ์ฐ 503์
๋ฐํํฉ๋๋ค.
ํ ์ค์ฆ๊ถ API ์ธ์ฆ ์ ๋ณด ์ค๋น
- ํ ์ค์ฆ๊ถ WTS์ ๋ก๊ทธ์ธํฉ๋๋ค.
- ์ค์ ์ Open API ๋ฉ๋ด์์ API ํด๋ผ์ด์ธํธ๋ฅผ ๋ฑ๋กํฉ๋๋ค.
- ๋ฐ๊ธ๋
client_id์client_secret์ ์์ ํ๊ฒ ๋ณด๊ดํฉ๋๋ค. - ๋ ๊ฐ์ TossInvest MCP ์๋ฒ์
.env์๋ง ์ ์ฅํฉ๋๋ค.
client_secret์ Git ์ ์ฅ์, Hermes ์ค์ , ํ๋กฌํํธ, ์ฑํ
, ๋ก๊ทธ์ ๋ฃ์ผ๋ฉด ์ ๋ฉ๋๋ค.
๊ณ์ข sequence ํ์ธ
๊ณ์ขยท์์ฐยท์ฃผ๋ฌธ API๋ X-Tossinvest-Account ํค๋์ accountSeq๊ฐ ํ์ํฉ๋๋ค. ์ด ๊ฐ์
๊ณ์ข๋ฒํธ๊ฐ ์๋๋ฉฐ, ํ ์ค์ฆ๊ถ์ ๊ณ์ข ๋ชฉ๋ก API์์ ํ์ธํฉ๋๋ค.
jq๊ฐ ์ค์น๋ ๋ก์ปฌ ํฐ๋ฏธ๋์์ ๋ค์์ฒ๋ผ ์กฐํํ ์ ์์ต๋๋ค.
set -a
source .env
set +a
ACCESS_TOKEN="$(
curl -fsS -X POST 'https://openapi.tossinvest.com/oauth2/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=${TOSSINVEST_CLIENT_ID}" \
--data-urlencode "client_secret=${TOSSINVEST_CLIENT_SECRET}" |
jq -r '.access_token'
)"
curl -fsS 'https://openapi.tossinvest.com/api/v1/accounts' \
-H "Authorization: Bearer ${ACCESS_TOKEN}" |
jq '.result[] | {accountSeq, accountType}'
unset ACCESS_TOKEN
์ถ๋ ฅ๋ accountSeq๋ฅผ .env์ TOSSINVEST_ACCOUNT_SEQ์ ์ค์ ํฉ๋๋ค. ์ ๋ช
๋ น์ ๊ณ์ข ์๋ณ
์ ๋ณด๋ฅผ ๋ค๋ฃจ๋ฏ๋ก ์ถ๋ ฅ ๋ด์ฉ์ ๊ณต์ ํ๊ฑฐ๋ ์ ์ฅ์์ ๋จ๊ธฐ์ง ๋ง์ธ์.
MCP์ list_accounts ๋๊ตฌ๋ ๋ณด์์ ์ํด ์๋ณธ ๊ณ์ข๋ฒํธ์ accountSeq๋ฅผ ๋ฐํํ์ง ์์ต๋๋ค.
๊ณ์ข ์ ํ๊ณผ ํ์ฌ ์๋ฒ์ ์ค์ ๋ ๊ณ์ข์ธ์ง ์ฌ๋ถ๋ง ์ ๊ณตํฉ๋๋ค.
ํ๊ฒฝ๋ณ์ ์ค์
| ๋ณ์ | ํ์ ์กฐ๊ฑด | ๊ธฐ๋ณธ๊ฐ | ์ค๋ช
|
| --- | --- | --- | --- |
| TOSSINVEST_CLIENT_ID | ํญ์ | ์์ | ํ ์ค์ฆ๊ถ Open API ํด๋ผ์ด์ธํธ ID |
| TOSSINVEST_CLIENT_SECRET | ํญ์ | ์์ | ํ ์ค์ฆ๊ถ Open API ํด๋ผ์ด์ธํธ secret |
| TOSSINVEST_ACCOUNT_SEQ | ๊ณ์ขยท์ฃผ๋ฌธ ๋๊ตฌ | ์์ | ์๋ฒ๊ฐ ์ฌ์ฉํ ๊ณ ์ ๊ณ์ข sequence |
| TOSSINVEST_MAX_ORDER_KRW | ์ฃผ๋ฌธ ํ์ฑํ | ์์ | ๋จ์ผ ์ํ ์ฃผ๋ฌธ ์ต๋ ๊ธ์ก |
| TOSSINVEST_MAX_ORDER_USD | ์ฃผ๋ฌธ ํ์ฑํ | ์์ | ๋จ์ผ ๋ฌ๋ฌ ์ฃผ๋ฌธ ์ต๋ ๊ธ์ก |
| TOSSINVEST_APPROVAL_TOKEN_SHA256 | ์ฃผ๋ฌธ ํ์ฑํ | ์์ | ์ฌ๋ ์ ์ฉ ์น์ธ token์ SHA-256 hex digest |
| TOSSINVEST_APPROVAL_BASE_URL | ์ ํ | http://127.0.0.1:8000 | ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ํ์ํ ์น์ธ ํ์ด์ง ์ฃผ์ |
| TOSSINVEST_BASE_URL | ์ ํ | ๊ณต์ API ์ฃผ์ | ํ
์คํธ ๋๋ ํธํ ํ๋ก์์ฉ API ์ฃผ์ |
| TOSSINVEST_REQUEST_TIMEOUT | ์ ํ | 15 | ํ ์ค API ์์ฒญ timeout(์ด) |
| MCP_AUTH_TOKEN | ํญ์ | ์์ | MCP ์ฐ๊ฒฐ์ ์ฌ์ฉํ๋ Bearer token, ์ต์ 16์ |
| MCP_ALLOWED_ORIGINS | ์ ํ | ๋น ๊ฐ | ํ์ฉํ ๋ธ๋ผ์ฐ์ Origin์ ์ผํ ๊ตฌ๋ถ ๋ชฉ๋ก |
| MCP_HOST | ์ง์ ์คํ | 0.0.0.0 | Compose ์ธ ์ง์ ์คํ ์ listen ์ฃผ์ |
| MCP_PORT | ์ง์ ์คํ | 8000 | Compose ์ธ ์ง์ ์คํ ์ listen ํฌํธ |
| MCP_PUBLISHED_PORT | Docker Compose | 8000 | ํธ์คํธ์ ๊ณต๊ฐํ ํฌํธ |
| LOG_LEVEL | ์ ํ | INFO | ์๋ฒ ๋ก๊ทธ ๋ ๋ฒจ |
์ฃผ์์ฌํญ:
.env๋.gitignore์ ํฌํจ๋์ด ์์ง๋ง ๋ณ๋๋ก ๋ฐฑ์ ยท๊ณต์ ํ์ง ์๋ ๊ฒ์ด ์์ ํฉ๋๋ค.MCP_AUTH_TOKEN์ ํ ์ค์ฆ๊ถclient_secret๊ณผ ๋ค๋ฅธ ๊ฐ์ด์ด์ผ ํฉ๋๋ค.- ์ฌ๋ ์ ์ฉ ์น์ธ token์ MCP token๊ณผ ํ ์ค์ฆ๊ถ secret ๋ชจ๋์ ๋ฌ๋ผ์ผ ํฉ๋๋ค.
- ์ฃผ๋ฌธ ๊ธฐ๋ฅ์ ์ผ๋ฉด ๊ณ์ข sequence, ๋ ํตํ์ ์ฃผ๋ฌธ ํ๋, ์น์ธ token์ด ๋ชจ๋ ํ์ํฉ๋๋ค.
- ์๋ฌธ ์น์ธ token์ ์๋ฒ
.env, Hermes ํ๊ฒฝ๋ณ์, Hermes ์ค์ ์ ๋ฃ์ง ๋ง์ธ์. ์๋ฒ์๋TOSSINVEST_APPROVAL_TOKEN_SHA256๋ง ์ ์ฅํฉ๋๋ค. - Hermes์ ์๋ฒ
.env๋ฅผ ์ฝ์ ์ ์๋ filesystem/shell ๊ถํ์ ๋ถ์ฌํ๋ฉด ์น์ธ ๊ฒฝ๊ณ๊ฐ ๋ฌด๋์ง๋๋ค. - ๋น ์ฃผ๋ฌธ ํ๋๋ ๋ฌด์ ํ์ ์๋ฏธํ์ง ์์ต๋๋ค. ์ฃผ๋ฌธ ํ์ฑํ ์ ์๋ฒ ์์ ์คํจ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
Docker๋ก ์คํ
๋น๋์ ์์
docker compose up -d --build
๋ก๊ทธ ํ์ธ
docker compose logs -f tossinvest-mcp
์ฌ์์
docker compose restart tossinvest-mcp
์ข ๋ฃ
docker compose down
๋ค๋ฅธ ํธ์คํธ ํฌํธ ์ฌ์ฉ
.env:
MCP_PUBLISHED_PORT=18000
์ด ๊ฒฝ์ฐ MCP ์ฃผ์๋ http://127.0.0.1:18000/mcp๊ฐ ๋ฉ๋๋ค. Hermes ์ค์ ์ URL๋ ๊ฐ์ ํฌํธ๋ก
์์ ํด์ผ ํฉ๋๋ค. ๊ฑฐ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ค๋ฉด ์น์ธ URL๋ ๊ฐ์ ํฌํธ๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ์ค์ ํฉ๋๋ค.
TOSSINVEST_APPROVAL_BASE_URL=http://127.0.0.1:18000
Compose๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํฌํธ๋ฅผ 127.0.0.1์๋ง ๋ฐ์ธ๋ฉํฉ๋๋ค. ๊ฐ์ ์ปดํจํฐ์์ ์คํ๋๋
Hermes๋ง ์ ๊ทผํ ์ ์๋ ๊ตฌ์ฑ์ด๋ฉฐ, ํน๋ณํ ์ด์ ์์ด 0.0.0.0์ผ๋ก ๊ณต๊ฐํ์ง ๋ง์ธ์.
๊ณต๊ฐ ์ด๋ฏธ์ง ์ฌ์ฉ
๋ฆด๋ฆฌ์ค ํ๊ทธ๊ฐ ๋ฐํ๋ ์ดํ์๋ GHCR ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
docker pull ghcr.io/cha2hyun/tossinvest-mcp:latest
docker compose up -d
ํน์ ๋ฒ์ ์ ์ด์ ํ๊ฒฝ์ ๊ณ ์ ํ๋ ค๋ฉด latest ๋์ SemVer ํ๊ทธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
Hermes Agent ์ฐ๊ฒฐ
1. Hermes์ฉ ํ ํฐ ์ ์ฅ
~/.hermes/.env:
TOSSINVEST_MCP_AUTH_TOKEN=.env์_MCP_AUTH_TOKEN๊ณผ_๋์ผํ_๊ฐ
Bearer ์ ๋์ฌ๋ ์ด ํ์ผ์ ๋ฃ์ง ์์ต๋๋ค.
2. MCP ์๋ฒ ์ค์ ์ถ๊ฐ
~/.hermes/config.yaml์ ์ต์์ mcp_servers ์๋์ ์ถ๊ฐํฉ๋๋ค.
mcp_servers:
tossinvest:
url: "http://127.0.0.1:8000/mcp"
headers:
Authorization: "Bearer ${TOSSINVEST_MCP_AUTH_TOKEN}"
enabled: true
timeout: 120
connect_timeout: 30
supports_parallel_tool_calls: false
tools:
include:
- get_stock_info
- get_stock_warnings
- get_prices
- get_orderbook
- get_recent_trades
- get_price_limits
- get_candles
- get_exchange_rate
- get_market_calendar
- list_accounts
- get_holdings
- list_orders
- get_order
- get_buying_power
- get_sellable_quantity
- get_commissions
resources: false
prompts: false
๋์ผํ ์์ ๋ examples/hermes-config.yaml์๋ ์์ต๋๋ค.
3. ์ฐ๊ฒฐ ํ์ธ
hermes mcp test tossinvest
์กฐํ ์ ์ฉ ๊ธฐ๋ณธ ๋ชจ๋์์๋ 16๊ฐ ๋๊ตฌ๊ฐ ๋ณด์ฌ์ผ ํ๋ฉฐ, place_order, modify_order,
cancel_order ๊ฐ์ ์ฃผ๋ฌธ ์คํ ๋๊ตฌ๋ ๋ณด์ด๋ฉด ์ ๋ฉ๋๋ค.
Hermes Skill ์ค์น
MCP ๋๊ตฌ๋ โ๋ฌด์์ ์คํํ ์ ์๋์งโ๋ฅผ ์ ๊ณตํ๊ณ , Skill์ Hermes์ โ์ด๋ค ์์์ ์์ ๊ท์น์ผ๋ก ์ฌ์ฉํด์ผ ํ๋์งโ๋ฅผ ์๋ ค์ค๋๋ค.
mkdir -p ~/.hermes/skills
cp -R skills/tossinvest ~/.hermes/skills/
cp -R skills/tossinvest-trading ~/.hermes/skills/
hermes skills list | grep tossinvest
์ค์น ํ ์ Hermes ์ธ์
์ ์์ํฉ๋๋ค. tossinvest๋ ์กฐํ ์ ์ฐจ๋ง ์๋ดํฉ๋๋ค.
tossinvest-trading์ ๊ฑฐ๋ ๋๊ตฌ๊ฐ ์ค์ ๋ก ๋ฑ๋ก๋ ๊ฒฝ์ฐ์๋ง ๋ํ๋๋ฉฐ ๋ค์ ํ๋ฆ์ ์๋ดํฉ๋๋ค.
- ์ข ๋ชฉ๊ณผ ์์ฅ ํ์ธ
- ์ฅ ์ด์ ์๊ฐ ํ์ธ
- ์ข ๋ชฉ ๊ฒฝ๊ณ ์กฐํ
- ๋งค์ ๊ฐ๋ฅ ๊ธ์ก ๋๋ ํ๋งค ๊ฐ๋ฅ ์๋ ํ์ธ
- ์ฃผ๋ฌธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ์น์ธ URL ์ ์
- ์ฌ์ฉ์๊ฐ ๋ณ๋ ์น์ธ ํ์ด์ง์์ ์ฃผ๋ฌธ ๋ด์ฉ ํ์ธ
- ์ฌ๋ ์ ์ฉ token์ผ๋ก ์น์ธํ ๋ค ํ ๋ฒ๋ง ์ฃผ๋ฌธ ์คํ
- ์ฃผ๋ฌธ ์์ธ ์ฌ์กฐํ
- ์ํ๊ฐ ๋ถ๋ช ํํ๋ฉด ์ฌ์ฃผ๋ฌธํ์ง ์๊ณ ์ฃผ๋ฌธ ๋ด์ญ ํ์ธ
Skill์ ํ๋ ์ง์นจ์ด๋ฉฐ ๋ณด์ ๊ฒฝ๊ณ๊ฐ ์๋๋๋ค. ๊ฑฐ๋ ์ ํ๊ณผ ํ์ธ ์ ์ฐจ๋ MCP ์๋ฒ๋ ๋ ๋ฆฝ์ ์ผ๋ก ๊ฐ์ ํฉ๋๋ค.
์ ๊ณต ๋๊ตฌ
Hermes์์๋ ์๋ฒ ์ด๋ฆ์ด ๋๊ตฌ๋ช
์์ ๋ถ์ด mcp_tossinvest_get_prices์ฒ๋ผ ๋ณด์ผ ์ ์์ต๋๋ค.
์๋ ํ๋ MCP ์๋ฒ ๋ด๋ถ ๋๊ตฌ๋ช
์ ๊ธฐ์ค์ผ๋ก ํฉ๋๋ค.
์ข ๋ชฉยท์์ธ
| ๋๊ตฌ | ์ค๋ช
| ์ฃผ์ ์
๋ ฅ |
| --- | --- | --- |
| get_stock_info | ์ข
๋ชฉ๋ช
, ์์ฅ, ํตํ, ์์ฅ ์ํ ๋ฑ ์ข
๋ชฉ ๊ธฐ๋ณธ ์ ๋ณด | symbols |
| get_stock_warnings | ํฌ์๊ฒฝ๊ณ , ์ํ, ๊ณผ์ด, VI ๋ฑ ๋งค์ ์ ์์ฌํญ | symbol |
| get_prices | ์ต๋ 200๊ฐ ์ข
๋ชฉ์ ํ์ฌ๊ฐ | symbols |
| get_orderbook | ๋งค์ยท๋งค๋ ํธ๊ฐ | symbol |
| get_recent_trades | ์ต๊ทผ ์ฒด๊ฒฐ ๋ด์ญ, ์ต๋ 50๊ฑด | symbol, count |
| get_price_limits | ๊ตญ๋ด ์ข
๋ชฉ ์ํ๊ฐยทํํ๊ฐ | symbol |
| get_candles | 1๋ถ๋ด ๋๋ ์ผ๋ด OHLCV | symbol, interval, count |
์ฌ๋ฌ ์ข
๋ชฉ์ ๋ฐ๋ symbols ์
๋ ฅ์ ์ผํ๋ก ๊ตฌ๋ถํฉ๋๋ค.
005930,000660,AAPL
์์ฅ ์ ๋ณด
| ๋๊ตฌ | ์ค๋ช
| ์ฃผ์ ์
๋ ฅ |
| --- | --- | --- |
| get_exchange_rate | KRW/USD ํ์จ | base_currency, quote_currency |
| get_market_calendar | ํ๊ตญ ๋๋ ๋ฏธ๊ตญ ์ฅ ์ด์ ์๊ฐ | market, date |
๊ณ์ขยท์์ฐ
| ๋๊ตฌ | ์ค๋ช
| ์ฃผ์ ์
๋ ฅ |
| --- | --- | --- |
| list_accounts | ์๋ณ ์ ๋ณด๋ฅผ ์ ๊ฑฐํ ๊ณ์ข ์ ํ๊ณผ ์ ํ ์ํ | ์์ |
| get_holdings | ๋ณด์ ์ฃผ์๊ณผ ํ๊ฐยท์์ต ์ ๋ณด | ์ ํ์ symbol |
| get_buying_power | ํ๊ธ ๊ธฐ๋ฐ ๋งค์ ๊ฐ๋ฅ ๊ธ์ก | currency |
| get_sellable_quantity | ํ์ฌ ํ๋งค ๊ฐ๋ฅํ ์๋ | symbol |
| get_commissions | ๊ตญ๋ดยท๋ฏธ๊ตญ ์์ฅ๋ณ ์์๋ฃ | ์์ |
์ฃผ๋ฌธ ์กฐํ
| ๋๊ตฌ | ์ค๋ช
| ์ฃผ์ ์
๋ ฅ |
| --- | --- | --- |
| list_orders | ์งํ ์ค ๋๋ ์ข
๋ฃ ์ฃผ๋ฌธ ๋ชฉ๋ก | status, ๋ ์ง, cursor |
| get_order | ์ฃผ๋ฌธ ํ ๊ฑด์ ์ํ์ ์ฒด๊ฒฐ ๊ฒฐ๊ณผ | order_id |
์ฃผ๋ฌธ ์คํ
๋ค์ ๋๊ตฌ๋ ์๋ฒ๋ฅผ --dangerously-enable-trading ์ธ์๋ก ์์ํ์ ๋๋ง ๋ฑ๋ก๋ฉ๋๋ค.
| ๋จ๊ณ | ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋๊ตฌ | ์คํ ๋๊ตฌ |
| --- | --- | --- |
| ์ฃผ๋ฌธ ์์ฑ | preview_order | place_order |
| ์ฃผ๋ฌธ ์ ์ | preview_order_modification | modify_order |
| ์ฃผ๋ฌธ ์ทจ์ | preview_order_cancellation | cancel_order |
์ฃผ๋ฌธ ๊ธฐ๋ฅ ํ์ฑํ
๋จผ์ ์ถฉ๋ถํ ๋ฎ์ ์ฃผ๋ฌธ ํ๋๋ก ์์ํ์ธ์.
์ฌ๋ ์ ์ฉ ์น์ธ token์ 32-byte ๋์๋ก ์์ฑํ๊ณ ๋น๋ฐ๋ฒํธ ๊ด๋ฆฌ์ ๋ฑ ์๋ฒยทHermes ๋ฐ์ ์์ ํ
์ฅ์์ ์ ์ฅํฉ๋๋ค. ์๋ฌธ token์ .env์ ๋ฃ์ง ์์ต๋๋ค.
openssl rand -hex 32
์ ์ฅํ token์ ํ๋ฉด์ ๋ค์ ๋ ธ์ถํ์ง ์๊ณ SHA-256 digest๋ฅผ ๊ณ์ฐํฉ๋๋ค.
read -rsp "Approval token: " APPROVAL_TOKEN
echo
printf '%s' "$APPROVAL_TOKEN" | openssl dgst -sha256 -r | awk '{print $1}'
unset APPROVAL_TOKEN
์ถ๋ ฅ๋ 64์๋ฆฌ digest๋ง .env์ ์ค์ ํฉ๋๋ค.
TOSSINVEST_ACCOUNT_SEQ=1
TOSSINVEST_MAX_ORDER_KRW=1000000
TOSSINVEST_MAX_ORDER_USD=500
TOSSINVEST_APPROVAL_TOKEN_SHA256=์น์ธ_token์_64์๋ฆฌ_sha256_digest
TOSSINVEST_APPROVAL_BASE_URL=http://127.0.0.1:8000
ํ๊ฒฝ๋ณ์๋ง์ผ๋ก๋ ์ฃผ๋ฌธ ๊ธฐ๋ฅ์ ํ์ฑํํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ compose.yaml์ ๊ฑฐ๋ ์ ์ฉ override
ํ์ผ์ ๋ช
์์ ์ผ๋ก ์ถ๊ฐํ์ฌ ์๋ฒ ์์ ๋ช
๋ น์ ์ํ ์ธ์๋ฅผ ์ ๋ฌํด์ผ ํฉ๋๋ค.
docker compose \
-f compose.yaml \
-f compose.trading.yaml \
up -d --build --force-recreate
์ง์ ์คํํ ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
uv run tossinvest-mcp --dangerously-enable-trading
TOSSINVEST_ENABLE_TRADING=true ๊ฐ์ ํ๊ฒฝ๋ณ์๋ ์ฃผ๋ฌธ ๊ธฐ๋ฅ์ ์ด์ง ์์ต๋๋ค. ์ ํํ
--dangerously-enable-trading ์ธ์๊ฐ ํ์ํฉ๋๋ค.
Hermes allowlist์๋ ์ฃผ๋ฌธ ๋๊ตฌ๋ฅผ ๋ช
์์ ์ผ๋ก ์ถ๊ฐํด์ผ ํฉ๋๋ค.
์ ์ฒด ์์๋ examples/hermes-trading-config.yaml์
์์ต๋๋ค.
tools:
include:
# ๊ธฐ์กด ์กฐํ ๋๊ตฌ
- preview_order
- place_order
- preview_order_modification
- modify_order
- preview_order_cancellation
- cancel_order
๊ฑฐ๋ ํ์ฑํ ๋ชจ๋์์๋ ์ด 22๊ฐ ๋๊ตฌ๊ฐ ๋ฑ๋ก๋ฉ๋๋ค.
์ฃผ๋ฌธ ์์ ์ฅ์น
1. ๊ฑฐ๋ ๋๊ตฌ ๊ธฐ๋ณธ ๋น๋ ธ์ถ
๊ธฐ๋ณธ tossinvest-mcp ๋ช
๋ น๊ณผ ๊ธฐ๋ณธ compose.yaml์ ์ฃผ๋ฌธ ๋๊ตฌ๋ฅผ MCP ๋๊ตฌ ๋ชฉ๋ก ์์ฒด์
๋ฑ๋กํ์ง ์์ต๋๋ค. ์ฃผ๋ฌธ ๋๊ตฌ๋ฅผ ์ด๋ ค๋ฉด ์๋ฒ ์์ ์ --dangerously-enable-trading์
๋ช
์ํด์ผ ํฉ๋๋ค.
2. MCP ์ฑ๋๊ณผ ๋ถ๋ฆฌ๋ ์ฌ๋ ์น์ธ
์ฃผ๋ฌธ์ ๋ฐ๋ก ์คํํ ์ ์์ต๋๋ค. ๋จผ์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋๊ตฌ๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค.
๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๋ค์ ์ ๋ณด๋ฅผ ๋ฐํํฉ๋๋ค.
preview_id- ์ฌ๋์ด ์ด์ด์ผ ํ๋
approval_url - ์ข ๋ชฉ, ๋ฐฉํฅ, ๊ฐ๊ฒฉ, ์๋ ๋๋ ๊ธ์ก
- ํ์ฌ๊ฐ์ ์์ ์ฃผ๋ฌธ ๊ธ์ก
- ์ํ ํ์ฐ ์์ ๊ธ์ก
- ์ข ๋ชฉ ๊ฒฝ๊ณ ์ ์ฅ ์ด์ ์ ๋ณด
- ๋งค์ ๊ฐ๋ฅ ๊ธ์ก ๋๋ ํ๋งค ๊ฐ๋ฅ ์๋
๋ฏธ๋ฆฌ๋ณด๊ธฐ ์๋ต์๋ ์ฃผ๋ฌธ์ ์น์ธํ ์ ์๋ secret์ด๋ ํ์ธ ๋ฌธ๊ตฌ๊ฐ ๋ค์ด ์์ง ์์ต๋๋ค.
์์ด์ ํธ๊ฐ place_order, modify_order, cancel_order๋ฅผ ๋ฐ๋ก ํธ์ถํ๋ฉด ์๋ฒ๋
approval-required๋ก ๊ฑฐ๋ถํ๋ฉฐ ํ ์ค์ฆ๊ถ ์ฃผ๋ฌธ API๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค.
์ฌ๋์ approval_url์ ๋ธ๋ผ์ฐ์ ๋ก ์ด์ด ์ ํํ ์ฃผ๋ฌธ ๋ด์ฉ์ ํ์ธํ๊ณ ,
๋ณ๋๋ก ๋ณด๊ดํ ์๋ฌธ ์น์ธ token์ ์
๋ ฅํด์ผ ํฉ๋๋ค. ์๋ฒ๋ ์
๋ ฅ๊ฐ์ SHA-256 digest๋ง ๋น๊ตํ๋ฉฐ
์๋ฌธ token์ ์ ์ฅํ์ง ์์ต๋๋ค. ์ด token์ Hermes์ ์ ๋ฌํ์ง ์๋ ๋ณ๋ credential์
๋๋ค.
์น์ธ ์ํ๋ ํ ๋ฒ ์ฌ์ฉํ๋ฉด ํ๊ธฐ๋๋ฉฐ, 2๋ถ์ด ์ง๋๊ฑฐ๋ ์๋ฒ๊ฐ ์ฌ์์๋๋ฉด ์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ
ํ์ํฉ๋๋ค. Origin์ด ์๊ฑฐ๋ ์ผ์นํ์ง ์๋ ์น์ธ ์์ฒญ์ ๊ฑฐ๋ถํ๋ฉฐ ๋ฐ๋ณต ์์ฒญ๊ณผ preview๋ณ
์คํจ ํ์๋ ์ ํํฉ๋๋ค.
Hermes MCP token โโ ๋ฏธ๋ฆฌ๋ณด๊ธฐ/์คํ ์์ฒญ
์ฌ๋ ์น์ธ token โโ ๋ณ๋ ์น ์น์ธ
๋ ์กฐ๊ฑด ๋ชจ๋ ์ถฉ์กฑ โโ ํ ์ค์ฆ๊ถ ์ฃผ๋ฌธ POST
3. ์ฃผ๋ฌธ ๊ธ์ก ์ ํ
TOSSINVEST_MAX_ORDER_KRWTOSSINVEST_MAX_ORDER_USD- ์ํ ํ์ฐ 1์ต์ ์ด์ ์ฃผ๋ฌธ์ ๊ฐ์ ์ฐจ๋จ
๋ฏธ๊ตญ ์ฃผ๋ฌธ์ ๊ณต์ ํ์จ๋ก ์ํ ๊ฐ์น๋ฅผ ๊ณ์ฐํ์ฌ 1์ต์ ์ ํ๋ ํจ๊ป ๊ฒ์ฌํฉ๋๋ค.
4. ์์ฅ๊ฐ ์ฃผ๋ฌธ์ ๋ณด์์ ๊ฒ์ฌ
๊ตญ๋ด ์์ฅ๊ฐ ์ฃผ๋ฌธ์ ํ์ฌ๊ฐ๊ฐ ์๋ ๊ณต์ ์ํ๊ฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ์์ ๊ธ์ก๊ณผ ๋งค์ ๊ฐ๋ฅ ๊ธ์ก์ ๊ฒ์ฌํฉ๋๋ค. ์ค์ ์ฃผ๋ฌธ ์์ ์ ๊ฐ๊ฒฉ ๋ณ๋์ผ๋ก ์ค์ ํ๋๋ฅผ ๋์ด๊ฐ ๊ฐ๋ฅ์ฑ์ ์ค์ด๊ธฐ ์ํ ์ ์ฑ ์ ๋๋ค.
๊ณต์ ์ํ๊ฐ๋ก ์ ๋ ํ๋๋ฅผ ๊ณ์ฐํ ์ ์๋ ๋ฏธ๊ตญ ์๋ ๊ธฐ๋ฐ ์์ฅ๊ฐ ์ฃผ๋ฌธ์ ๊ฑฐ๋ถํฉ๋๋ค. ๋ฏธ๊ตญ
์์ฅ๊ฐ ์ฃผ๋ฌธ์ ์ง์๋๋ ๊ฒฝ์ฐ ๊ณ ์ order_amount๋ฅผ ์ฌ์ฉํด์ผ ํ๋ฉฐ, ๋ฏธ๊ตญ ์์ฅ๊ฐ ์ ์ ๋
๊ฑฐ๋ถํฉ๋๋ค.
5. ์คํ ์ง์ ์ฌ๊ฒ์ฆ
์ฌ๋ ์น์ธ ํ ์คํ ๋๊ตฌ๊ฐ ํธ์ถ๋๋ฉด ์๋ฒ๋ ๊ฐ๊ฒฉ, ํ์จ, ๋งค์ ๊ฐ๋ฅ ๊ธ์ก ๋๋ ํ๋งค ๊ฐ๋ฅ ์๋,
์ฃผ๋ฌธ ์ํ์ ์ค์ ํ๋๋ฅผ ๋ค์ ์กฐํํฉ๋๋ค. ์ํ๊ฐ ๋ฌ๋ผ์ก๊ฑฐ๋ ํ๋๋ฅผ ๋์ผ๋ฉด ํด๋น preview๋ฅผ
ํ๊ธฐํ๊ณ preview-state-changed๋ฅผ ๋ฐํํฉ๋๋ค. ๋ณ๊ฒฝ๋ ์ํ๋ก ์ preview์ ์ ์น์ธ์ด
ํ์ํฉ๋๋ค.
6. ์ฃผ๋ฌธ ์๋ ์ฌ์๋ ๊ธ์ง
์ฃผ๋ฌธ ์์ฑยท์ ์ ยท์ทจ์๋ ํ ํฐ ๋ง๋ฃ ์๋ต, rate limit, timeout, ๋คํธ์ํฌ ์ค๋ฅ๊ฐ ๋ฐ์ํด๋ ์๋์ผ๋ก ์ฌ์ ์กํ์ง ์์ต๋๋ค.
์ ์ก ์ดํ ์ฐ๊ฒฐ์ด ๋๊ฒจ ์ฃผ๋ฌธ ์ฑ๊ณต ์ฌ๋ถ๋ฅผ ์ ์ ์์ผ๋ฉด ๋ค์ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค.
order-state-unknown
์ด ๊ฒฝ์ฐ ๊ฐ์ ์ฃผ๋ฌธ์ ๋ค์ ์คํํ์ง ๋ง๊ณ list_orders์ get_order๋ก ์ํ๋ถํฐ ํ์ธํด์ผ
ํฉ๋๋ค.
7. ๋ฉฑ๋ฑ์ฑ
์ฃผ๋ฌธ ์์ฑ ์ ์๋ฒ๊ฐ clientOrderId๋ฅผ ์๋ ์์ฑํฉ๋๋ค. ํ ์ค์ฆ๊ถ์ ์ด ๊ฐ์ ๊ธฐ์ค์ผ๋ก 10๋ถ๊ฐ
๋ฉฑ๋ฑ์ฑ์ ์ ๊ณตํฉ๋๋ค. ๋ค๋ง ์ด ๊ธฐ๋ฅ์ ๋ฏฟ๊ณ ์ ํ๋ฆฌ์ผ์ด์
์ด ์ฃผ๋ฌธ์ ์๋ ์ฌ์๋ํ์ง๋ ์์ต๋๋ค.
์๋ต๊ณผ ์ค๋ฅ ํ์
์ ์์ ์ธ Toss API ๊ฒฐ๊ณผ๋ ๋ค์ ํํ๋ก ์ ๊ทํ๋ฉ๋๋ค.
{
"data": {},
"meta": {
"request_id": "ํ ์ค์ฆ๊ถ ์์ฒญ ์๋ณ์",
"retrieved_at": "2026-06-18T04:00:00+00:00",
"rate_limit": {
"limit": "10",
"remaining": "9",
"reset": "0.1"
}
}
}
request_id๋ ํ ์ค์ฆ๊ถ ๋ฌธ์๋ ์ฅ์ ์ถ์ ์ ์ ์ฉํฉ๋๋ค.
์์ ๊ฐ๋ฅํ ์ค๋ฅ๋ MCP ToolError ์์ ๋ค์ ์ ๋ณด๊ฐ ํฌํจ๋ฉ๋๋ค.
{
"error": {
"status_code": 429,
"code": "rate-limit-exceeded",
"message": "์์ฒญ ํ๋๋ฅผ ์ด๊ณผํ์ต๋๋ค.",
"request_id": "request-id",
"data": null
}
}
ํ ์ค์ฆ๊ถ Authorization header, OAuth access token, client secret, account sequence์ ์น์ธ token digest๋ MCP ๋๊ตฌ schema, ๊ฒฐ๊ณผ, resource, prompt์ ๋ ธ์ถํ์ง ์์ต๋๋ค.
์ด์๊ณผ ๋ณด์
๊ธฐ๋ณธ Compose ๋ณด์ ์ค์ :
- ํธ์คํธ์
127.0.0.1์๋ง ํฌํธ ๊ณต๊ฐ - ์ปจํ ์ด๋ non-root ์ฌ์ฉ์ ์คํ
- read-only root filesystem
- Linux capability ์ ์ฒด ์ ๊ฑฐ
no-new-privileges/tmp๋ง ์ ํ๋ ์์ filesystem์ผ๋ก ์ ๊ณต- healthcheck์ ์๋ ์ฌ์์
- Uvicorn ๋จ์ผ worker
์ธ๋ถ ์๋ฒ์ ๋ฐฐํฌํ ๋
์ด ์ ์ฅ์์ Compose ํฌํธ๋ฅผ ๊ทธ๋๋ก ์ธํฐ๋ท์ ๊ณต๊ฐํ๋ฉด ์ ๋ฉ๋๋ค.
- HTTPS reverse proxy ์ฌ์ฉ
- MCP streaming ์๋ต์ bufferingํ์ง ์๋๋ก ์ค์
- ๋ฐฉํ๋ฒฝ ๋๋ ์ฌ์ค๋ง์ผ๋ก ์ ๊ทผ ์ ํ
- ์ถฉ๋ถํ ๊ธด
MCP_AUTH_TOKEN์ฌ์ฉ - secret manager ์ฌ์ฉ
/healthz,/readyz์ ์ธ๋ถ ์ ๊ทผ ์ ํ- Hermes allowlist ์ต์ํ
- ์ฃผ๋ฌธ ํ๋๋ฅผ ๋ฎ๊ฒ ์์
์์ธํ ๋ด์ฉ์ SECURITY.md๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋ก์ปฌ ๊ฐ๋ฐ
Python 3.12์ uv๊ฐ ํ์ํฉ๋๋ค.
uv sync --all-extras
์๋ฒ ์ง์ ์คํ:
cp .env.example .env
uv run tossinvest-mcp
๊ฒ์ฆ:
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pip-audit --strict
uv run python scripts/update_openapi.py --check
docker build .
๊ณต์ OpenAPI ๊ฒ์ฌ๊ธฐ๋ ๋ค์์ ํ์ธํฉ๋๋ค.
- API ๋ฒ์
- ์ ์ฒด OpenAPI ๋ฌธ์์ SHA-256 fingerprint
- ๋ชจ๋ HTTP operation
- ๊ณต์
operationId์ MCP ๊ตฌํ์ ๋งคํ
๊ณต์ ์คํค๋ง ๋ณ๊ฒฝ์ ๊ฒํ ํ ๋ค manifest๋ฅผ ๊ฐฑ์ ํ๋ ค๋ฉด:
uv run python scripts/update_openapi.py --update
๋ฌธ์ ํด๊ฒฐ
401 Unauthorized
MCP ์์ฒญ์ Authorization header๋ฅผ ํ์ธํ์ธ์.
Authorization: Bearer <MCP_AUTH_TOKEN>
Hermes์ TOSSINVEST_MCP_AUTH_TOKEN์๋ Bearer ์์ด ํ ํฐ ๊ฐ๋ง ์ ์ฅํด์ผ ํฉ๋๋ค.
/readyz๊ฐ 503์ ๋ฐํํจ
TOSSINVEST_CLIENT_IDํ์ธTOSSINVEST_CLIENT_SECRETํ์ธ- ์ปจํ ์ด๋์ ์ธ๋ถ ๋คํธ์ํฌ ์ฐ๊ฒฐ ํ์ธ
- ํ ์ค์ฆ๊ถ Open API ์ ๊ฒ ์ฌ๋ถ ํ์ธ
docker compose logs tossinvest-mcp
account-not-configured
.env์ ์ฌ๋ฐ๋ฅธ TOSSINVEST_ACCOUNT_SEQ๊ฐ ํ์ํฉ๋๋ค. ๊ฐ์ ์์ ํ ๋ค ์ปจํ
์ด๋๋ฅผ ๋ค์
์์ฑํ์ธ์.
docker compose up -d --force-recreate
๊ฑฐ๋ ๋๊ตฌ๊ฐ ๋ณด์ด์ง ์์
๋ค์์ ๋ชจ๋ ํ์ธํ์ธ์.
- Docker ์คํ ์
compose.trading.yaml์ ํจ๊ป ์ง์ ํ๋์ง ํ์ธ - ์ง์ ์คํ ์
--dangerously-enable-trading์ ์ฌ์ฉํ๋์ง ํ์ธ - ์ํยท๋ฌ๋ฌ ์ฃผ๋ฌธ ํ๋์ ์ฌ๋ ์น์ธ token์ด ๋ชจ๋ ์ค์ ๋๋์ง ํ์ธ
- ์ปจํ ์ด๋๊ฐ ์ค์ ๋ณ๊ฒฝ ํ ๋ค์ ์์ฑ๋๋์ง ํ์ธ
- Hermes
tools.include์ ๊ฑฐ๋ ๋๊ตฌ๊ฐ ์ถ๊ฐ๋๋์ง ํ์ธ
approval-required
๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ฒฐ๊ณผ์ approval_url์ ์ฌ๋์ด ์ง์ ๋ธ๋ผ์ฐ์ ๋ก ์ด๊ณ ์ฃผ๋ฌธ ๋ด์ฉ์ ํ์ธํด์ผ ํฉ๋๋ค.
์น์ธ ํ์ด์ง์์ ์๋ฒ ๋ฐ์ ๋ณ๋๋ก ๋ณด๊ดํ ์๋ฌธ ์น์ธ token์ ์
๋ ฅํ ๋ค ์คํ ๋๊ตฌ๋ฅผ ๋ค์
ํธ์ถํ์ธ์. .env์๋ ์๋ฌธ์ด ์๋๋ผ TOSSINVEST_APPROVAL_TOKEN_SHA256๋ง ์์ด์ผ ํฉ๋๋ค.
์น์ธ token์ Hermes ์ฑํ , Hermes ํ๊ฒฝ๋ณ์, Skill, MCP ์ ๋ ฅ์ ๋ณต์ฌํ๋ฉด ์ ๋ฉ๋๋ค.
preview-state-changed
์น์ธ ํ ์คํ ์ง์ ์ฌ๊ฒ์ฆ์์ ๊ฐ๊ฒฉ, ํ์จ, ์๊ณ , ํ๋งค ๊ฐ๋ฅ ์๋ ๋๋ ์ฃผ๋ฌธ ์ํ๊ฐ ๋ฌ๋ผ์ก์ต๋๋ค. ๊ธฐ์กด preview๋ ํ๊ธฐ๋ฉ๋๋ค. ๋ณ๊ฒฝ๋ ๋ด์ฉ์ ํ์ธํ๊ณ ์ preview๋ถํฐ ๋ค์ ์งํํ์ธ์.
unbounded-market-order
์ค์ ํ๋๋ฅผ ๋ณด์์ ์ผ๋ก ๋ณด์ฅํ ์ ์๋ ์์ฅ๊ฐ ์์ฒญ์
๋๋ค. ๋ฏธ๊ตญ ์์ฅ๊ฐ ์ ๊ท ์ฃผ๋ฌธ์ ๊ณ ์
order_amount๋ฅผ ์ฌ์ฉํ๊ณ , ์์ฅ๊ฐ ์ ์ ์ ์ง์ ๊ฐ ์ ์ ์ผ๋ก ๋ฐ๊พธ์ด ์ preview๋ฅผ ๋ง๋์ธ์.
origin-not-allowed
๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ MCP ํด๋ผ์ด์ธํธ๊ฐ Origin header๋ฅผ ๋ณด๋ด๋ ๊ฒฝ์ฐ ํด๋น ์ฃผ์๋ฅผ ์ค์ ํฉ๋๋ค.
MCP_ALLOWED_ORIGINS=https://agent.example.com,https://another.example.com
Origin์ ๋ณด๋ด์ง ์๋ ์ผ๋ฐ ์๋ฒ ํด๋ผ์ด์ธํธ์ Hermes ๋ก์ปฌ ์ฐ๊ฒฐ์ ์ด ๋ชฉ๋ก์ด ๋น์ด ์์ด๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
order-state-unknown
์ฃผ๋ฌธ ์์ฒญ์ด ์ ์ก๋ ๋ค ์๋ต์ ๋ฐ์ง ๋ชปํ ์ํ์ ๋๋ค. ์ ๋ ๊ฐ์ ์คํ ๋๊ตฌ๋ฅผ ๋ฐ๋ณต ํธ์ถํ์ง ๋ง์ธ์.
list_orders(status="OPEN")์กฐํ- ์ข
๋ฃ ์ฃผ๋ฌธ๋ ํ์ํ๋ฉด
list_orders(status="CLOSED")์กฐํ - ๋ฐ๊ฒฌ๋ ์ฃผ๋ฌธ ID๋ฅผ
get_order๋ก ํ์ธ - ์ฃผ๋ฌธ ์กด์ฌ ์ฌ๋ถ๊ฐ ํ์ ๋๊ธฐ ์ ๊น์ง ์ ์ฃผ๋ฌธ ๊ธ์ง
rate-limit-exceeded
์กฐํ ์์ฒญ์ ์๋ฒ๊ฐ Retry-After๋ฅผ ๋ฐ๋ผ ์ ํ์ ์ผ๋ก ์ฌ์๋ํฉ๋๋ค. ๊ณ์ ๋ฐ์ํ๋ฉด ํธ์ถ ๋น๋๋ฅผ
์ค์ด์ธ์. ์ฃผ๋ฌธ ์์ฒญ์ rate limit ์ค๋ฅ๊ฐ ๋ฐ์ํด๋ ์๋ ์ฌ์๋ํ์ง ์์ต๋๋ค.
ํ์ฌ ์ ํ์ฌํญ
- ํ ์ค์ฆ๊ถ Open API๊ฐ ์ ๊ณตํ๋ REST API๋ง ์ฌ์ฉํฉ๋๋ค.
- WebSocket ๊ธฐ๋ฐ ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ์ ์ ๊ณตํ์ง ์์ต๋๋ค.
- ์์ธ ๊ฐฑ์ ์ด ํ์ํ ์์ด์ ํธ๋ ์กฐํ API๋ฅผ pollingํด์ผ ํฉ๋๋ค.
- OAuth token๊ณผ ์ฃผ๋ฌธ preview๋ ๋ฉ๋ชจ๋ฆฌ์๋ง ์ ์ฅ๋ฉ๋๋ค.
- ์๋ฒ ์ฌ์์ ์ ๊ธฐ์กด preview์ ์น์ธ ์ํ๋ ๋ฌดํจํ๋ฉ๋๋ค.
- ์์ ํ ์ผํ์ฉ preview๋ฅผ ์ํด ๋จ์ผ worker๋ก ์คํํฉ๋๋ค.
- ํ์ฌ ๊ตฌ์ฑ์ ๋จ์ผ ์ธ์คํด์ค๋ฅผ ์ ์ ๋ก ํ๋ฉฐ ์ํ ํ์ฅ์ฉ ๊ณต์ ์ํ ์ ์ฅ์๊ฐ ์์ต๋๋ค.
- ๊ณต์ ๋ชจ์ํฌ์ ๋๋ sandbox๊ฐ ๋ฌธ์ํ๋์ง ์์ ๊ฒฝ์ฐ ์ค๊ณ์ข ์ฃผ๋ฌธ ํ ์คํธ๊ฐ ๋ ์ ์์ต๋๋ค.
- CI๋ ์ค์ ํ ์ค์ฆ๊ถ ๊ณ์ ์ ์ฐ๊ฒฐํ๊ฑฐ๋ ์ค์ฃผ๋ฌธ์ ์คํํ์ง ์์ต๋๋ค.
๊ธฐ์ฌ
๋ฒ๊ทธ ์์ , ๋ฌธ์ ๊ฐ์ , ํ ์คํธ ์ถ๊ฐ๋ฅผ ํ์ํฉ๋๋ค. ์์ํ๊ธฐ ์ ์ CONTRIBUTING.md์ CODE_OF_CONDUCT.md๋ฅผ ํ์ธํ์ธ์.
๋ณด์ ์ทจ์ฝ์ ์ ๊ณต๊ฐ Issue ๋์ SECURITY.md์ ๋น๊ณต๊ฐ ์ ๊ณ ์ ์ฐจ๋ฅผ ์ด์ฉํ์ธ์.
๋ผ์ด์ ์ค
Copyright (c) 2026 cha2hyun