ํ ์ค์ฆ๊ถ MCP๋ ํ ์ค์ฆ๊ถ ๊ณต์ Open API๋ฅผ MCP(Model Context Protocol) ํธํ AI ์์ด์ ํธ์ ์ฐ๊ฒฐํ๋ ์คํ์์ค ์๋ฒ์ ๋๋ค. VS Code, Hermes ๊ฐ์ MCP ํด๋ผ์ด์ธํธ์์ ์ฃผ์ ์์ธ, ๋ณด์ ์ข ๋ชฉ, ์ฃผ๋ฌธ ๊ฐ๋ฅ ๊ธ์ก๊ณผ ์ฃผ๋ฌธ ๋ด์ญ์ ์กฐํํ ์ ์์ต๋๋ค.
์ด ํ๋ก์ ํธ๋ ํ ์ค์ฆ๊ถ์ ๊ณต์ ์ ํ์ด ์๋๋ฉฐ ํฌ์ ์กฐ์ธ์ ์ ๊ณตํ์ง ์์ต๋๋ค.
TossInvest MCP๋ ํ ์ค์ฆ๊ถ Open API์ ๊ธฐ๋ฅ์ AI ์์ด์ ํธ๊ฐ ํธ์ถํ ์ ์๋ MCP ๋๊ตฌ๋ก
์ ๊ณตํฉ๋๋ค. Docker ์ปจํ
์ด๋๋ API ํค ์์ด ๊ณ์ ์คํํ๊ณ , ๊ฐ ์ฌ์ฉ์๊ฐ ์์ ์
client_id์ client_secret์ MCP ์ฐ๊ฒฐ์ ๋น๊ณต๊ฐ ์์ฒญ ํค๋๋ก ์ ๋ฌํ๋ ๊ตฌ์กฐ์
๋๋ค.
- ๊ธฐ๋ณธ ์คํ์ ์กฐํ ์ ์ฉ์ด๋ฉฐ ์ฃผ๋ฌธ ๋๊ตฌ๊ฐ ๋ฑ๋ก๋์ง ์์ต๋๋ค.
- ๊ตญ๋ด์ธ ์ข ๋ชฉ ์ ๋ณด, ์์ธ, ํธ๊ฐ, ์ฒด๊ฒฐ, ๊ณ์ข์ ๋ณด์ ์ฃผ์์ ์กฐํํ ์ ์์ต๋๋ค.
- API ํค์ ๊ณ์ข ์ ๋ณด๋ MCP ๋๊ตฌ ์ธ์๋ schema์ ๋ ธ์ถํ์ง ์์ต๋๋ค.
- ๊ฑฐ๋ ๊ธฐ๋ฅ์
--dangerously-enable-trading๊ณผ ๋ณ๋ ์ฌ๋ ์น์ธ์ ๋ชจ๋ ์๊ตฌํฉ๋๋ค.
- Toss API ํค์ ๊ณ์ข sequence๋ MCP ์๋ฒ์
.env๋ ์ปจํ ์ด๋ ํ๊ฒฝ์ ์ ์ฅํ์ง ์์ต๋๋ค. - ์๊ฒฉ ์ฆ๋ช ์ MCP ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ ํค๋๋ก ์ ๋ฌํ๊ณ ์๋ฒ๋ ์์ฒญ๋ณ ์ธ์ฆ ์ปจํ ์คํธ๋ฅผ ๋ง๋ญ๋๋ค.
- ์๊ฒฉ ์ฆ๋ช ํค๋๋ MCP ๋๊ตฌ schema์ ๋๊ตฌ ์ธ์์ ๋ํ๋์ง ์์ต๋๋ค.
- ์์ฒญ๋ณ OAuth token, HTTP client, ์ฃผ๋ฌธ preview๋ ์๊ฒฉ ์ฆ๋ช fingerprint๋ณ๋ก ๊ฒฉ๋ฆฌ๋ฉ๋๋ค.
- ๊ณต๊ฐ ์ฃผ์์ ํ๋ฌธ HTTP ์์ฒญ์
426 https-required๋ก ๊ฑฐ๋ถํฉ๋๋ค. - ํ๋ฌธ HTTP๋ loopback์ผ๋ก ๊ฒ์ํ ๋ก์ปฌ ์๋ฒ์ ๋ด๋ถ healthcheck์์๋ง ํ์ฉํฉ๋๋ค.
- MCP ์๋ต์
Cache-Control: no-store์ด๋ฉฐ HTTPS ์๋ต์๋ HSTS๋ฅผ ์ถ๊ฐํฉ๋๋ค. - Uvicorn access log๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ค๋ฅ์ upstream ๋ฐ์ดํฐ์ ์ธ์ฆยท๊ณ์ข ํ๋๋ redactionํฉ๋๋ค.
- ์ฃผ๋ฌธ ๋๊ตฌ๋
--dangerously-enable-trading์์ด๋ ๋ฑ๋ก๋์ง ์์ต๋๋ค. - ๋ชจ๋ ์ฃผ๋ฌธ ์์ฑยท์ ์ ยท์ทจ์๋ 2๋ถ์ง๋ฆฌ preview, ๋ณ๋ ์น์ธ ํ์ด์ง, ์คํ ์ง์ ์ฌ๊ฒ์ฆ์ ํต๊ณผํด์ผ ํ๋ฉฐ ์๋ ์ฌ์๋ํ์ง ์์ต๋๋ค.
flowchart LR
U["์ฌ์ฉ์"] --> H["MCP ํด๋ผ์ด์ธํธ"]
H -->|"๋๊ตฌ ์ธ์<br/>(๋น๋ฐ๊ฐ ์์)"| M["TossInvest MCP"]
H -->|"๋น๊ณต๊ฐ ์์ฒญ ํค๋<br/>HTTPS ๋๋ loopback HTTP"| M
M --> C["์์ฒญ๋ณ ์ธ์ฆ ์ปจํ
์คํธ"]
C --> T["ํ ์ค์ฆ๊ถ Open API"]
U -->|"๋ณ๋ ์ฌ๋ ์น์ธ token"| A["์น์ธ ํ์ด์ง"]
A --> M
ํ์ํ ๊ฒ์ Python 3.12 ๋๋ Docker, ๊ทธ๋ฆฌ๊ณ ํ ์ค์ฆ๊ถ Open API client_id์
client_secret์
๋๋ค.
์ด์ ํ๊ฒฝ์์๋ ์ด๋ํ๋ main์ด๋ latest ๋์ ํ์ฌ ์์ ๋ฒ์ ์ธ
v0.1.1์ ๊ณ ์ ํ์ธ์.
git clone --branch v0.1.1 --depth 1 https://github.com/cha2hyun/tossinvest-mcp.git
cd tossinvest-mcp
cp .env.example .env
docker compose up -d --build
curl http://127.0.0.1:8000/healthzGitHub Release์๋ Python wheel, source distribution๊ณผ SHA-256 checksum์ด ์ฒจ๋ถ๋ฉ๋๋ค. ๋น๋ ์์ด ๊ฒ์๋ multi-architecture GHCR ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ฒ์ ์ ๋ช ์ํด ์คํํ์ธ์.
TOSSINVEST_IMAGE=ghcr.io/cha2hyun/tossinvest-mcp:0.1.1 docker compose pull
TOSSINVEST_IMAGE=ghcr.io/cha2hyun/tossinvest-mcp:0.1.1 docker compose up -d --no-buildlatest๋ ์ ๋ฆด๋ฆฌ์ฆ๋ง๋ค ์ด๋ํฉ๋๋ค. ์ฌํ ๊ฐ๋ฅํ ๋ฐฐํฌ์๋ 0.1.1์ฒ๋ผ ์ ์ฒด ๋ฒ์ ํ๊ทธ๋ฅผ
์ฌ์ฉํ์ธ์. ๋ฆด๋ฆฌ์ฆ ์ ์ฐจ๋ RELEASING.md์ ์ ๋ฆฌ๋์ด ์์ต๋๋ค.
์๋ฒ .env์๋ ํฌํธ์ ์บ์ ๊ฐ์ ๋น๋ฐ์ด ์๋ ์ด์ ์ค์ ๋ง ๋ก๋๋ค. ํ ์ค ํค์ ๊ณ์ข๊ฐ์
์ถ๊ฐํ์ง ๋ง์ธ์.
๊ธฐ๋ณธ ๋ก์ปฌ ์ฃผ์:
| ์ฉ๋ | ์ฃผ์ |
|---|---|
| MCP | http://127.0.0.1:8000/mcp |
| ์ํ | http://127.0.0.1:8000/healthz |
| ์ค๋น ์ํ | http://127.0.0.1:8000/readyz |
์์ฒญ๋ณ ์ธ์ฆ ๋ชจ๋์ /readyz๋ ์ธ๋ถ API๋ฅผ ํธ์ถํ๊ฑฐ๋ ์๊ฒฉ ์ฆ๋ช
์ ๊ฒ์ฌํ์ง ์๊ณ ์๋ฒ๊ฐ ์์ฒญ์
๋ฐ์ ์ค๋น๊ฐ ๋์๋์ง๋ง ๋ฐํํฉ๋๋ค.
| ๋ณ์ | ๊ธฐ๋ณธ๊ฐ | ์ค๋ช |
|---|---|---|
MCP_PUBLISHED_HOST |
127.0.0.1 |
Compose๊ฐ ํธ์คํธ์ ๋ฐ์ธ๋ฉํ ์ฃผ์ |
MCP_PUBLISHED_PORT |
8000 |
Compose๊ฐ ๊ณต๊ฐํ ํฌํธ |
MCP_TENANT_CACHE_SIZE |
100 |
๋ฉ๋ชจ๋ฆฌ์ ์ ์งํ ์์ฒญ๋ณ ์ธ์ฆ ์ปจํ ์คํธ ์ต๋ ์ |
MCP_TENANT_CACHE_TTL |
3600 |
์ฌ์ฉํ์ง ์์ ์ธ์ฆ ์ปจํ ์คํธ ๋ณด์กด ์๊ฐ(์ด) |
MCP_TRUSTED_PROXY_IPS |
127.0.0.1 |
forwarded scheme์ ์ ๋ขฐํ reverse proxy IP ๋ชฉ๋ก |
MCP_ALLOWED_ORIGINS |
๋น ๊ฐ | ๋ธ๋ผ์ฐ์ MCP ์์ฒญ์ ํ์ฉํ Origin ๋ชฉ๋ก |
TOSSINVEST_APPROVAL_BASE_URL |
http://127.0.0.1:8000 |
preview๊ฐ ๋ฐํํ ์น์ธ ํ์ด์ง origin |
TOSSINVEST_BASE_URL |
๊ณต์ API ์ฃผ์ | ํ ์คํธยทํธํ ํ๋ก์์ฉ upstream ์ฃผ์ |
TOSSINVEST_REQUEST_TIMEOUT |
15 |
upstream timeout(์ด) |
LOG_LEVEL |
INFO |
์๋ฒ ๋ก๊ทธ ๋ ๋ฒจ |
์ง์ ์คํํ ๋๋ง MCP_HOST์ MCP_PORT๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๋ ๊ฐ์ Compose ๋ด๋ถ์์
๊ฐ๊ฐ 0.0.0.0, 8000์ผ๋ก ๊ณ ์ ๋ฉ๋๋ค.
/mcp ์์ฒญ์ด 403 {"error":"origin-not-allowed"}๋ก ์คํจํ๋ฉด ๋ธ๋ผ์ฐ์ ๋ ์น๋ทฐ ๊ธฐ๋ฐ
ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ Origin์ด ํ์ฉ๋์ง ์์ ๊ฒ์
๋๋ค. ํด๋น ํด๋ผ์ด์ธํธ์ ์ ํํ origin์
์ผํ๋ก ๊ตฌ๋ถํด MCP_ALLOWED_ORIGINS์ ๋ฃ๊ณ ์ปจํ
์ด๋๋ฅผ ๋ค์ ์์ฑํ์ธ์. ์:
MCP_ALLOWED_ORIGINS=http://127.0.0.1:6274,http://localhost:6274.
ํ ์ค ์๊ฒฉ ์ฆ๋ช
์ MCP ์๋ฒ๊ฐ ์๋๋ผ ํด๋ผ์ด์ธํธ์ ๋น๋ฐ ์ ์ฅ์์ ๋ก๋๋ค. Hermes ์์๋
~/.hermes/.env์
๋๋ค.
TOSSINVEST_CLIENT_ID=๋ฐ๊ธ๋ฐ์_client_id
TOSSINVEST_CLIENT_SECRET=๋ฐ๊ธ๋ฐ์_client_secret~/.hermes/config.yaml:
mcp_servers:
tossinvest:
url: "http://127.0.0.1:8000/mcp"
headers:
X-Tossinvest-Client-Id: "${TOSSINVEST_CLIENT_ID}"
X-Tossinvest-Client-Secret: "${TOSSINVEST_CLIENT_SECRET}"
enabled: true
timeout: 120
connect_timeout: 30
supports_parallel_tool_calls: false์ด ํค๋๋ MCP ์ฐ๊ฒฐ ๊ณ์ธต์ด ์๋์ผ๋ก ๋ถ์ด๋ฉฐ ๋ชจ๋ธ์ ๋๊ตฌ ์ธ์์๋ ํฌํจ๋์ง ์์ต๋๋ค. ์ค์ ์๊ฒฉ ์ฆ๋ช ๊ฐ์ ํ๋กฌํํธ, ์ฑํ , Skill, tool argument์ ๋ณต์ฌํ์ง ๋ง์ธ์.
์กฐํ ์ ์ฉ allowlist ์ ์ฒด ์์๋
examples/hermes-config.yaml, ํด๋ผ์ด์ธํธ ํ๊ฒฝ๋ณ์ ์์๋
examples/hermes.env.example์ ์์ต๋๋ค.
์๋ฒ๋ client_id์ client_secret์ผ๋ก OAuth token์ ๋ฐ๊ธํ ๋ค ๊ณ์ข ๋ชฉ๋ก API๋ฅผ ํธ์ถํฉ๋๋ค.
๊ณ์ข๊ฐ ํ๋๋ฉด ์ค์ accountSeq๋ฅผ ๋ด๋ถ ๋ฉ๋ชจ๋ฆฌ์์ ์๋ ์ ํํ๋ฏ๋ก ์ฌ์ฉ์๊ฐ sequence๋ฅผ ์๊ฑฐ๋
์ค์ ํ ํ์๊ฐ ์์ต๋๋ค.
๊ณ์ข๊ฐ ์ฌ๋ฌ ๊ฐ๋ฉด ์๋ฒ๋ ์์๋ก ์ฃผ๋ฌธ ๊ณ์ข๋ฅผ ์ ํํ์ง ์์ต๋๋ค. list_accounts๊ฐ ๊ณ์ข๋ฒํธ์
sequence๋ฅผ ์ ๊ฑฐํ ๋ค์ account_index, ๊ณ์ข ์ ํ, ์ ํ ์ํ๋ง ๋ฐํํฉ๋๋ค. ์ฌ์ฉํ ๊ณ์ข์
1๋ถํฐ ์์ํ๋ index๋ฅผ MCP ์ฐ๊ฒฐ ํค๋์ ์ถ๊ฐํ์ธ์.
X-Tossinvest-Account-Index: "${TOSSINVEST_ACCOUNT_INDEX}"index๋ ์ค์ ๊ณ์ข๊ฐ์ด ์๋๋ฉฐ ๋ชจ๋ธ ๋๊ตฌ ์ธ์์๋ ๋ค์ด๊ฐ์ง ์์ต๋๋ค.
๋ช
๋ น ํ๋ ํธ์ MCP: Open User Configuration์์ ์ฌ๋ mcp.json์๋ ๊ธฐ๋ณธ์ ์ผ๋ก
client_id์ client_secret ๋ ์
๋ ฅ๋ง ํ์ํฉ๋๋ค. VS Code๊ฐ ${input:...} ๊ฐ์ ์ฒ์
์ฐ๊ฒฐํ ๋ ๋ฌผ์ด๋ณด๊ณ ๋ณด์ ์ ์ฅ์์ ๋ณด๊ดํฉ๋๋ค.
{
"inputs": [
{
"type": "promptString",
"id": "tossinvest-client-id",
"description": "TossInvest Client ID",
"password": true
},
{
"type": "promptString",
"id": "tossinvest-client-secret",
"description": "TossInvest Client Secret",
"password": true
}
],
"servers": {
"tossinvest": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp",
"headers": {
"X-Tossinvest-Client-Id": "${input:tossinvest-client-id}",
"X-Tossinvest-Client-Secret": "${input:tossinvest-client-secret}"
}
}
}
}์ค์ ID์ secret์ JSON์ ์ง์ ์ ์ง ๋ง์ธ์. ${input:...}๋ก ์
๋ ฅํ ๊ฐ์ ์ฐ๊ฒฐ ํค๋์๋ง
์ฌ์ฉ๋๋ฉฐ ๋ชจ๋ธ์ด ์์ฑํ๋ ๋๊ตฌ JSON ์ธ์์๋ ํฌํจ๋์ง ์์ต๋๋ค. ๊ณต๊ฐ ์๋ฒ๋ผ๋ฉด url์ ๋ฐ๋์
https://์ฌ์ผ ํฉ๋๋ค.
์ ์ฒด ์กฐํ ์์ ๋ examples/vscode-mcp.json, ๊ฑฐ๋ ๋ชจ๋ ์์ ๋
examples/vscode-mcp-trading.json์ ์์ต๋๋ค.
๋ค์ค ๊ณ์ข์์๋ง ๋ค์ input๊ณผ header๋ฅผ ์ถ๊ฐํฉ๋๋ค.
{
"type": "promptString",
"id": "tossinvest-account-index",
"description": "TossInvest account index from list_accounts",
"password": false
}{
"X-Tossinvest-Account-Index": "${input:tossinvest-account-index}"
}๊ธฐ๋ณธ ์กฐํ ๋ชจ๋๋ ๋ค์ 28๊ฐ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
| ๊ตฌ๋ถ | ๋๊ตฌ |
|---|---|
| ์ข ๋ชฉยท์์ธ | get_stock_info, list_stocks, get_stock_warnings, get_prices, get_orderbook, get_recent_trades, get_price_limits, get_candles |
| ์ข ๋ชฉ ๋ํฅ | get_stock_investor_trading, get_stock_program_trades, get_stock_short_selling, get_stock_credit_trades, get_stock_securities_lending |
| ์์ฅ ์ ๋ณด | get_exchange_rate, get_market_calendar, get_rankings, get_market_indicator_prices, get_market_indicator_candles, get_market_indicator_investor_trading |
| ๊ณ์ขยท์์ฐ | list_accounts, get_holdings, get_buying_power, get_sellable_quantity, get_commissions |
| ์ฃผ๋ฌธ ์กฐํ | list_orders, get_order, list_conditional_orders, get_conditional_order |
๊ณต์ OpenAPI์ ์กฐ๊ฑด์ฃผ๋ฌธ ์์ฑยท์์ ยท์ทจ์๋ ์ผ๋ฐ ์ฃผ๋ฌธ์ ์ ์ฉ๋ preview, ๋ณ๋ ์ฌ๋ ์น์ธ, ์คํ ์ง์ ์ฌ๊ฒ์ฆ์ด ์์ง ๊ตฌํ๋์ง ์์ MCP ๋๊ตฌ๋ก ๋ ธ์ถํ์ง ์์ต๋๋ค.
๊ฑฐ๋ ๋ชจ๋๋ ์๋ ์ธ ์กฐ๊ฑด์ ๋ชจ๋ ์ถฉ์กฑํด์ผ ํฉ๋๋ค.
- ์๋ฒ๋ฅผ
--dangerously-enable-trading์ผ๋ก ์์ - MCP ํด๋ผ์ด์ธํธ๊ฐ ์ฃผ๋ฌธ ํ๋์ ์น์ธ token digest ํค๋๋ฅผ ์ ๋ฌ
- ์ฌ์ฉ์๊ฐ ๋ณ๋ ์น์ธ ํ์ด์ง์์ ์๋ฌธ ์น์ธ token์ผ๋ก preview๋ฅผ ์น์ธ
์๋ฌธ ์น์ธ token์ ๋น๋ฐ๋ฒํธ ๊ด๋ฆฌ์์ฒ๋ผ MCP ํด๋ผ์ด์ธํธ์ ์๋ฒ ๋ฐ์ ์ ์ฅ์์ ๋ณด๊ดํฉ๋๋ค. ํด๋ผ์ด์ธํธ์๋ SHA-256 digest๋ง ๋ก๋๋ค.
openssl rand -hex 32
read -rsp "Approval token: " APPROVAL_TOKEN
echo
printf '%s' "$APPROVAL_TOKEN" | openssl dgst -sha256 -r | awk '{print $1}'
unset APPROVAL_TOKEN~/.hermes/.env์ ์ถ๊ฐ:
TOSSINVEST_MAX_ORDER_KRW=1000000
TOSSINVEST_MAX_ORDER_USD=500
TOSSINVEST_APPROVAL_TOKEN_SHA256=64์๋ฆฌ_sha256_digest๊ฑฐ๋์ฉ ํค๋์ allowlist๋
examples/hermes-trading-config.yaml์ ์ฌ์ฉํฉ๋๋ค.
docker compose \
-f compose.yaml \
-f compose.trading.yaml \
up -d --build --force-recreate๋ฑ๋ก๋๋ ์ถ๊ฐ ๋๊ตฌ:
| ์์ | preview | ์คํ |
|---|---|---|
| ์์ฑ | preview_order |
place_order |
| ์ ์ | preview_order_modification |
modify_order |
| ์ทจ์ | preview_order_cancellation |
cancel_order |
preview์๋ ์น์ธ secret์ด ์์ผ๋ฉฐ, ์น์ธ๋์ง ์์ ์คํ์ approval-required๋ก ๊ฑฐ๋ถ๋ฉ๋๋ค.
์น์ธ ํ์๋ ๊ฐ๊ฒฉยทํ์จยท์๊ณ ยทํ๋งค ๊ฐ๋ฅ ์๋ยท์ฃผ๋ฌธ ์ํยทํ๋๋ฅผ ๋ค์ ํ์ธํฉ๋๋ค. ๋คํธ์ํฌ ์ค๋ฅ๋ก
order-state-unknown์ด ๋ฐํ๋๋ฉด ๊ฐ์ ์ฃผ๋ฌธ์ ์ฌ์๋ํ์ง ๋ง๊ณ ์ฃผ๋ฌธ ๋ด์ญ์ ๋จผ์ ํ์ธํ์ธ์.
๊ณต๊ฐ ์๋ฒ๋ ๋ฐ๋์ TLS reverse proxy ๋ค์ ๋์ธ์.
- ์ธ๋ถ MCP URL๊ณผ
TOSSINVEST_APPROVAL_BASE_URL๋ชจ๋https://์ฌ์ฉ - reverse proxy๊ฐ ์๋ scheme์ ์ ๋ฌํ๊ณ ๊ทธ ์ฃผ์๋ง
MCP_TRUSTED_PROXY_IPS์ ์ค์ - proxy access/error log์์
X-Tossinvest-*,Authorization, form body๋ฅผ ์ญ์ ๋๋ redaction - request/response body dump, debug trace, APM header capture ๋นํ์ฑํ
- MCP streaming ์๋ต buffering ๋นํ์ฑํ
/healthz,/readyz,/approvals/*์ ๊ทผ ๋ฒ์ ์ ํ- ๋ฐฉํ๋ฒฝ, VPN ๋๋ ๋ณ๋ gateway ์ธ์ฆ ์ถ๊ฐ
- ๊ณต๊ฐ ํฌํธ๊ฐ ํ์ํ ๋๋ง
MCP_PUBLISHED_HOST=0.0.0.0์ฌ์ฉ
์ ํ๋ฆฌ์ผ์ด์ ์ HTTPS๊ฐ ์๋ ๊ณต๊ฐ ์์ฒญ์ ๊ฑฐ๋ถํ์ง๋ง, TLS ์ข ๋ฃ์ proxy ๋ก๊ทธ ์ ์ฑ ์ reverse proxy ์ด์์๊ฐ ์ฑ ์์ ธ์ผ ํฉ๋๋ค.
๊ธฐ๋ณธ Compose๋ loopback bind, non-root ์ฌ์ฉ์, read-only root filesystem, capability ์ ๊ฑฐ,
no-new-privileges, ์ ํ๋ /tmp, ๋จ์ผ worker๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ธ์ฆ ์ปจํ
์คํธ์ preview๋
๋ฉ๋ชจ๋ฆฌ์ ์์ผ๋ฏ๋ก ์๋ฒ ์ฌ์์ ์ ์ฌ๋ผ์ง๋๋ค. ํ์ฌ ๊ตฌ์กฐ๋ ๋จ์ผ instance ์ ์ ์
๋๋ค.
uv sync --all-extras
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy src scripts tests
uv run pip-audit --strict .
uv run python scripts/check_docs.py
uv run python scripts/validate_skills.py
uv run python scripts/update_openapi.py --check
uv build
docker build .
./scripts/run_e2e.shrun_e2e.sh๋ ํ๋ก๋์
์ด๋ฏธ์ง๋ฅผ ๊ธฐ๋ํ๊ณ ๋ก์ปฌ ๊ฐ์ง upstream์ ํตํด MCP HTTP, ์์ฒญ๋ณ
์๊ฒฉ ์ฆ๋ช
๊ฒฉ๋ฆฌ, OAuth, ์กฐํ ํธ์ถ๊ณผ ์ค๋ฅ redaction์ ๋๊น์ง ๊ฒ์ฆํฉ๋๋ค. ์ธ๋ถ API๋ ์ค์
์๊ฒฉ ์ฆ๋ช
์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
๋ณด์ ๋ฌธ์ ๋ ๊ณต๊ฐ Issue ๋์ SECURITY.md์ ์ ์ฐจ๋ก ์ ๊ณ ํ์ธ์.