ianlyoo/K-invest
GitHub: ianlyoo/K-invest
一个只读投资数据 MCP 服务器,让 Web 端 LLM 能够访问用户的券商账户、持仓、行情和财务数据并据此回答投资相关问题。
Stars: 1 | Forks: 0
# K-invest
[English](README.en.md) · [MIT 许可证](LICENSE) · Python 3.10+ · 
ChatGPT、Claude、Perplexity 等 Web LLM 并不知道我的账户、持仓股票和交易记录。
K-invest 将 **Toss Securities、Korea Investment & Securities (KIS)、SEC EDGAR、yfinance、Binance USD-M 期货**
整合到一个 MCP(Model Context Protocol)服务器中,让 LLM 能够以只读方式
访问我的投资数据并据此作出回答。
**没有下单、修改或取消的工具。** 所有 endpoint 均为 read-only。
## 架构
```
flowchart LR
A[Claude / ChatGPT / Perplexity] -- "HTTPS + Bearer" --> B[K-invest
FastMCP · Streamable HTTP] B --> C[Toss Securities] B --> D[KIS Open API] B --> E[SEC EDGAR] B --> F[yfinance] B --> G[Binance USD-M Futures] B -.optional.-> H[margin-ta 기술적 분석] ``` ## 快速开始 ### 方法 1 — clone & run ``` git clone https://github.com/ianlyoo/K-invest && cd K-invest pip install -r requirements.txt cp .env.example .env # MCP_AUTH_TOKEN과 provider credential 채우기 python3 server.py # 127.0.0.1:8100 에서 기동 ``` ### 方法 2 — pip 安装 ``` pip install git+https://github.com/ianlyoo/K-invest # venv/pipx/uv 격리 설치 권장 k-invest ``` provider **支持部分配置**。即使只配置了 Toss,服务器也会启动,未配置的 provider 相关工具将返回类似 `KIS_NOT_CONFIGURED` 的错误 envelope。 ## 工具目录 ### 行情/市场数据 | 工具 | 说明 | |------|------| | `get_quote(symbol)` | Toss 当前价格 | | `get_orderbook(symbol)` | Toss 买卖盘 | | `get_recent_trades(symbol)` | Toss 最近市场成交 | | `get_price_limits(symbol)` | 涨/跌停板。基准日/交易时段需结合 provider 字段进行解析。 | | `get_candles(symbol, interval="1d", count=100)` | `1d` 或 `1m` 蜡烛图 | | `get_stock_info(symbol)` | 股票基本信息 | | `get_stock_warnings(symbol)` | 买入注意事项 | | `get_exchange_rate(base="USD", quote="KRW")` | 汇率 | | `get_market_hours(market="US"|"KR")` | 交易时间 | | `get_kis_domestic_quote(symbol)` | KIS 国内行情 | | `get_kis_overseas_quote(symbol, exchange)` | KIS 海外行情。日本允许使用 `TKSE`/`TSE`,内部 KIS 代码使用 `TSE`。 | | `compare_quotes(symbol, exchange="NASDAQ")` | Toss/KIS 行情比较及 provider 警告 | ### 加密货币期货数据 仅使用 Binance USD-M Futures 的公开 market-data endpoint。不需要 API 密钥,不暴露下单/杠杆/保证金/转账功能。 | 工具 | 说明 | |------|------| | `get_binance_futures_quote(symbol)` | 最新期货价格。例:`BTCUSDT`, `ETHUSDT` | | `get_binance_futures_mark_price(symbol)` | mark price, index price, latest funding rate | | `get_binance_funding_rate(symbol, limit=10)` | 资金费率历史。包含 `funding_rate_pct` | | `get_binance_open_interest(symbol, history=false, period="1h", limit=30)` | 当前 open interest 或最近 1 个月范围历史 | | `get_binance_futures_candles(symbol, interval="1h", count=100, price_type="last")` | 基于 last price 或 mark price 的期货蜡烛图 | | `get_crypto_futures_snapshot(symbol)` | 价格、mark/index、资金费率、open interest 汇总 | `get_crypto_futures_snapshot("BTCUSDT")` 示例: ``` { "symbol": "BTCUSDT", "market": "binance_usd_m_futures", "auth_required": false, "quote": {"price": 60000.5}, "mark": {"mark_price": 60010.25, "last_funding_rate_pct": 0.01}, "funding_rates": [{"funding_rate_pct": 0.01}], "open_interest": {"open_interest": 123.45}, "open_interest_notional": 7408265.3625 } ``` ### 账户/投资组合查询 | 工具 | 说明 | |------|------| | `get_toss_accounts()` | 已配置的 Toss 账户 label 列表。不返回 credential 值。 | | `get_toss_holdings(symbol="", account="primary")` | Toss 持仓股票。`account` 可为 `primary`, `secondary`, `all` | | `get_toss_buying_power(currency="USD"|"KRW", account="primary")` | Toss 可用买入金额。支持 `account="all"` | | `get_toss_trade_history(limit=50, account="primary")` | Toss 最近成交记录。支持 `account="all"` | | `get_kis_domestic_balance()` | KIS 国内余额 | | `get_kis_overseas_balance()` | KIS 海外余额 | | `get_kis_trade_history(start_date, end_date)` | KIS 成交记录 | | `get_kis_cash_balance()` | KIS 现金余额 | | `get_portfolio_risk(detail_level="summary")` | 尽力收集 Toss/KIS 持仓,计算各货币敞口和集中度风险 | ### 财务/公告 | 工具 | 说明 | |------|------| | `get_financials(symbol)` | yfinance 财务报表/估值。比率以 `_pct` 表示,期间以 `period_type`/`period_end` 表示。 | | `get_key_metrics(symbol)` | 关键估值/盈利能力/增长率指标。包含 yfinance 预期 EPS/营收预估、目标价及推荐共识。 | | `get_sec_financials(symbol)` | SEC CompanyFacts 10-K 年度财务 + 10-Q 季度财务 + 最近 4 个会计季度 TTM | | `get_ttm_financials(symbol)` | 基于 SEC 10-Q/FY 的 TTM 汇总及最近季度列表 | | `get_insider_trades(symbol, days_back=180, detail_level="summary")` | SEC Form 4 内部人士交易。默认为汇总/聚合,仅在 `full` 时包含 raw lot。 | | `get_risk_free_rate()` | 基于 yfinance `^TNX` 的 10 年期美国国债收益率 | `get_sec_financials` SEC 扩展块示例: ``` { "quarters": [{"fiscal_year": 2026, "fiscal_period": "Q2", "revenue": {"value": 10599000000}}], "ttm": { "period_type": "TTM", "revenue": {"value": 44487000000}, "operating_income": {"value": 11355000000}, "operating_cash_flow": {"value": 14285000000}, "capex": {"value": 1783000000}, "free_cash_flow": {"value": 12502000000} }, "segment_revenue": { "latest_quarter": [ {"segment": "qct", "value": 9076000000}, {"segment": "qtl", "value": 1382000000}, {"segment": "handsets", "value": 6024000000} ] }, "annuals": [{"earnings_quality": {"normalization_flags": ["high_effective_tax_rate"]}}] } ``` `get_key_metrics` 共识示例: ``` { "analyst_consensus": { "forward_eps": 10.9653, "target_price": {"mean": 215.42, "median": 220.0}, "recommendation": {"key": "hold", "mean": 2.51}, "revenue_estimate": {"+1y": {"avg": 43579002120, "growth_pct": 2.37}} } } ``` ### 技术分析 | 工具 | 说明 | |------|------| | `analyze_technical(symbol, market="auto", detail_level="summary")` | margin-ta 综合分析摘要 | | `get_entry_plan(symbol, market="auto", detail_level="summary")` | 推荐入场策略/止损/目标价 | | `scan_top_stocks(top_n=5, min_score=0)` | NASDAQ100 + S&P500 技术扫描器。使用 margin-ta `scan_nightly.py --json` | 若未设置 `MARGIN_TA_HOME`,将返回 `MARGIN_TA_NOT_CONFIGURED` 错误,这是一项可选功能。 margin-ta 对于韩国股票,将根据 KRW 报价单位对入场价/止损价/目标价进行取整。`entry_tranche_pct` 为战术性入场 tranche 大小,并非整体投资组合仓位建议。若相对首个目标价的 R:R 较低,将降低 quality/confidence 并返回警告。 ### 复合/运营工具 | 工具 | 说明 | |------|------| | `get_stock_snapshot(symbol, market="auto")` | 一次性返回行情比较、关键指标、内部人士摘要、技术入场计划 | | `get_portfolio_risk(detail_level="summary")` | 投资组合货币敞口/集中度风险 | | `health_check()` | Toss/KIS/SEC/yfinance/margin-ta 轻量级状态检查 | | `get_invest_mcp_help(topic="overview")` | LLM 使用指南 | ## 互联网暴露 (HTTPS) MCP connector 需要 HTTPS。只要有固定 IP,即可使用 [sslip.io](https://sslip.io) 和 Caddy 在没有域名的情况下进行暴露: ``` # /etc/caddy/Caddyfile — 将 替换为服务器公网 IP
.sslip.io {
reverse_proxy 127.0.0.1:8100
}
```
在 `.env` 中设置 `MCP_PUBLIC_URL=https://.sslip.io`(DNS rebinding
保护允许列表将从此值推导得出)。
## 连接 LLM 客户端
- **Claude** (Pro/Max/Team): 设置 → Connectors → *Add custom connector* →
URL 为公开 URL 加上 `/mcp` (`https://.sslip.io` + `/mcp`),
Authorization 填入 `MCP_AUTH_TOKEN` 值
- **ChatGPT** (Pro/Business): 设置 → Connectors → 添加 MCP 服务器 — 相同的 URL/token
## 配置参考
| 环境变量 | 必需 | 说明 |
|---|---|---|
| `MCP_AUTH_TOKEN` | ✅ | Bearer token。使用 `openssl rand -hex 32` 生成 |
| `MCP_PUBLIC_URL` | | 外部访问 URL (默认 `http://127.0.0.1:8100`) |
| `TOSS_CLIENT_ID` / `TOSS_CLIENT_SECRET` | ✅* | Toss Securities Open API (WTS → 设置 → Open API) |
| `TOSS_CREDS_FILE` | | 多账户 JSON (`{"accounts": [...]}`, chmod 600) |
| `KIS_APP_KEY` / `KIS_APP_SECRET` | | KIS Open API ([签发](https://apiportal.koreainvestment.com)) |
| `KIS_CANO` / `KIS_ACNT_PRDT_CD` | | KIS 8 位账号 / 2 位产品代码 |
| `KIS_ENV_FILE` | | 复用包含 APP_KEY 等信息的现有 env 文件 |
| `SEC_USER_AGENT` | | SEC 建议 UA — 包含可联系的电子邮件 |
| `MARGIN_TA_HOME` | | margin-ta 检出路径(启用 3 种技术分析) |
| `KINVEST_CACHE_DIR` | | token 缓存目录 (默认 `~/.cache/k-invest`) |
\* Toss 或 KIS 至少需要其一。其余为可选。
## 响应协议
所有工具均返回 `{ok, data, error, meta}` envelope:
```
{"ok": true, "data": {...}, "error": null,
"meta": {"server_version": "2.0.0", "provider": "toss"}}
```
失败时,将填充 `error.code`(如 `KIS_NOT_CONFIGURED`, `UPSTREAM_TOSS_ERROR` 等)、`provider` 以及
`retryable`。各 provider 之间的行情差异可能是正常的——因为交易所、交易时段或延迟
不同,`compare_quotes` 类工具会在警告字段中明确指出这一点。
## 安全
- **READ-ONLY 不变量**:不注册任何与下单相关的工具。也拒不接受相关 PR。
- credential 仅通过 env/文件注入,且不会在响应中暴露。creds 文件需执行 `chmod 600`。
- 若无 MCP_AUTH_TOKEN,服务器将拒绝启动。
- 互联网暴露时:需使用高强度 token,强制开启 HTTPS,禁止在防火墙直接暴露 8100 端口(仅限反向代理)。
## systemd 常驻运行 (可选)
替换 `deploy/k-invest.service` 模板中的占位符(如 `youruser`),
安装至 `/etc/systemd/system/`,并将 env 配置文件放置于 `/etc/k-invest.env`。
## margin-ta (可选)
`analyze_technical`/`get_entry_plan`/`scan_top_stocks` 需要单独的技术分析引擎
[margin-ta] 的本地检出 (`MARGIN_TA_HOME`)。**margin-ta 即将作为独立仓库公开**,
在此之前,这 3 个工具为可选功能。
## 开发
```
python3 -m pytest tests/ # 테스트
ruff check . # 린트
```
## 免责声明
所有输出均为辅助投资判断的数据,并非交易建议。不保证数据的准确性与时效性,
因使用产生的任何损失由用户自行承担。
## 许可证
[MIT](LICENSE) © 2026 AhnRyu
FastMCP · Streamable HTTP] B --> C[Toss Securities] B --> D[KIS Open API] B --> E[SEC EDGAR] B --> F[yfinance] B --> G[Binance USD-M Futures] B -.optional.-> H[margin-ta 기술적 분석] ``` ## 快速开始 ### 方法 1 — clone & run ``` git clone https://github.com/ianlyoo/K-invest && cd K-invest pip install -r requirements.txt cp .env.example .env # MCP_AUTH_TOKEN과 provider credential 채우기 python3 server.py # 127.0.0.1:8100 에서 기동 ``` ### 方法 2 — pip 安装 ``` pip install git+https://github.com/ianlyoo/K-invest # venv/pipx/uv 격리 설치 권장 k-invest ``` provider **支持部分配置**。即使只配置了 Toss,服务器也会启动,未配置的 provider 相关工具将返回类似 `KIS_NOT_CONFIGURED` 的错误 envelope。 ## 工具目录 ### 行情/市场数据 | 工具 | 说明 | |------|------| | `get_quote(symbol)` | Toss 当前价格 | | `get_orderbook(symbol)` | Toss 买卖盘 | | `get_recent_trades(symbol)` | Toss 最近市场成交 | | `get_price_limits(symbol)` | 涨/跌停板。基准日/交易时段需结合 provider 字段进行解析。 | | `get_candles(symbol, interval="1d", count=100)` | `1d` 或 `1m` 蜡烛图 | | `get_stock_info(symbol)` | 股票基本信息 | | `get_stock_warnings(symbol)` | 买入注意事项 | | `get_exchange_rate(base="USD", quote="KRW")` | 汇率 | | `get_market_hours(market="US"|"KR")` | 交易时间 | | `get_kis_domestic_quote(symbol)` | KIS 国内行情 | | `get_kis_overseas_quote(symbol, exchange)` | KIS 海外行情。日本允许使用 `TKSE`/`TSE`,内部 KIS 代码使用 `TSE`。 | | `compare_quotes(symbol, exchange="NASDAQ")` | Toss/KIS 行情比较及 provider 警告 | ### 加密货币期货数据 仅使用 Binance USD-M Futures 的公开 market-data endpoint。不需要 API 密钥,不暴露下单/杠杆/保证金/转账功能。 | 工具 | 说明 | |------|------| | `get_binance_futures_quote(symbol)` | 最新期货价格。例:`BTCUSDT`, `ETHUSDT` | | `get_binance_futures_mark_price(symbol)` | mark price, index price, latest funding rate | | `get_binance_funding_rate(symbol, limit=10)` | 资金费率历史。包含 `funding_rate_pct` | | `get_binance_open_interest(symbol, history=false, period="1h", limit=30)` | 当前 open interest 或最近 1 个月范围历史 | | `get_binance_futures_candles(symbol, interval="1h", count=100, price_type="last")` | 基于 last price 或 mark price 的期货蜡烛图 | | `get_crypto_futures_snapshot(symbol)` | 价格、mark/index、资金费率、open interest 汇总 | `get_crypto_futures_snapshot("BTCUSDT")` 示例: ``` { "symbol": "BTCUSDT", "market": "binance_usd_m_futures", "auth_required": false, "quote": {"price": 60000.5}, "mark": {"mark_price": 60010.25, "last_funding_rate_pct": 0.01}, "funding_rates": [{"funding_rate_pct": 0.01}], "open_interest": {"open_interest": 123.45}, "open_interest_notional": 7408265.3625 } ``` ### 账户/投资组合查询 | 工具 | 说明 | |------|------| | `get_toss_accounts()` | 已配置的 Toss 账户 label 列表。不返回 credential 值。 | | `get_toss_holdings(symbol="", account="primary")` | Toss 持仓股票。`account` 可为 `primary`, `secondary`, `all` | | `get_toss_buying_power(currency="USD"|"KRW", account="primary")` | Toss 可用买入金额。支持 `account="all"` | | `get_toss_trade_history(limit=50, account="primary")` | Toss 最近成交记录。支持 `account="all"` | | `get_kis_domestic_balance()` | KIS 国内余额 | | `get_kis_overseas_balance()` | KIS 海外余额 | | `get_kis_trade_history(start_date, end_date)` | KIS 成交记录 | | `get_kis_cash_balance()` | KIS 现金余额 | | `get_portfolio_risk(detail_level="summary")` | 尽力收集 Toss/KIS 持仓,计算各货币敞口和集中度风险 | ### 财务/公告 | 工具 | 说明 | |------|------| | `get_financials(symbol)` | yfinance 财务报表/估值。比率以 `_pct` 表示,期间以 `period_type`/`period_end` 表示。 | | `get_key_metrics(symbol)` | 关键估值/盈利能力/增长率指标。包含 yfinance 预期 EPS/营收预估、目标价及推荐共识。 | | `get_sec_financials(symbol)` | SEC CompanyFacts 10-K 年度财务 + 10-Q 季度财务 + 最近 4 个会计季度 TTM | | `get_ttm_financials(symbol)` | 基于 SEC 10-Q/FY 的 TTM 汇总及最近季度列表 | | `get_insider_trades(symbol, days_back=180, detail_level="summary")` | SEC Form 4 内部人士交易。默认为汇总/聚合,仅在 `full` 时包含 raw lot。 | | `get_risk_free_rate()` | 基于 yfinance `^TNX` 的 10 年期美国国债收益率 | `get_sec_financials` SEC 扩展块示例: ``` { "quarters": [{"fiscal_year": 2026, "fiscal_period": "Q2", "revenue": {"value": 10599000000}}], "ttm": { "period_type": "TTM", "revenue": {"value": 44487000000}, "operating_income": {"value": 11355000000}, "operating_cash_flow": {"value": 14285000000}, "capex": {"value": 1783000000}, "free_cash_flow": {"value": 12502000000} }, "segment_revenue": { "latest_quarter": [ {"segment": "qct", "value": 9076000000}, {"segment": "qtl", "value": 1382000000}, {"segment": "handsets", "value": 6024000000} ] }, "annuals": [{"earnings_quality": {"normalization_flags": ["high_effective_tax_rate"]}}] } ``` `get_key_metrics` 共识示例: ``` { "analyst_consensus": { "forward_eps": 10.9653, "target_price": {"mean": 215.42, "median": 220.0}, "recommendation": {"key": "hold", "mean": 2.51}, "revenue_estimate": {"+1y": {"avg": 43579002120, "growth_pct": 2.37}} } } ``` ### 技术分析 | 工具 | 说明 | |------|------| | `analyze_technical(symbol, market="auto", detail_level="summary")` | margin-ta 综合分析摘要 | | `get_entry_plan(symbol, market="auto", detail_level="summary")` | 推荐入场策略/止损/目标价 | | `scan_top_stocks(top_n=5, min_score=0)` | NASDAQ100 + S&P500 技术扫描器。使用 margin-ta `scan_nightly.py --json` | 若未设置 `MARGIN_TA_HOME`,将返回 `MARGIN_TA_NOT_CONFIGURED` 错误,这是一项可选功能。 margin-ta 对于韩国股票,将根据 KRW 报价单位对入场价/止损价/目标价进行取整。`entry_tranche_pct` 为战术性入场 tranche 大小,并非整体投资组合仓位建议。若相对首个目标价的 R:R 较低,将降低 quality/confidence 并返回警告。 ### 复合/运营工具 | 工具 | 说明 | |------|------| | `get_stock_snapshot(symbol, market="auto")` | 一次性返回行情比较、关键指标、内部人士摘要、技术入场计划 | | `get_portfolio_risk(detail_level="summary")` | 投资组合货币敞口/集中度风险 | | `health_check()` | Toss/KIS/SEC/yfinance/margin-ta 轻量级状态检查 | | `get_invest_mcp_help(topic="overview")` | LLM 使用指南 | ## 互联网暴露 (HTTPS) MCP connector 需要 HTTPS。只要有固定 IP,即可使用 [sslip.io](https://sslip.io) 和 Caddy 在没有域名的情况下进行暴露: ``` # /etc/caddy/Caddyfile — 将
标签:API集成, LLM集成, MCP服务器, Python, 可观测性, 市场数据, 投资数据, 无后门, 逆向工具, 金融科技