#!/usr/bin/env python3
"""
互動式測試客戶端 - 記帳 MCP 工具
"""
import argparse
import asyncio
import json
import shlex
from typing import List, Optional
from accounting_mcp.tools import AccountingTools
def _print_result(result: dict) -> None:
print(json.dumps(result, ensure_ascii=False, indent=2))
async def _handle_add(tools: AccountingTools, args: argparse.Namespace) -> None:
result = await tools.add_transaction(
amount=args.amount,
category=args.category,
description=args.description or "",
date_str=args.date,
)
_print_result(result)
async def _handle_balance(tools: AccountingTools, args: argparse.Namespace) -> None:
result = await tools.get_balance(detailed=args.detailed)
_print_result(result)
async def _handle_list(tools: AccountingTools, args: argparse.Namespace) -> None:
result = await tools.list_transactions(
limit=args.limit,
offset=args.offset,
category=args.category,
start_date=args.start_date,
end_date=args.end_date,
)
_print_result(result)
async def _handle_summary(tools: AccountingTools, args: argparse.Namespace) -> None:
result = await tools.get_monthly_summary(year=args.year, month=args.month)
_print_result(result)
async def _handle_categories(tools: AccountingTools, _args: argparse.Namespace) -> None:
result = await tools.get_categories()
_print_result(result)
def _build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="記帳 MCP 測試客戶端")
subparsers = parser.add_subparsers(dest="command")
add_parser = subparsers.add_parser("add", help="新增交易")
add_parser.add_argument("amount", type=float, help="金額,正數為收入、負數為支出")
add_parser.add_argument("category", type=str, help="分類 ID")
add_parser.add_argument("description", nargs="?", default="", help="描述(可選)")
add_parser.add_argument("--date", dest="date", help="交易日期 YYYY-MM-DD(可選)")
add_parser.set_defaults(handler=_handle_add)
balance_parser = subparsers.add_parser("balance", help="取得餘額")
balance_parser.add_argument("--detailed", action="store_true", help="顯示月度統計")
balance_parser.set_defaults(handler=_handle_balance)
list_parser = subparsers.add_parser("list", help="列出交易")
list_parser.add_argument("limit", nargs="?", type=int, default=20, help="回傳筆數(預設 20)")
list_parser.add_argument("--offset", type=int, default=0, help="偏移量(預設 0)")
list_parser.add_argument("--category", type=str, help="分類篩選")
list_parser.add_argument("--start-date", dest="start_date", help="開始日期 YYYY-MM-DD")
list_parser.add_argument("--end-date", dest="end_date", help="結束日期 YYYY-MM-DD")
list_parser.set_defaults(handler=_handle_list)
summary_parser = subparsers.add_parser("summary", help="月度彙總")
summary_parser.add_argument("--year", type=int, help="年份(可選)")
summary_parser.add_argument("--month", type=int, help="月份(可選)")
summary_parser.set_defaults(handler=_handle_summary)
categories_parser = subparsers.add_parser("categories", help="分類清單")
categories_parser.set_defaults(handler=_handle_categories)
return parser
async def _run_command(tools: AccountingTools, argv: List[str]) -> None:
parser = _build_parser()
args = parser.parse_args(argv)
if not hasattr(args, "handler"):
parser.print_help()
return
await args.handler(tools, args)
async def _repl() -> None:
tools = AccountingTools()
print("記帳 MCP 測試客戶端,輸入 help 查看指令,輸入 exit 離開。")
while True:
try:
raw = input("> ").strip()
except (EOFError, KeyboardInterrupt):
print("\n已離開。")
return
if not raw:
continue
if raw in {"exit", "quit"}:
print("已離開。")
return
if raw == "help":
_build_parser().print_help()
continue
try:
argv = shlex.split(raw)
except ValueError as exc:
print(f"指令解析失敗: {exc}")
continue
try:
await _run_command(tools, argv)
except Exception as exc:
print(f"執行失敗: {exc}")
if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
asyncio.run(_run_command(AccountingTools(), sys.argv[1:]))
else:
asyncio.run(_repl())