hamlog-mcp
# hamlog-mcp
Turbo HAMLOG のログを読むための MCP サーバ。**読み取り専用**。
交信データの登録・更新・削除にあたるツールは実装していません。HAMLOG の
`.hdb` を開くこともしません。自分のログを自然言語で検索・集計するためのものです。
---
## ログの取り込み方は 2 通り
### A. HAMLOG.HDB を直接読む (`import_from_hdb`)
`HAMLOG50.DLL` 経由で HDB を直接読みます。エクスポート操作が不要で、
常に最新のログが見えます。
HAMLOG50.DLL は 32 ビットですが、**MCP サーバ本体は 64 ビットのままで
かまいません**。DLL を触る部分だけを `hdb_dump.py` という子プロセスに
分離し、32 ビット Python で実行して JSON を受け取る構成です。
`hdb_dump.py` は **標準ライブラリしか使いません**。32 ビット側に pip で
何かを入れる必要はなく、32 ビット Python の実行ファイルがあるだけで動きます。
これは MCP SDK が `pyjwt[crypto]` 経由で `cryptography` を要求し、
cryptography には 32 ビット Windows 用の wheel が無いためです
(ソースビルドに落ちて Rust ツールチェーンが要る)。
安全のため、既定では HDB と MST を一時領域へ複製してから開きます
(`use_copy=True`)。`HamlogOpen` はインデックスファイルが無ければ生成するので、
原本のフォルダに副産物を作らせないためです。HAMLOG 起動中でも安全に読めます。
バインドしている DLL 関数は `HamlogOpen` / `HamlogClose` / `THW_read` /
`dbf_rcount` の 4 つだけです。`DB_append` `THW_append` `THW_update`
`QSL_Rcv` `QSL_Send` `THW_zap` といった書き込み系は意図的に未バインドで、
呼ぼうとしてもコード上存在しません。
### B. ADIF をエクスポートして読む (`import_log`)
64 ビット Python でも使え、HAMLOG が起動していなくても動きます。
DLL も不要です。手軽さならこちら。
どちらも同じ SQLite キャッシュに入るので、以降の検索・集計ツールは共通です。
### 32 ビット Python の指定
環境変数 `HAMLOG_PY32` に 32 ビット `python.exe` のフルパスを設定します。
仮想環境である必要はなく、インストールした本体を直接指定して構いません。
```
HAMLOG_PY32 = C:\\Users\\<user>\\AppData\\Local\\Programs\\Python\\Python313-32\\python.exe
```
子プロセスの単体確認もできます (DLL 不要):
```cmd
set PYTHONPATH=C:\hamlog-mcp
<32bit python.exe> -m hamlog_mcp.hdb_dump --self-test
```
### 構造体について
`TQsoBuff` の肝は `Hiss[764]` で、これは単なる HIS RST 欄ではなく
**可変長 8 項目 (Hiss/Myrs/Freq/Mode/Name/Qth/Rmk1/Rmk2) を連結した
バッファ**です。`*Myrs` 〜 `*Rmk2` のポインタはこの中を指します。
`HAMLOG50.H` のコメントにある各最大長 13/13/17/17/65/129/255/255 の合計が
ちょうど 764 で一致します。
**重要:** ヘッダのコメントにある 13/13/17/17/65/129/255/255 は各項目の
「最大長」であって、実際のフィールド長ではありません。実データでは
4/4/8/7/13/29/55/55 のように短いことがあり、データファイルの構造に依存します。
固定オフセットで実装すると全項目が壊れます。
本実装は決め打ちせず、`HamlogOpen` 後の実際のポインタ値からオフセットを
実測します (自己校正)。最終項目 (Rmk2) だけは後ろにポインタが無いため、
構造体の `Rmk2Len` で長さを決めます。実際に使われたレイアウトは
`import_from_hdb` の戻り値の `hiss_layout` で確認できます。`check_hdb_layout` で構造体サイズの自己診断ができます
(`sizeof(TQsoBuff)==857`, `sizeof(TThLog)==3927`)。
なお `long` は Win32 では 4 バイトなので、構造体では `c_long` ではなく
`c_int32` を使っています。ここを間違えると `TDBFh` が 8 バイトずれます。
---
## セットアップ
### 1. インストール
```bash
pip install -e .
# Windows で get_hamlog_input を使う場合のみ
pip install pywin32
```
MCP SDK は 2.x / 1.x のどちらでも動きます(`server.py` で吸収しています)。
### 2. HAMLOG からログを出す
HAMLOG のメニューから **ADIF 形式でエクスポート**します。
文字コードは UTF-8 でも Shift_JIS でも自動判別します。
CSV でも読めますが、列の並びがバージョンや出力設定で変わるため、
最初の 1 回は `search_qso` の結果を目で確認してください。
並びが違う場合は `import_log` の `csv_columns` に列名リストを渡します。
### 3. MCP クライアントに登録
Claude Desktop なら設定ファイルの `mcpServers` に、Claude Code なら
`claude mcp add` で、いずれも下記の内容を登録します。設定ファイルの正確な
場所と書式は公式ドキュメントを参照してください
(https://docs.claude.com/en/docs/claude-code/mcp)。
```json
{
"mcpServers": {
"hamlog": {
"command": "python",
"args": ["-m", "hamlog_mcp.server"],
"env": {
"HAMLOG_EXPORT": "C:\\\\Hamlog\\\\export.adi",
"HAMLOG_DB": "C:\\\\Hamlog\\\\hamlog-mcp.sqlite3",
"HAMLOG_HDB": "C:\\\\Hamlog\\\\HAMLOG.HDB",
"HAMLOG_DLL": "C:\\\\Hamlog\\\\HAMLOG50.DLL"
}
}
}
}
```
`HAMLOG_EXPORT` を設定しておくと、初回起動時に自動で取り込みます。
ログを更新したら `import_log` を呼び直してください。
ChatGPT デスクトップ、Cursor、VS Code などでも同じサーバがそのまま使えます。
MCP はクライアントを選びません。
---
## ツール
| ツール | 内容 |
|---|---|
| `db_info` | キャッシュの状態。交信数、日付範囲、使用バンド・モード |
| `import_log` | エクスポートファイルを読み込んでキャッシュを更新 |
| `search_qso` | コールサイン(ワイルドカード可)・バンド・モード・期間・JCC・QSL 状況で検索 |
| `qso_stats` | バンド/モード/年/月/時間帯/相手局/JCC/都府県/GL 別の集計 |
| `station_history` | 特定局との全交信履歴。初回・最終交信日、使ったバンドとモード |
| `award_progress` | 都府県 47 の取得済み・未取得。JCC と GL は取得済み一覧 |
| `get_hamlog_input` | 起動中 HAMLOG の入力ウィンドウを読む(Windows のみ、読み取りのみ) |
| `import_from_hdb` | HAMLOG.HDB を DLL 経由で直接読み込む(32 ビット Python) |
| `check_hdb_layout` | 読み込み経路の自己診断。DLL や HDB が無くても実行できる |
全ツールに MCP の `readOnlyHint` を付けてあるので、クライアント側で
「確認なしで呼んでよいツール」として扱われます。
### 聞き方の例
- 「今年 7MHz の CW で何局と交信した?」
- 「JA1ABC とは前にいつ交信した?」
- 「都府県アワードであと足りないのはどこ?」
- 「40m CW だけで見たときの都府県の進捗は?」
- 「一番よく交信している時間帯は?」
- 「QSL 未受領の交信を古い順に 20 件」
---
## 実装メモ
- SQLite 接続は **スレッドごとに持つ** (`threading.local`)。MCP サーバは
ツールをスレッドプールで実行するため、単一接続を使い回すと 2 回目以降の
呼び出しが別スレッドに乗った瞬間に
`ProgrammingError: SQLite objects created in a thread can only be used in
that same thread` になる。CLI から叩いている間は単一スレッドなので
露見しない。
- `journal_mode=WAL` と `busy_timeout=30000` を設定してある。
`cache.sqlite3-wal` / `-shm` が並んでできるのは正常。
## 注意
- `hour` 集計は交信時刻の「時」をそのまま使います。ログが JST か UTC かは
HAMLOG 側の設定に依存するので、解釈するときは確認してください。
- 都府県の判定は `hamlog_mcp/data/jcc_prefectures.json` の対応表によります。
この表は手で編集できます。誤りがあれば JARL の資料で確認して直してください。
対応表に無いコードは `unrecognized_codes` に出ます。
- **`import_from_hdb` を使うときは Turbo HAMLOG を終了してください。**
HAMLOG はデータファイルを排他モードで開くため、起動中は読み取り目的の
複製すらできず `WinError 32` になります。ADIF 経路 (`import_log`) には
この制約はありません。
- `get_hamlog_input` は HAMLOG Ver5.27c 以降が対象です。HAMLOG 本体と
本サーバを同じユーザー・同じ権限レベルで起動してください。片方だけ
管理者権限だと UIPI でメッセージが弾かれます。
## HAMLOG50.DLL の利用条件
`import_from_hdb` を使う場合、HAMLOG 付属の `HAMLOG50.DLL` を利用することに
なります。作者 JG1MOU 局が定める条件は「Turbo HAMLOG 用のツールを作成する
場合にのみ利用可」です。本ツールはこれに該当します。
DLL 自体は同梱していません。HAMLOG のインストール先にあるものを
`HAMLOG_DLL` で指定して使ってください。もし本ツールを再配布する場合は、
`Th527api.zip` 同梱の `Hamlog50.txt` と `Readme.txt` の条件を確認してください。
ADIF 経路 (`import_log`) だけを使うなら DLL は不要で、この条件もかかりません。
## ライセンス
本リポジトリのコードは [MIT License](LICENSE) で公開しています。
`HAMLOG50.DLL` は本リポジトリに含まれず、MIT License の対象外です。
DLL の利用には上記の条件が適用されます。
TDQS
Scored across 9 tools
Each tool has a distinct primary role: status, file import, HDB import, search, aggregate stats, station history, award progress, live input reading, and diagnostics. Slight overlap exists between search_qso and station_history when filtering by callsign, and between import_log and import_from_hdb, but the descriptions clearly distinguish their intended use cases.
All names use consistent snake_case and are readable, but the set mixes verb-led names (import_log, search_qso, get_hamlog_input) with noun-led names (db_info, qso_stats, station_history, award_progress). This is a minor deviation from a uniform verb_noun pattern, though the naming remains predictable overall.
Nine tools is well-scoped for a read/analysis server for amateur radio logs. Each tool earns its place, covering status, import, search, aggregation, history, awards, live input, and diagnostics without redundancy.
The surface covers the full read/import/analysis lifecycle: cache status, two import paths, flexible search, statistics, station history, award progress, live input reading, and a diagnostic tool. No direct update/delete operations exist, but that aligns with the read-only nature of the HAMLOG source. A minor gap is the lack of an explicit cache-clearing or individual record management tool, though replace options in import tools mitigate this.