multi-publisher-mcp
README.md
# multi-publisher-mcp
**One-Shot Multi-Platform Publishing (note / Zenn / Qiita / Dev.to / Medium / X), CJK Chart Generation, Excel/CSV Packaging & Analyst Knowledge Vault MCP Server Powered by DuckDB**
**データ分析結果から、たった1回のツール呼び出し(1秒以内)で「6媒体分の記事原稿 + 日本語グラフ画像(PNG)+ 販売用Excel/CSV + ローカルDuckDBへの知見・文体レシピ蓄積」を一括実行する汎用 MCP サーバー**
[](LICENSE)
[](https://modelcontextprotocol.io)
[](https://www.python.org/)
[](https://duckdb.org/)
[English](#english-documentation) | [日本語ドキュメント](#japanese-documentation)
---
<a name="english-documentation"></a>
## 🌍 English Documentation
### Why `multi-publisher-mcp`?
After discovering an exciting statistical correlation or anomaly using an AI agent or DuckDB query, turning that raw data into publication-ready assets across multiple platforms is tedious and error-prone:
1. **Platform Formatting Friction**: Each platform (`note`, `Zenn`, `Qiita`, `Dev.to`, `Medium`, `X / Twitter`) requires different frontmatter, heading structures, code explanations, and language adaptation.
2. **X (Twitter) Character Limit Failures**: LLMs frequently miscount character limits (140 Japanese characters / 280 English weighted characters).
3. **Garbled CJK Charts & CSVs**: Standard Matplotlib charts often render Japanese labels as blank boxes (`□□□`), and standard UTF-8 CSVs without BOM appear garbled when opened in Microsoft Excel on Windows.
4. **Ephemeral Insights**: Analytical findings and effective writing tones get lost across chat sessions unless stored in a structured local database.
**`multi-publisher-mcp`** solves all of these challenges in a single, unified MCP tool (`vault_and_publish`):
- **Sub-Second 8-Asset Generation (`action="publish_all"`)**: Produces 6 tailored markdown/text manuscripts (`01_note.md`, `02_zenn.md`, `03_qiita.md`, `04_devto.md`, `05_medium.md`, `06_x_threads.txt`), a high-resolution CJK-ready chart (`chart.png`), a `utf-8-sig` (UTF-8 with BOM) CSV (`dataset.csv`), and an auto-column-width formatted Excel workbook (`dataset.xlsx`) in **~0.15s – 0.35s**.
- **Local DuckDB Knowledge & Style Vault (`action="save_insight"` / `"search_insights"`)**: Persists hypotheses, SQL queries, extracted JSON records, and reusable writing style templates (`style_templates`) in a local DuckDB file (`VAULT_DB_PATH`).
- **Strict Python X/Twitter Thread Trimming**: Deterministically computes exact character counts and X weighted lengths (URL = 23 weight, CJK = 2 weight, ASCII = 1 weight) to guarantee **$\le 140$ chars for Japanese posts** and **$\le 280$ weight for English posts**.
- **Enterprise-Grade Sandboxing & Security**:
- Zero hardcoded local paths or secrets; configured entirely via environment variables (`VAULT_DB_PATH`, `PUBLISH_OUTPUT_DIR`, `AUTHOR_LINKS_JSON`).
- Strict filesystem sandboxing via `Path.resolve()` and `relative_to()` that rejects any path traversal (`../`) or outside absolute path, with **zero file-deletion capabilities**.
- Sanitizes control tokens and wraps external strings in `<untrusted_data>...</untrusted_data>` boundary tags to prevent prompt injection.
---
### ✨ Single Unified Tool: `vault_and_publish`
| Action | Purpose | Key Parameters | Output |
| :--- | :--- | :--- | :--- |
| **`"save_insight"`** | **Save Insight & Custom Style Recipe to DuckDB** | `title`, `insight_summary`, `hypothesis`, `sql_or_code`, `data_records`, `style_template` | Stores the insight and optional custom style recipe in `analyst_vault.duckdb` with `<untrusted_data>` boundary protection. |
| **`"search_insights"`** | **Search Stored Insights & Style Templates** | `query`, `tag`, `limit` | Returns matching historical insights, sample records, and all available built-in + custom writing styles. |
| **`"publish_all"`** | **One-Shot 6-Platform + Chart + Excel/CSV Export** | `title`, `insight_summary`, `data_records`, `dataset_source`, `dataset_period`, `dataset_record_count`, `chart_type`, `style_name` | Generates all 8 publication assets (9 files) inside a sandboxed subfolder under `PUBLISH_OUTPUT_DIR` in `<1.0s`. |
#### Generated Publication Package (`action="publish_all"`)
| File | Target Platform / Format | Key Specifications |
| :--- | :--- | :--- |
| **`01_note.md`** | **note (Japanese)** | TOC-ready `##`/`###` headings, `**bold**` highlights, empirical ranking table, explicit dataset provenance (source, period, record count), analyst tone, and attached Excel/CSV sales guide. |
| **`02_zenn.md`** | **Zenn (Japanese Tech)** | Zenn CLI frontmatter (`title`, `emoji`, `type: "tech"`, `topics`, `published`) + reproducible DuckDB SQL & Python MCP pipeline walkthrough. |
| **`03_qiita.md`** | **Qiita (Japanese Hands-On)** | 5 engineering tags (`Python`, `DuckDB`, `MCP`, `データ分析`, `オープンデータ`) + public data cleansing guide (`utf-8-sig`, canonical IDs) & hands-on code. |
| **`04_devto.md`** | **Dev.to (English Dev)** | Dev.to frontmatter + developer guide for integrating Local LLMs with MCP, DuckDB, RapidAPI, and Hugging Face Datasets. |
| **`05_medium.md`** | **Medium (English Business/Quant)** | Data storytelling brief for quantitative analysts & business leaders + empirical ranking table + API/Dataset links. |
| **`06_x_threads.txt`** | **X / Twitter (JP & EN Threads)** | 3-post Japanese thread (**strictly $\le 140$ chars**) + 3-post English thread (**strictly $\le 280$ X-weight**), with exact character/weight verification headers. |
| **`chart.png`** | **High-Res PNG Chart** | Auto-detects Japanese fonts (`Yu Gothic`, `Meiryo`, `MS Gothic`, `Hiragino Sans`, `Noto Sans CJK JP`); supports `bar`, `line`, and `scatter` (with linear regression trendline). |
| **`dataset.xlsx` & `dataset.csv`** | **Excel & BOM CSV Package** | `dataset.csv` encoded in `utf-8-sig` (zero Excel garbling on Windows) + `dataset.xlsx` with styled headers, auto-adjusted column widths, frozen top row, and a `Metadata` provenance sheet. |
---
### 🚀 Quick Start
#### 1. Installation
```bash
git clone https://github.com/japan-opendata-lab/multi-publisher-mcp.git
cd multi-publisher-mcp
pip install -e ".[dev]"
pytest -v
```
#### 2. Configure in LM Studio (`~/.lmstudio/mcp.json`) or Claude Desktop / Cursor
```json
{
"mcpServers": {
"multi-publisher-mcp": {
"command": "python",
"args": [
"-X",
"utf8",
"./oss_mcp/multi-publisher-mcp/server.py"
],
"env": {
"PYTHONIOENCODING": "utf-8",
"VAULT_DB_PATH": "./data/analyst_vault.duckdb",
"PUBLISH_OUTPUT_DIR": "./exports/publications"
}
}
}
}
```
---
### 🔗 Three-Server Synergy: `correlation-discovery-mcp` + `japan-data-mcp` + `multi-publisher-mcp`
When combined with the companion open-source MCP servers from **Japan Open Data Lab**, any local LLM (`Qwen3-8B`, `Llama-3`, etc.) or cloud agent becomes a complete end-to-end **Automated Data Journalism & Dataset Publishing Studio**:
1. **Step 1 — Discover (`correlation-discovery-mcp`)**:
Scan 160+ datasets in `<0.2s` using `discover_correlations(mode="find_drivers")` or `mode="pair"` to find strong Pearson correlations ($r$) and regression outliers (`residual_z_score > 3.0`).
- Repo: [`japan-opendata-lab/correlation-discovery-mcp`](https://github.com/japan-opendata-lab/correlation-discovery-mcp)
2. **Step 2 — Deep-Dive (`japan-data-mcp`)**:
Fetch normalized entity records across 162 Japanese & Global official datasets by `municipality_code` or `corporate_number`.
- Repo: [`japan-opendata-lab/japan-data-mcp`](https://github.com/japan-opendata-lab/japan-data-mcp)
- Cloud API: [Japan Official Data Megabank on RapidAPI](https://rapidapi.com/organization/japan-opendata-lab)
- Sample Parquet: [`japan-opendata-lab/japan-official-data-megabank`](https://huggingface.co/datasets/japan-opendata-lab/japan-official-data-megabank)
3. **Step 3 — Vault & Publish (`multi-publisher-mcp`)**:
Pass the discovered insight and extracted records to `vault_and_publish(action="publish_all")` to immediately generate all 6 platform articles, the Japanese PNG chart, and the commercial Excel/CSV package in `<1.0s`.
---
<a name="japanese-documentation"></a>
## 🇯🇵 日本語ドキュメント
### なぜ `multi-publisher-mcp` が必要なのか?
ローカルLLM(LM Studio 上の `Qwen3-8B` 等)や Claude Desktop / Cursor でデータ分析を行い、有益な相関やランキング・異常値を発見しても、それを実際のコンテンツや販売パッケージに仕上げるには多くの手作業が発生していました。
1. **媒体ごとのフォーマット変換コスト**: `note`、`Zenn`、`Qiita`、`Dev.to`、`Medium`、`X (旧Twitter)` では、求められる見出し構造・Frontmatter・コード解説の深さ・言語(日英)がすべて異なります。
2. **LLMによるX(Twitter)文字数制限の超過**: LLM自身に「140字以内で書いて」と指示しても、文字数カウントが不正確で140字を超えるケースが頻発します。
3. **日本語グラフの豆腐化(文字化け)とWindows ExcelのCSV文字化け**: Matplotlibのデフォルト設定では日本語ラベルが `□□□` に化け、BOMなしUTF-8のCSVはWindows版Excelで開くと文字化けします。
4. **分析知見と文体レシピの散逸**: チャットセッションが終わると、せっかく見つけた仮説や反応の良かった記事構成が消えてしまいます。
**`multi-publisher-mcp`** は、これらすべての工程を **単一の統合ツール `vault_and_publish`(実行時間 0.15〜0.35秒)** に凝縮したオープンソースの MCP サーバーです。
---
### 4大特徴
1. **1回のツール呼び出し・1秒以内で「8種の成果物(実ファイル9個)」を一括生成 (`action="publish_all"`)**
- `01_note.md`: `##` / `###` 目次対応見出し、`**太字**`、ランキング表、**実データの収録期間・レコード件数・公的出典の明記**、AIコピペ感を排した誠実なアナリスト調、末尾に添付Excel/CSVの販売案内を収録。
- `02_zenn.md`: Zenn用Frontmatter(`title`, `emoji`, `type: "tech"`, `topics`, `published`)+ DuckDB SQL / Python MCP 実装解説。
- `03_qiita.md`: エンジニア向け5タグ(`Python`, `DuckDB`, `MCP`, `データ分析`, `オープンデータ`)+ 公的データクレンジング&ハンズオン記事。
- `04_devto.md`(英語): Dev.to用Frontmatter + 海外AI開発者向け RapidAPI / Hugging Face / MCP 実装ガイド。
- `05_medium.md`(英語): 英語圏ビジネス・クオンツ層向けのデータストーリー記事 + 統計テーブル + RapidAPI導線。
- `06_x_threads.txt`: Python側で **「日本語140字以内(かつ280ウェイト以内)」「英語280字以内(かつ280ウェイト以内)」** を厳密にカウント・自動トリミングした日英3連スレッド原稿。
- `chart.png`: 日本語フォント(`Yu Gothic` / `Meiryo` / `MS Gothic` / `Hiragino Sans` / `Noto Sans CJK JP`)を自動検出し、`bar`(横棒ランキング)、`line`(折れ線推移)、`scatter`(散布図+最小二乗回帰トレンドライン)を高解像度出力。
- `dataset.xlsx` & `dataset.csv`: Windows Excelで文字化けしない `utf-8-sig`(BOM付き)CSVと、全角・半角幅を計算して列幅自動調整・ヘッダー固定・オートフィルタ・`Metadata` シートを付与した即戦力Excelファイル。
2. **3大内蔵文体スタイル + カスタム文体レシピ登録 (`style_name` / `style_template`)**
- 初期内蔵の3スタイル(**「常識逆転ランキング調」「投資・ビジネス深掘り調」「データセット直販カタログ調」**)を引数1つで切り替え可能。
- さらに `action="save_insight"` で独自の文体レシピ(`style_template`)をローカルDuckDBに登録し、次回以降の `publish_all` で呼び出すことができます。
3. **ローカル DuckDB による「知見メモ・仮説・SQL・抽出データ」の永続蓄積**
- 分析で得た気づきや仮説を `VAULT_DB_PATH`(デフォルト `./data/analyst_vault.duckdb`)に自動蓄積し、`action="search_insights"` でいつでもキーワード・タグ検索できます。
4. **厳格なセキュリティ&サンドボックス設計**
- ローカルの絶対パスやAPIキーのハードコードは完全ゼロ(すべて環境変数 `VAULT_DB_PATH`, `PUBLISH_OUTPUT_DIR`, `AUTHOR_LINKS_JSON` または相対パスで注入)。
- ファイル出力先は `Path.resolve()` と `relative_to()` により `PUBLISH_OUTPUT_DIR` 配下のみに厳密制限し、パストラバーサル(`../`)や絶対パス指定による外部書き出しを完全拒否。既存ファイルの削除機能は一切持ちません。
- 外部入力テキストは制御トークンを除去し、`<untrusted_data>...</untrusted_data>` データ境界タグでプロンプトインジェクションを無害化します。
---
### 🛠 セットアップと LM Studio / Claude Desktop 登録方法
#### 1. インストールと単体テストの実行
```bash
git clone https://github.com/japan-opendata-lab/multi-publisher-mcp.git
cd multi-publisher-mcp
pip install -e ".[dev]"
pytest -v
```
#### 2. 環境変数一覧
| 環境変数名 | デフォルト値 | 説明 |
| :--- | :--- | :--- |
| `VAULT_DB_PATH` | `./data/analyst_vault.duckdb` | 知見メモ・カスタム文体レシピを保存するローカルDuckDBファイルパス |
| `PUBLISH_OUTPUT_DIR` | `./exports/publications` | 記事・グラフ・Excel/CSVの出力先ルートディレクトリ(サンドボックス境界) |
| `AUTHOR_LINKS_JSON` | *(公開デフォルトURL群)* | 記事末尾やXスレッドに挿入するリンク設定(JSONオブジェクト文字列) |
#### 3. LM Studio (`~/.lmstudio/mcp.json`) への登録例
`japan-data-mcp` および `correlation-discovery-mcp` と並べて登録することで、**「データ検索 → 0.2秒相関・外れ値発掘 → 6媒体+グラフ+Excel一括出版」** の完全自動パイプラインが完成します。
```json
{
"mcpServers": {
"correlation-discovery-mcp": {
"command": "python",
"args": ["-X", "utf8", "./oss_mcp/correlation-discovery-mcp/server.py"],
"env": {
"PYTHONIOENCODING": "utf-8",
"DATA_SOURCE_DIR": "./data/platform_dist/global_megabank.duckdb;./data/dist"
}
},
"multi-publisher-mcp": {
"command": "python",
"args": ["-X", "utf8", "./oss_mcp/multi-publisher-mcp/server.py"],
"env": {
"PYTHONIOENCODING": "utf-8",
"VAULT_DB_PATH": "./data/analyst_vault.duckdb",
"PUBLISH_OUTPUT_DIR": "./exports/publications"
}
}
}
}
```
---
### 📊 ツール呼び出し例 (`vault_and_publish`)
#### 1. 一括パブリッシュ (`action="publish_all"`)
```json
{
"action": "publish_all",
"title": "全国市区町村の課税所得と公示地価の乖離ランキング検証",
"insight_summary": "課税所得と公示地価は強い正の相関(r=0.7105)を示す一方、商業集積地では所得トレンドを大きく上回るプラス乖離が確認された。",
"hypothesis": "昼間流入人口と商業地需要が住宅地ベースの所得水準以上の地価プレミアムを形成している。",
"dataset_source": "総務省 統計局 / 国土交通省 地価公示(標準化オープンデータ)",
"dataset_period": "2020年〜2026年(過去7年間)",
"dataset_record_count": "1,354自治体(全1,741市区町村中)",
"chart_type": "scatter",
"style_name": "常識逆転ランキング調",
"sql_or_code": "SELECT label, income_jpy, land_price_jpy FROM municipality_metrics ORDER BY land_price_jpy DESC LIMIT 10;",
"data_records": [
{ "label": "東京都千代田区", "income_jpy": 10065653, "land_price_jpy": 5495833 },
{ "label": "東京都中央区", "income_jpy": 7598445, "land_price_jpy": 5178378 },
{ "label": "東京都港区", "income_jpy": 11520000, "land_price_jpy": 4890000 }
]
}
```
#### 2. 知見・カスタム文体レシピの保存 (`action="save_insight"`)
```json
{
"action": "save_insight",
"title": "地方中核都市における製造業出荷額と夜間人口あたり税収の相関メモ",
"insight_summary": "人口規模で正規化(Per Capita)すると、単純総額とは異なる高収益自治体が上位に浮上する。",
"tags": ["自治体財政", "製造業", "PerCapita"],
"style_template": {
"style_name": "自治体政策提言調",
"display_name_ja": "自治体政策・EBPM提言調",
"tone_description": "自治体職員・政策立案者向けに、EBPM(証拠に基づく政策立案)の観点から統計データを解説するトーン。"
}
}
```
#### 3. 蓄積した知見・文体一覧の検索 (`action="search_insights"`)
```json
{
"action": "search_insights",
"query": "自治体財政"
}
```
---
### 🌐 関連エコシステム(Japan Open Data Lab)
- **[`correlation-discovery-mcp`](https://github.com/japan-opendata-lab/correlation-discovery-mcp)**: あらゆる DuckDB / Parquet / CSV から相関係数 ($r$値)・要因ランキング・回帰外れ値を0.2秒で算出する統計探索 MCP サーバー
- **[`japan-data-mcp`](https://github.com/japan-opendata-lab/japan-data-mcp)**: 日本の公的オープンデータ(全162データセット・1,150万件超)を自然言語・標準フィルタ・SQLで検索できる公式 MCP サーバー
- **[`japan-official-data-megabank`](https://github.com/japan-opendata-lab/japan-official-data-megabank)**: 公式 Python SDK & スターターキット
- **[RapidAPI Hub — Japan Open Data Lab](https://rapidapi.com/organization/japan-opendata-lab)**: クラウド API サブスクリプション(無料 BASIC プランあり)
- **[Hugging Face Datasets](https://huggingface.co/datasets/japan-opendata-lab/japan-official-data-megabank)**: サンプル Parquet データセット公開ページ
---
## License
MIT License — Copyright (c) 2026 Japan Open Data Lab (`japan.opendata.lab@gmail.com`)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues