O2n
FreeNot checkedObsidian の vault を、リンク・フォルダ階層・frontmatter・添付ファイルを保ったまま Notion へ移行するツール(CLI / MCP サーバー)
About
Obsidian の vault を、リンク・フォルダ階層・frontmatter・添付ファイルを保ったまま Notion へ移行するツール(CLI / MCP サーバー)
README
🤔 なぜ o2n?
Notion の標準インポートは Obsidian 特有の書き方を解釈しないため、大きな vault ほど手直しが現実的でなくなります。o2n は vault 全体を解析してから Notion のデータ構造に変換します。
| Obsidian の記法 | 標準インポート | o2n |
|---|---|---|
[[ノート]] wikilink |
❌ 文字列のまま | ✅ ページ間リンク(同名ノート・aliases も解決) |
![[画像.png]] 添付 |
❌ 表示されない | ✅ アップロードして元の位置に表示 |
| frontmatter | ❌ 生テキスト | ✅ メタ情報 or データベースのプロパティ |
icon / cover |
❌ | ✅ ページのアイコン・カバー |
> [!note] callout |
❌ ただの引用 | ✅ 全 13 種別を色・アイコン付きで再現、折りたたみはトグルに |
==ハイライト== |
❌ | ✅ 色付きハイライト(Obsidian 1.14 対応) |
| フォルダ階層 | ⚠️ 崩れがち | ✅ ページ階層として再現 |
| 途中で失敗 | 🔁 最初から | ✅ resume で続きから(二重作成しない) |
| 変換できなかったもの | 🤫 黙って欠落 | ✅ レポートに一覧 |
🚀 3 分で始める
必要なもの: Node.js 22.13 以上・Notion のトークン・Obsidian の vault(プラグイン・MCP サーバーから使う場合は .obsidian フォルダのある vault に限ります)
以下の手順は npx で実行します。npm i -g @tk_wfl/o2n-cli でインストールすると、npx @tk_wfl/o2n-cli の代わりに o2n と打つだけで使えます(このページの o2n … はこの意味です)。
1. Notion のトークンを用意する
Notion 開発者ポータル → Personal access tokens で New token → 名前・有効期限を選んで作成し、表示されたトークンを控えます(作成時にしか表示されません)。
export NOTION_TOKEN=ntn_xxx
# または一度だけ保存(プロンプトに貼り付け。以降は設定不要)
npx @tk_wfl/o2n-cli login --token
💡 個人アクセストークン(PAT) なら、移行先ページを integration に接続する手順が不要で、Free プランのブロック上限(後述)の対象外です。他の方法は Notion との連携方法 を参照。
2. 計画を作る
npx @tk_wfl/o2n-cli plan <vaultのパス> --parent <移行先 Notion ページの ID>
移行先ページの ID は、Notion でそのページの「リンクをコピー」をしたときの URL の末尾にある 32 桁の英数字です。
フォルダごとに「ページ階層」か「データベース」かを対話で選べます(frontmatter が揃っているフォルダは自動でデータベース化を提案)。
3. 試してから、移行する
npx @tk_wfl/o2n-cli migrate <vaultのパス> --dry-run # 書き込まずにシミュレーション
npx @tk_wfl/o2n-cli migrate <vaultのパス> # 本番
npx @tk_wfl/o2n-cli verify <vaultのパス> --deep # Notion の実ページと照合
途中で止まっても npx @tk_wfl/o2n-cli resume <vaultのパス> で続きから再開できます。
🧑💻 コマンドが苦手な方へ: Claude のプラグイン(Claude Code / Cowork)か MCP サーバーとして使うと、「この vault を Notion に移行して」と話しかけるだけで進められます → MCP サーバーとして使う
📖 コマンド一覧
| コマンド | 役割 | 主なオプション |
|---|---|---|
scan <vault> |
vault を走査して件数・推定ブロック数を表示(Notion にはアクセスしない) | --verbose --json |
plan <vault> |
移行計画(.o2n/plan.json)を対話で作成 |
--parent <id> --yes --embed-mode inline --link-style link --no-inline-fields --out <path> |
migrate <vault> |
計画に従って移行 | --dry-run --plan <path> --parent <id> --quiet --verbose |
resume <vault> |
中断・失敗した移行を続きから再開(冪等) | --quiet --verbose |
verify <vault> |
state と vault の突き合わせ。--deep で Notion の実ページとも照合 |
--deep --json |
report <vault> |
最新のレポート(.o2n/report.md)を表示 |
|
login --token |
Notion のトークンを保存(入力は表示されない) | |
logout |
保存したトークンを削除し、Notion との連携を解除 | |
whoami |
連携中の Notion ワークスペースを表示 | |
mcp allow <vault> / mcp disallow <vault> |
MCP サーバー(プラグイン)が読んでよい vault を保存・取り消し | |
mcp write on / mcp write off |
MCP サーバーからの Notion への書き込みと確認フレーズを保存・解除 | |
mcp status |
保存された MCP の設定と、実際に使われる設定を表示 |
- 移行後にノートを別フォルダへ移動・改名しても、
resumeで検知して Notion 上の同じページを移動・改名します(内容も同時に変えた場合は新しいページとして作成) migrate --dry-runのレポートは.o2n/report.dry-run.mdに書かれ、本番のreport.mdを上書きしません--embed-mode inline:![[ノート]]の埋め込みを、リンクではなく本文にその場で展開します(![[ノート#見出し]]はそのセクションのみ)- 終了コード:
0全件成功 /1一部失敗・不一致あり /2致命的エラー
🔑 Notion との連携方法
トークンの渡し方は2通りです。どちらもコマンドライン引数では受け取りません(シェル履歴への漏洩防止)。
- 環境変数
NOTION_TOKENに設定する o2n login --tokenで保存する:プロンプトに貼り付ける(入力は表示されません)か、標準入力で渡します。Notion に接続して有効なことを確かめてから~/.o2n/credentials.json(パーミッション 600)に保存し、以降は CLI と MCP サーバーが自動で使います。解除はo2n logout
npx @tk_wfl/o2n-cli login --token
両方ある場合は NOTION_TOKEN が優先されます(空文字なら未設定扱い)。
方法 A: 個人アクセストークン(PAT)— 推奨
開発者ポータル「Personal access tokens」 で New token → 名前・権限(Notion API)・有効期限(7 日〜1 年)を選んで作成。
- 作成した本人がアクセスできるページにそのまま書き込めるため、ページごとに integration を接続する手順が不要
- 有効期限付きで、ワークスペース管理者が一覧・失効できる
- Notion Free プランのブロック上限の対象外
- 2026 年 5 月に追加された機能。古いワークスペース設定では「Connections」タブから辿れる
方法 B: internal integration のトークン
ワークスペース単位で動く integration を作り、そのトークン(同じ ntn_ 形式)を設定します。
移行先の親ページを事前にその integration に 接続(Connect) しておく必要があります(ページ右上の … → 「接続先」)。未接続のページを指定すると plan / migrate 時に 404 Could not find page になります。
方法 C: ブラウザでログイン(既定停止中)
npx @tk_wfl/o2n-cli login
旧 OAuth poll 方式にトークン窃取リスクが見つかったため、既定で停止しています。検証目的で新しい loopback handoff 方式を使う場合のみ O2N_ENABLE_BROWSER_LOGIN=1 を明示してください。旧バージョンで o2n login を利用した場合は、Notion 側で該当トークンを失効・再発行することを推奨します。仕組みは「セキュリティ」節の折りたたみを参照。
🤖 MCP サーバーとして使う
Claude のプラグインとして使う(Claude Code / Cowork)
plugin/ は Claude のプラグインです。MCP サーバーの起動設定が入っており、トークンなどは有効化したときに表示される設定画面で入力します。このリポジトリはプラグインのマーケットプレイスにもなっているので、GitHub のリポジトリ名 TK-WFL/o2n を指定して追加できます。
Claude Code では次を実行します。
/plugin marketplace add TK-WFL/o2n
/plugin install o2n@o2n
手元で変更を試すときは、clone したフォルダを直接読み込めます。
git clone https://github.com/TK-WFL/o2n.git
claude --plugin-dir ./o2n/plugin
Cowork では、プラグインの追加画面でマーケットプレイスとして TK-WFL/o2n を追加し、表示される o2n をインストールします。そのあと、下の「Cowork で使う場合」の設定を保存します。
| 設定 | 内容 |
|---|---|
| Allowed vault paths | 読んでよい vault の絶対パス(カンマ区切り)。これ以外は拒否 |
| Notion token | 個人アクセストークン推奨。OS の安全な保管場所に入る。空なら o2n login --token で保存したものを使う |
| Allow writing to Notion | 既定オフ。オフの間は走査・計画の確認・dry-run のみ。計画の変更と本実行には、書き込み許可と確認フレーズが必要 |
| Confirmation phrase | 16 文字以上。本実行はこの文字列を Claude が渡したときだけ始まる |
| Notion requests per second | 1〜10(既定 2) |
プラグインが動くのは、ローカルの MCP サーバーを起動できる Claude Code と Cowork です。claude.ai のチャットはローカルの MCP サーバーを起動しません。
Cowork で使う場合は設定画面が出ないので、先にターミナルで次を実行して設定を保存します。プラグインの設定が空のときは、MCP サーバーがこの保存内容を使います。
npx @tk_wfl/o2n-cli login --token # Notion のトークン
npx @tk_wfl/o2n-cli mcp allow <vaultのパス> # 読んでよい vault
npx @tk_wfl/o2n-cli mcp write on # 本実行したいとき。確認フレーズを設定
mcp allow と mcp write on はターミナルで直接実行したときだけ受け付けます(Claude がツール経由で自分に権限を与えられないようにするため)。保存先は ~/.o2n/mcp-settings.json(パーミッション 600)です。何を読み・書き・送るかは plugin/README.md にまとめています。
MCP 設定に直接登録する
Claude Desktop / Claude Code の MCP 設定に npx -y @tk_wfl/o2n-mcp-server を登録します。
{
"mcpServers": {
"o2n": {
"command": "npx",
"args": ["-y", "@tk_wfl/o2n-mcp-server"],
"env": {
"NOTION_TOKEN": "ntn_xxx",
"O2N_ALLOWED_VAULTS": "/absolute/path/to/vault"
}
}
}
}
| ツール | 役割 |
|---|---|
scan_vault |
vault を走査(読み取りのみ) |
get_plan / update_plan |
計画の確認・調整(parentPageId / folders / skipList / embedMode / linkStyle / inlineFields)。調整には書き込み許可と確認フレーズが必要 |
prepare_migration |
移行内容(対象・移行先・件数)を固定して requestId を返す |
commit_migration |
固定した内容を実行。本実行には確認フレーズ(引数 confirmationToken)が必須 |
resume_migration / cancel_migration |
続きから再開 / ノート境界で中断 |
migration_status / verify_migration / get_report |
進捗・検証・レポート |
🔒 安全設計: 許可した vault(O2N_ALLOWED_VAULTS または o2n mcp allow)以外へはアクセスできません。Notion への本実行は既定で無効です。書き込み許可(O2N_ENABLE_MCP_WRITE=1、true も可。または o2n mcp write on)と確認フレーズ(O2N_MCP_WRITE_TOKEN または o2n mcp write on で設定)を用意し、commit_migration にそのフレーズを渡す必要があります。環境変数に値があれば環境変数が優先されます。失敗・拒否の応答は isError 付きで返ります。
🔄 変換される内容
対応表を開く
| Obsidian | Notion での扱い |
|---|---|
[[ノート]] |
ページメンション(Notion のバックリンクに現れ、改名にも追従)。plan --link-style link で URL リンク |
[[ノート|表示名]]、aliases 経由の [[別名]] |
書いた表示名のままの URL リンク(大文字小文字非依存で解決) |
[[ノート#見出し]] [[#見出し]] [x](note.md#見出し) |
その見出しへのリンク(見出しが無ければページ先頭にして報告) |
[[ノート#^id]] |
ページ先頭へのリンク(Notion にブロック参照が無いため。レポートに記録) |
![[ノート]] ![[ノート#見出し]] |
既定はリンク。--embed-mode inline で本文を展開(循環・深さ 3 以上はリンク) |
![[画像.png|300]]  [資料](a.pdf) [[表.xlsx]] |
アップロードして元の位置に画像 / PDF / 音声 / 動画 / ファイルブロック。docx・xlsx・pptx・zip・csv など任意の形式に対応(Notion が受け付けない形式はレポートに記録) |
[テキスト](note.md#見出し) |
wikilink と同じ解決(.MD も可) |
| frontmatter | page_tree: 冒頭のメタ callout / database: プロパティ(title・rich_text・number・checkbox・date・multi_select・url) |
icon cover banner |
ページのアイコン(絵文字・URL・vault 内画像)・カバー(URL・vault 内画像) |
tags(配列 / a, b) |
multi_select |
Dataview の key:: value [key:: value] |
database モードではプロパティにする(frontmatter が優先。plan --no-inline-fields で無効) |
> [!type] callout |
全 13 種別+別名を色・アイコンに対応。[!type]- はトグル。コードブロックやネストも保持 |
==text== ==🔴text== |
ハイライト(色付きは色を反映) |
- [ ] - [x] |
To-do。[/] [-] 等は未完了に正規化し元記号を本文に残す |
# 〜 #### |
見出し(h5/h6 は h4 に降格しレポートに記録) |
数式 $…$ $$…$$、mermaid |
そのまま保持 |
%% コメント %% <!-- コメント --> |
削除(コードブロックをまたぐものも) |
[^1] 脚注、^[インライン脚注] |
文中に展開 |
行末のブロック ID ^abc123 |
取り除く(Obsidian でも非表示のため) |
| インラインコード・コードブロック | 中身は変換しない |
| Excalidraw ノート | 同名の書き出し画像(.png / .svg)があれば画像として移行、無ければスキップ |
.canvas .base、Dataview の実行結果 |
非対応(レポートに記録) |
フォルダ直下のノートの 60% 以上が共通の frontmatter キーを 3 つ以上持つ場合、そのフォルダの データベース化を自動提案します(最終判断は plan で行います)。
⏱ 所要時間と制限
- 目安: 1,000 ノート+500 添付 ≒ API 呼び出し 4,000〜5,000 回 ≒ 約 30〜40 分(既定 2 req/秒)
- Business プラン以上なら
O2N_REQUESTS_PER_SECOND=8(1〜10)で短縮できます。ノートは同じ数だけ並行に処理されます(ページの並び順は保たれます)。429 はRetry-Afterに従って自動で待ちます - Notion Free プランのブロック上限(2026 年 9 月〜): 複数メンバーの Free ワークスペースは生涯 1,000 ブロックが API にも適用されます(公式リファレンス)。
scan/planが推定ブロック数で事前警告し、上限に達した場合は即座に中断してresumeで再開できます。PAT・有料プラン・メンバー 1 人の Free は対象外です
🛡 セキュリティ
- トークンは環境変数
NOTION_TOKENか~/.o2n/credentials.json(パーミッション 600、o2n login --tokenで作成)にのみ保存。MCP の許可 vault・確認フレーズの保存先~/.o2n/mcp-settings.jsonも同じ保護 - vault 本体は 常に読み取り専用。書き込むのは
.o2n/ディレクトリのみ - frontmatter は YAML のみ受け付け、
---js/---jsonなどはそのノートだけを安全にスキップ - vault 内のシンボリックリンクは辿らない。
.o2n/と~/.o2n/は symlink / hardlink / TOCTOU 攻撃を防ぐ形で読み書き .o2n/state.jsonは vault・計画・Notion ワークスペースに署名で結合され、取り違えを検知- 悪意のある vault で処理をハングさせる ReDoS への対策済み
- Notion API 以外への通信なし(テレメトリなし)。npm パッケージは Trusted Publishing(OIDC)で provenance 付きで公開
- 何を読み・送り・保存するか、その消し方は プライバシーポリシー にまとめています
- 脆弱性を見つけた場合は、公開の Issue ではなく SECURITY.md の手順(非公開の Security Advisory)で報告してください
o2n login(OAuth 連携)の仕組みと信頼モデル
- Notion の OAuth(public integration)は
client_secretが必須なため CLI に埋め込めません。代わりにservices/auth-proxy(Cloudflare Worker)がclient_secretを保持し、認可コード → トークンの交換だけを代行します - 新方式では CLI が
127.0.0.1の一時 HTTP リスナーを開き、Worker は交換後に短寿命の handoff code だけを loopback へ返します。CLI はセッション秘密値と handoff code を Worker へ POST し、一度だけトークンを受け取って~/.o2n/credentials.jsonに保存します client_secretは CLI・MCP サーバー・このリポジトリのどこにも含まれません(Worker 環境変数のみ)。Worker は vault や Notion ページの内容にはアクセスしません- 再有効化する場合、Worker 運用者(TK-WFL または自己ホスト)を信頼する必要があります。
NOTION_TOKENを使う方法はこの信頼モデルに依存しません。デプロイ手順は services/auth-proxy/README.md
🧑🔧 開発
npm install
npm run build
npm test
packages/
core/ # scanner / planner / converter / migrator / state / notion / report
cli/ # o2n コマンド(core の薄いラッパー)
mcp-server/ # stdio MCP サーバー(core の薄いラッパー)
plugin/ # Claude のプラグイン(MCP サーバーの起動設定と設定項目)
services/
auth-proxy/ # `o2n login` 用の OAuth コード交換代理(Cloudflare Worker)
fixtures/test-vault/ # 全構文網羅のテスト用 vault
scripts/verify-release.mjs # npm 公開前の内容・チェックサム検証
docs/
e2e.md # 手動 E2E 手順書
questions.md # 実装判断と実ワークスペースでの検証記録
spec.md # セキュリティ境界・永続化データの仕様
不具合報告・要望は Issues へ。変換がうまくいかない記法があれば、その断片を添えてもらえると助かります。
MIT License · TK-WFL
Installing O2n
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/TK-WFL/o2nFAQ
Is O2n MCP free?
Yes, O2n MCP is free — one-click install via Unyly at no cost.
Does O2n need an API key?
No, O2n runs without API keys or environment variables.
Is O2n hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install O2n in Claude Desktop, Claude Code or Cursor?
Open O2n on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectServer Sequential Thinking
MCP server for sequential thinking and problem solving
by GitHub ActionsUnyly Deploy
Deploy sites and MCP servers to Unyly straight from your AI agent
by UnylyAmap Maps Mcp Server
MCP server for using the AMap Maps API
by duxiaohuiPayMCP
Lightweight payments layer for MCP servers: turn tools into paid endpoints with a two-line decorator. [PyPI](https://pypi.org/project/paymcp/) · [npm](https://w
by blustAIServer For Power BI
Enables exploring Microsoft Fabric / Power BI workspaces and semantic models, and executing ad-hoc DAX queries.
by Mitsubishi-FusoGpt Image 2 Mcp
RunAPI GPT Image 2 MCP server for image generation: create tasks, poll results, and check pricing across 1 model from Claude Code, Codex, Cursor, and VS Code.
by runapi-aiCompare O2n with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
