kiwoom-mcp-server 0.18.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/kiwoom/api.js +14 -1
- package/dist/kiwoom/types.js +15 -0
- package/dist/server.js +1 -1
- package/dist/tools/account-balance.js +34 -7
- package/package.json +2 -1
package/dist/kiwoom/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { sleep } from "../utils/sleep.js";
|
|
3
3
|
import { KiwoomApiError } from "./errors.js";
|
|
4
|
-
import { accountEvaluationResponseSchema, allIndexResponseSchema, brokerActivityResponseSchema, dailyChartItemSchema, depositResponseSchema, etfInfoResponseSchema, etfNavItemSchema, etfReturnItemSchema, foreignHoldingResponseSchema, investorDailyItemSchema, investorTotalItemSchema, lendingTrendResponseSchema, limitStockItemSchema, minuteChartItemSchema, newHighLowItemSchema, orderbookResponseSchema, pendingOrdersResponseSchema, priceChangeRankItemSchema, priceJumpItemSchema, programTradeItemSchema, realizedPnlResponseSchema, sectorPriceResponseSchema, sectorStocksResponseSchema, shortSellingResponseSchema, stockInfoResponseSchema, stockListResponseSchema, themeGroupsResponseSchema, tradingJournalResponseSchema, themeStocksResponseSchema, transactionsResponseSchema, valueRankItemSchema, viStockItemSchema, volumeRankItemSchema, watchlistGroupDetailResponseSchema, watchlistGroupsResponseSchema, } from "./types.js";
|
|
4
|
+
import { accountEvaluationResponseSchema, accountPeriodPlResponseSchema, allIndexResponseSchema, brokerActivityResponseSchema, dailyChartItemSchema, depositResponseSchema, etfInfoResponseSchema, etfNavItemSchema, etfReturnItemSchema, foreignHoldingResponseSchema, investorDailyItemSchema, investorTotalItemSchema, lendingTrendResponseSchema, limitStockItemSchema, minuteChartItemSchema, newHighLowItemSchema, orderbookResponseSchema, pendingOrdersResponseSchema, priceChangeRankItemSchema, priceJumpItemSchema, programTradeItemSchema, realizedPnlResponseSchema, sectorPriceResponseSchema, sectorStocksResponseSchema, shortSellingResponseSchema, stockInfoResponseSchema, stockListResponseSchema, themeGroupsResponseSchema, tradingJournalResponseSchema, themeStocksResponseSchema, transactionsResponseSchema, valueRankItemSchema, viStockItemSchema, volumeRankItemSchema, watchlistGroupDetailResponseSchema, watchlistGroupsResponseSchema, } from "./types.js";
|
|
5
5
|
const STOCK_INFO_PATH = "/api/dostk/stkinfo";
|
|
6
6
|
const ACCOUNT_PATH = "/api/dostk/acnt";
|
|
7
7
|
const CHART_PATH = "/api/dostk/chart";
|
|
@@ -72,6 +72,19 @@ export async function fetchAccountEvaluation(client, qryTp) {
|
|
|
72
72
|
// 남은 페이지가 있는데 상한에서 멈췄으면 데이터가 잘렸다는 뜻.
|
|
73
73
|
return { ...first, acnt_evlt_remn_indv_tot: holdings, truncated: res.hasNext };
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* kt00004 계좌평가현황요청 — consumed only for the 당일/당월/누적 투자손익 block
|
|
77
|
+
* (기간 손익); the deposit/evaluation scalars and per-stock list duplicate
|
|
78
|
+
* kt00001/kt00018. qry_tp "0" = 상장폐지 포함 전체 (probe-validated body).
|
|
79
|
+
*/
|
|
80
|
+
export async function fetchAccountPeriodPl(client) {
|
|
81
|
+
const res = await client.call({
|
|
82
|
+
path: ACCOUNT_PATH,
|
|
83
|
+
apiId: "kt00004",
|
|
84
|
+
body: { qry_tp: "0", dmst_stex_tp: "KRX" },
|
|
85
|
+
});
|
|
86
|
+
return accountPeriodPlResponseSchema.parse(res.json);
|
|
87
|
+
}
|
|
75
88
|
/**
|
|
76
89
|
* kt00015 위탁종합거래내역요청 — all transactions in [fromDate, toDate] (yyyyMMdd).
|
|
77
90
|
* NOTE (live-verified): only 매매 rows are returned for this account type; cash
|
package/dist/kiwoom/types.js
CHANGED
|
@@ -72,6 +72,21 @@ export const accountEvaluationResponseSchema = z.looseObject({
|
|
|
72
72
|
prsm_dpst_aset_amt: str(), // 추정예탁자산
|
|
73
73
|
acnt_evlt_remn_indv_tot: z.array(holdingItemSchema).default([]),
|
|
74
74
|
});
|
|
75
|
+
// ── kt00004: 계좌평가현황 (subset — 당일/당월/누적 기간 손익 필드만 소비) ──
|
|
76
|
+
// 예수금/평가액 계열과 종목별 리스트(stk_acnt_evlt_prst)는 kt00001/kt00018과
|
|
77
|
+
// 중복이라 소비하지 않는다. 필드명은 스펙 그대로(lspft 계열 명명이 뒤섞여 있음).
|
|
78
|
+
export const accountPeriodPlResponseSchema = z.looseObject({
|
|
79
|
+
...envelope,
|
|
80
|
+
tdy_lspft_amt: str(), // 당일투자원금
|
|
81
|
+
invt_bsamt: str(), // 당월투자원금
|
|
82
|
+
lspft_amt: str(), // 누적투자원금
|
|
83
|
+
tdy_lspft: str(), // 당일투자손익 (부호 유의미)
|
|
84
|
+
lspft2: str(), // 당월투자손익 (부호 유의미)
|
|
85
|
+
lspft: str(), // 누적투자손익 (부호 유의미)
|
|
86
|
+
tdy_lspft_rt: str(), // 당일손익율(%)
|
|
87
|
+
lspft_ratio: str(), // 당월손익율(%)
|
|
88
|
+
lspft_rt: str(), // 누적손익율(%)
|
|
89
|
+
});
|
|
75
90
|
// ── kt00015: 위탁종합거래내역 (subset) ──
|
|
76
91
|
// NOTE: trde_dt is the settlement date (D+2), not the trade date.
|
|
77
92
|
export const transactionRowSchema = z.looseObject({
|
package/dist/server.js
CHANGED
|
@@ -27,7 +27,7 @@ import { registerTransactionsTool } from "./tools/transactions.js";
|
|
|
27
27
|
import { registerViStocksTool } from "./tools/vi-stocks.js";
|
|
28
28
|
import { registerWatchlistGroupsTool, registerWatchlistTool } from "./tools/watchlist.js";
|
|
29
29
|
export const SERVER_NAME = "kiwoom-mcp-server";
|
|
30
|
-
export const SERVER_VERSION = "0.
|
|
30
|
+
export const SERVER_VERSION = "0.19.1";
|
|
31
31
|
export function createServer() {
|
|
32
32
|
const server = new McpServer({
|
|
33
33
|
name: SERVER_NAME,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { getKiwoomContext } from "../context.js";
|
|
2
|
-
import { fetchAccountEvaluation, fetchDeposit } from "../kiwoom/api.js";
|
|
2
|
+
import { fetchAccountEvaluation, fetchAccountPeriodPl, fetchDeposit } from "../kiwoom/api.js";
|
|
3
3
|
import { formatKRW, formatPercent, formatSignedKRW, parseKiwoomNumber } from "../utils/num.js";
|
|
4
4
|
import { runTool, textResult } from "./helpers.js";
|
|
5
|
-
export function formatBalance(deposit, evaluation, modeLabel) {
|
|
5
|
+
export function formatBalance(deposit, evaluation, modeLabel, periodPl = null) {
|
|
6
6
|
const n = parseKiwoomNumber;
|
|
7
|
-
|
|
7
|
+
const lines = [
|
|
8
8
|
`[${modeLabel}] 계좌 잔고 요약`,
|
|
9
9
|
"",
|
|
10
10
|
"■ 예수금 (kt00001)",
|
|
@@ -17,20 +17,47 @@ export function formatBalance(deposit, evaluation, modeLabel) {
|
|
|
17
17
|
`- 총평가금액: ${formatKRW(n(evaluation.tot_evlt_amt))}`,
|
|
18
18
|
`- 총평가손익: ${formatSignedKRW(n(evaluation.tot_evlt_pl))} (${formatPercent(n(evaluation.tot_prft_rt))})`,
|
|
19
19
|
`- 추정예탁자산: ${formatKRW(n(evaluation.prsm_dpst_aset_amt))}`,
|
|
20
|
-
]
|
|
20
|
+
];
|
|
21
|
+
// 기간 손익 블록은 best-effort — kt00004 조회 실패 시 조용히 생략된다.
|
|
22
|
+
// 라벨은 키움 스펙 원문 그대로 (당일/당월/누적 투자손익·투자원금·손익율).
|
|
23
|
+
if (periodPl) {
|
|
24
|
+
const values = [
|
|
25
|
+
periodPl.tdy_lspft_amt, periodPl.invt_bsamt, periodPl.lspft_amt,
|
|
26
|
+
periodPl.tdy_lspft, periodPl.lspft2, periodPl.lspft,
|
|
27
|
+
periodPl.tdy_lspft_rt, periodPl.lspft_ratio, periodPl.lspft_rt,
|
|
28
|
+
];
|
|
29
|
+
const allZero = values.every((v) => !(n(v) ?? 0));
|
|
30
|
+
lines.push("", "■ 기간 손익 (kt00004)");
|
|
31
|
+
if (allZero) {
|
|
32
|
+
// REAL 실측(2026-07-13): 보유·이력이 있는 계좌도 9필드 전부 0으로 반환될 수
|
|
33
|
+
// 있다 (집계 시점/기준 미설정 추정). "손익 0원"으로 단정 표시하면 오해를
|
|
34
|
+
// 유발하므로, ka40009 NAV 선례처럼 값이 채워질 때만 수치를 렌더한다.
|
|
35
|
+
lines.push("- 키움이 기간 손익을 모두 0으로 반환했습니다 — 집계 전이거나 수익률 산출 기준이 없는 계좌일 수 있어 실제 손익이 0이라는 뜻은 아닐 수 있습니다.");
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
lines.push(`- 당일투자손익: ${formatSignedKRW(n(periodPl.tdy_lspft))} (${formatPercent(n(periodPl.tdy_lspft_rt))}) / 당일투자원금 ${formatKRW(n(periodPl.tdy_lspft_amt))}`, `- 당월투자손익: ${formatSignedKRW(n(periodPl.lspft2))} (${formatPercent(n(periodPl.lspft_ratio))}) / 당월투자원금 ${formatKRW(n(periodPl.invt_bsamt))}`, `- 누적투자손익: ${formatSignedKRW(n(periodPl.lspft))} (${formatPercent(n(periodPl.lspft_rt))}) / 누적투자원금 ${formatKRW(n(periodPl.lspft_amt))}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return lines.join("\n");
|
|
21
42
|
}
|
|
22
43
|
export function registerAccountBalanceTool(server) {
|
|
23
44
|
server.registerTool("get_account_balance", {
|
|
24
45
|
title: "계좌 잔고 조회",
|
|
25
46
|
description: "계좌의 예수금(주문가능/출금가능 포함)과 총매입금액, 총평가금액, 총평가손익, " +
|
|
26
|
-
"
|
|
47
|
+
"추정예탁자산, 당일/당월/누적 투자손익을 조회합니다 (키움 kt00001 + kt00018 + kt00004). " +
|
|
48
|
+
"인자가 필요 없습니다.",
|
|
27
49
|
}, async () => runTool(async () => {
|
|
28
50
|
const { client, config } = getKiwoomContext();
|
|
29
51
|
// Different TRs — the per-TR rate limit allows these in parallel.
|
|
30
|
-
|
|
52
|
+
// kt00004 is best-effort: on failure only the 기간 손익 block is dropped.
|
|
53
|
+
const [deposit, evaluation, periodPl] = await Promise.all([
|
|
31
54
|
fetchDeposit(client),
|
|
32
55
|
fetchAccountEvaluation(client, "1"),
|
|
56
|
+
fetchAccountPeriodPl(client).catch((error) => {
|
|
57
|
+
console.error("kt00004 계좌평가현황 조회 실패 — 기간 손익 블록 생략:", error);
|
|
58
|
+
return null;
|
|
59
|
+
}),
|
|
33
60
|
]);
|
|
34
|
-
return textResult(formatBalance(deposit, evaluation, config.modeLabel));
|
|
61
|
+
return textResult(formatBalance(deposit, evaluation, config.modeLabel, periodPl));
|
|
35
62
|
}));
|
|
36
63
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kiwoom-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
|
+
"mcpName": "io.github.ChunSam/kiwoom-mcp-server",
|
|
4
5
|
"description": "Read-only MCP server exposing the Kiwoom Securities REST API (market data, account inquiry, ISA tax-allowance calculator) to Claude Desktop / Claude Code.",
|
|
5
6
|
"private": false,
|
|
6
7
|
"type": "module",
|