Skip to main content
Glama
Yatty1
by Yatty1

mynote-mcp

Obsidian の vault にノートを読み書きするための、ローカル専用 MCP サーバです。

どのディレクトリで開いた Claude Code / Codex セッションからでも、同じ vault にノートを残せる ことを目的にしています。ノートはフォルダで分類せず、すべて vault ルート直下に <prefix> YYYY-MM-DD HHmm.md という名前で作られ、分類はタグ (YAML frontmatter の tags) で行います。

走査範囲は vault ルート直下のみです。 create_note はフォルダを作らず、search_notes / list_tags / read_note も ルート直下の *.md しか見ません。既存のサブフォルダに入っているノートは検索対象外です。

  • ランタイムは Bun。TypeScript を直接実行するのでビルド不要

  • MCP SDK の McpServer + WebStandardStreamableHTTPServerTransport (Web 標準の Request/Response で完結)

  • HTTP 本体は Hono + Bun.serve

  • 依存は @modelcontextprotocol/sdk / hono / zod のみ

  • テストは bun test (アサーションは node:assert/strict)

  • bun build --compile単一バイナリにできる (常駐用)

Node.js でも動きます

サーバ本体 (buildHttpApp) は Web 標準 API のみに依存しているため、ランタイムを選びません。 Bun.serve を使うのは listen 部分だけで、Node では @hono/node-server (optionalDependencies) へ自動的に切り替わります。

ただしテストは bun test に移行済みで Node では走りません。 Node 経路が壊れていないことは bun run test:node (scripts/node-smoke.sh) が 実際の Node プロセスで serve / stdio を叩いて確認します。

なぜ HTTP 常駐 + stdio ブリッジなのか

MCP サーバを stdio で登録すると、クライアントはセッションごとにプロセスを起動します。 それでも動きますが、次の点で困ります。

  • vault パスなどの設定を、セッションを開くディレクトリごとに用意したくない

  • ノート件数の走査やタグ集計を、セッション起動のたびに一から行いたくない

  • 「今どのプロセスが vault を触っているのか」を 1 つに寄せたい

そこで vault を触る本体は HTTP で 1 プロセスだけ常駐 させ (mynote-mcp serve)、 クライアントはそこへ接続する構成にしています。

  • Claude Code: HTTP トランスポートを直接サポートするので、常駐先の URL を登録するだけです。

  • Codex CLI: stdio しか扱えないため、mynote-mcp stdio を薄いブリッジとして挟みます。 ブリッジは initialize / tools/list / tools/call を常駐プロセスへ透過するだけで、 vault には触りません。

常駐プロセスが落ちていた場合、mynote-mcp stdioin-process モードへ自動フォールバック します (ブリッジ自身が同じツール群を組み立てて直接 vault を触る)。 そのため serve を起動し忘れていても、Codex 側は動作します。

Claude Code ──── HTTP ───────────────┐
                                     ├─→ mynote-mcp serve ──→ Obsidian vault
Codex CLI ──stdio──→ mynote-mcp stdio┘   (127.0.0.1:7391)
                          └─ 接続不可なら in-process で直接 vault を触る

Related MCP server: Vault MCP Server

セットアップ

Bun 1.2 以降が必要です (curl -fsSL https://bun.sh/install | bash)。

git clone <this repo> mynote-mcp
cd mynote-mcp
bun install
cp .env.example .env   # MYNOTE_VAULT_PATH を自分の vault に書き換える

ビルド手順はありません。Bun が src/index.ts を直接実行します。

.env の最低限の内容です。iCloud 上の Obsidian vault はパスにスペースを含むので、 必ずクォートしてください。

MYNOTE_VAULT_PATH="$HOME/Library/Mobile Documents/iCloud~md~obsidian/Documents/MyVault"

動作確認します。

bun start              # = bun src/index.ts serve
curl http://127.0.0.1:7391/health
# {"ok":true,"vault":"MyVault","notes":123}

開発中は bun run dev (bun --watch src/index.ts serve) が使えます。

単一バイナリを作る (常駐向け・任意)

bun run compile        # → dist/mynote-mcp (約 60MB, Bun ランタイム同梱)

node_modules も Bun 本体も不要な自己完結バイナリになります。 launchd / systemd から起動する場合、PATH やランタイムのバージョンに左右されないので確実です。 生成後は一度手で動作確認してください。

./dist/mynote-mcp serve

インストール構成の例 (常駐 + PATH)

開発用チェックアウトと、常駐させる実体を分けておくと運用が楽です。

git clone git@github.com:Yatty1/mynote-mcp.git ~/.local/share/mynote-mcp
cd ~/.local/share/mynote-mcp
bun install
bun run compile                                    # → dist/mynote-mcp
ln -sf ~/.local/share/mynote-mcp/dist/mynote-mcp ~/.local/bin/mynote-mcp
cp .env.example .env                               # MYNOTE_VAULT_PATH を設定

.envdist/mynote-mcp の 1 つ上 (= インストールルート) からも読まれるので、 launchd / systemd のように cwd が異なる環境からでも設定が効きます。

更新するときは pull して作り直します (.env は git 管理外なので残ります)。

cd ~/.local/share/mynote-mcp && git pull && bun install && bun run compile
launchctl kickstart -k gui/$(id -u)/com.mynote.mcp   # 常駐している場合

.env の探索場所

.envパッケージルート (このリポジトリの .env) か、 MYNOTE_ENV_FILE で明示したパスからのみ読み込みます。 カレントディレクトリの .env は読みません。 任意のリポジトリで開いたセッションから使うサーバなので、 第三者のリポジトリに置かれた .envMYNOTE_VAULT_PATHMYNOTE_URL を 差し替えられないようにしています。読み込むキーも MYNOTE_ で始まるものだけです。

環境変数

変数

必須

既定値

説明

MYNOTE_VAULT_PATH

Obsidian vault のルート。~ 展開に対応。スペースを含む場合はクォートする。起動時に存在確認し、無ければエラー終了する

MYNOTE_ATTACHMENTS_DIR

attachments

添付の保存先 (vault 相対)。無ければ自動作成

MYNOTE_PORT

7391

HTTP の待ち受けポート

MYNOTE_HOST

127.0.0.1

バインドするホスト。既定はループバックのみ

MYNOTE_URL

http://127.0.0.1:${MYNOTE_PORT}/mcp

stdio ブリッジの接続先。ループバック以外は拒否して in-process にフォールバックする

MYNOTE_ENV_FILE

読み込む .env のパス

CLI では --port / --host が環境変数を上書きします。

mynote-mcp serve --port 7500
mynote-mcp stdio
mynote-mcp --help

クライアントへの登録

Claude Code

常駐している HTTP エンドポイントを user スコープで登録します。 これでどのディレクトリで開いたセッションからでも同じ vault が使えます。

claude mcp add --transport http mynote http://127.0.0.1:7391/mcp --scope user

確認と削除。

claude mcp list
claude mcp remove mynote --scope user

Codex CLI

~/.codex/config.toml に stdio ブリッジを登録します。パスは自分の環境に合わせてください。

[mcp_servers.mynote]
command = "/Users/shinya/.bun/bin/bun"
args = ["/Users/shinya/Desktop/products/mynote-mcp/src/index.ts", "stdio"]

[mcp_servers.mynote.env]
MYNOTE_VAULT_PATH = "/Users/shinya/Library/Mobile Documents/iCloud~md~obsidian/Documents/MyVault"
MYNOTE_URL = "http://127.0.0.1:7391/mcp"

MYNOTE_VAULT_PATH は in-process フォールバック時に必要です (.env をパッケージルートに置いてあるなら省略できます)。 env$HOME などのシェル変数は書けないので、絶対パスを直接書いてください。 command も同様に bun の絶対パス (which bun) が必要です。

単一バイナリを作った場合は、そのパス 1 つで済むので確実です。

[mcp_servers.mynote]
command = "/Users/shinya/Desktop/products/mynote-mcp/dist/mynote-mcp"
args = ["stdio"]

常駐させる

macOS (launchd)

~/Library/LaunchAgents/com.mynote.mcp.plist を次の内容で作成します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.mynote.mcp</string>

  <key>ProgramArguments</key>
  <array>
    <string>/Users/shinya/Desktop/products/mynote-mcp/dist/mynote-mcp</string>
    <string>serve</string>
  </array>

  <key>WorkingDirectory</key>
  <string>/Users/shinya/Desktop/products/mynote-mcp</string>

  <key>EnvironmentVariables</key>
  <dict>
    <key>MYNOTE_VAULT_PATH</key>
    <string>/Users/shinya/Library/Mobile Documents/iCloud~md~obsidian/Documents/MyVault</string>
    <key>MYNOTE_PORT</key>
    <string>7391</string>
    <key>MYNOTE_HOST</key>
    <string>127.0.0.1</string>
  </dict>

  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>

  <key>StandardOutPath</key>
  <string>/Users/shinya/Library/Logs/mynote-mcp.log</string>
  <key>StandardErrorPath</key>
  <string>/Users/shinya/Library/Logs/mynote-mcp.error.log</string>
</dict>
</plist>

読み込みと操作。

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.mynote.mcp.plist
launchctl print gui/$(id -u)/com.mynote.mcp        # 状態確認
launchctl kickstart -k gui/$(id -u)/com.mynote.mcp # 再起動
launchctl bootout gui/$(id -u)/com.mynote.mcp      # 停止・解除

launchd はログインシェルの PATH を引き継がないため、絶対パスが必須です。 上記は bun run compile で作った単一バイナリを指しています (ランタイムを同梱するので、bun のインストール先やバージョンに影響されません)。

バイナリを作らずソースを直接動かす場合は、bun の絶対パス (which bun、 通常 /Users/<you>/.bun/bin/bun) を第 1 引数にしてください。

  <key>ProgramArguments</key>
  <array>
    <string>/Users/shinya/.bun/bin/bun</string>
    <string>/Users/shinya/Desktop/products/mynote-mcp/src/index.ts</string>
    <string>serve</string>
  </array>

Linux (systemd --user)

~/.config/systemd/user/mynote-mcp.service を次の内容で作成します。

[Unit]
Description=mynote-mcp (Obsidian vault MCP server)
After=default.target

[Service]
Type=simple
WorkingDirectory=/home/shinya/mynote-mcp
ExecStart=/home/shinya/mynote-mcp/dist/mynote-mcp serve
# 単一バイナリを作らない場合:
# ExecStart=/home/shinya/.bun/bin/bun /home/shinya/mynote-mcp/src/index.ts serve
Environment=MYNOTE_VAULT_PATH=/home/shinya/Obsidian/MyVault
Environment=MYNOTE_PORT=7391
Environment=MYNOTE_HOST=127.0.0.1
Restart=on-failure
RestartSec=3
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target

有効化と操作。

systemctl --user daemon-reload
systemctl --user enable --now mynote-mcp
systemctl --user status mynote-mcp
journalctl --user -u mynote-mcp -f
loginctl enable-linger "$USER"   # ログアウト後も動かす場合

値にスペースを含む場合は Environment="MYNOTE_VAULT_PATH=/path/with space" のように 行全体をクォートしてください。

エンドポイント (serve)

メソッド

パス

説明

POST

/mcp

MCP Streamable HTTP。initialize で新規セッションを作り、以降は mcp-session-id ヘッダで継続

GET

/mcp

既存セッションの SSE ストリーム

DELETE

/mcp

セッション終了

GET

/health

{ ok: true, vault: <vault のディレクトリ名>, notes: <ノート件数> }

SIGINT / SIGTERM で全セッションを閉じてから HTTP を停止します (graceful shutdown)。 無通信のセッションは 30 分で破棄されます。

ツール一覧

すべてのツールは JSON 文字列を text コンテンツとして返します。 エラーは例外ではなく isError: true のツール結果として返ります。

書き込み

ツール

入力

戻り値

create_note

prefix (必須), content (必須), tags?: string[], datetime? (ISO8601), frontmatter?: Record<string, string | string[]>

{ path, filename, title }

append_to_note

filename または title (どちらか必須), content (必須), heading?

{ path, filename, title, heading }

update_frontmatter

filename (必須), addTags?, removeTags?, set?, removeKeys?

{ path, filename, title, changed, frontmatter }

  • create_note は命名規則でファイル名を決め、frontmatter に tagscreated (ISO8601) を書きます。 frontmattertags / created を上書きすることもできます。

  • append_to_noteheading を指定するとその見出しセクションの末尾に挿入します (見出しが無ければ本文末尾に ## <heading> を作ります)。frontmatter は変更しません。

  • update_frontmatter は frontmatter だけを書き換え、本文は 1 バイトも変えません。 既存の frontmatter 行の書式も保ちます。

読み取り・検索

ツール

入力

戻り値

search_notes

tags?, tagMode?: "and" | "or" (既定 and), query?, from?, to?, prefix?, limit? (既定 50, 最大 500)

{ total, count, limit, truncated, results: { filename, title, prefix, datetime, date, time, tags, snippet }[] }

read_note

filename または title

{ path, filename, title, prefix, datetime, tags, frontmatter, body }

list_tags

なし

{ total, tags: { tag, count }[] } (count 降順)

  • query は本文の大文字小文字を無視した部分一致です。

  • from / toファイル名の日付で絞り込みます (YYYY-MM-DD または ISO8601)。

  • prefix は前方一致です。

  • タグは frontmatter の tags と本文中の #tag の両方を拾います。

  • truncatedtrue なら limit で切られています (total が実ヒット数)。

添付

ツール

入力

戻り値

save_attachment

filename (必須), base64?, sourcePath? (base64 と排他)

{ path, relativePath, filename, wikilink, size }

MYNOTE_ATTACHMENTS_DIR 配下に保存し (必要なら再帰的に作成)、 ![[<filename>]] 形式の wikilink を返します。 同名ファイルがあれば連番を付けます。1 件あたり 64MB までです。

デイリー

ツール

入力

戻り値

append_to_daily

content (必須), prefix? (既定 Daily), heading?, tags?

{ path, filename, title, created, date, prefix }

今日の日付を持つ <prefix> YYYY-MM-DD *.md を探し、あれば最も新しいものに追記します。 無ければ create_note 相当で新規作成 (タグ daily 付き) してから追記します。 created は新規作成したかどうかを表します。

ファイル命名規則

<prefix> YYYY-MM-DD HHmm.md

議事録 2026-07-30 1145.md
Idea 2026-07-30 0902.md
Daily 2026-07-30 0800.md
  • prefix は自由入力です。許可リストによる検証はありません。

  • 日時はローカルタイムゾーンです。datetime に ISO 文字列を渡せば任意の日時を使えます (日付のみ / オフセットなしの日時もローカルタイムとして解釈します)。

  • ファイル名として不正な文字 / \ : * ? " < > | と制御文字は除去し、 前後の空白を trim、連続空白を 1 つに圧縮します。 サニタイズ後に空になった場合は Note にフォールバックします。

  • 同名衝突時は 議事録 2026-07-30 1145-2.md のように連番サフィックスを付けます。

  • フォルダは作りません。 ノートはすべて vault ルート直下です。分類はタグで行います。 例外は添付だけで、MYNOTE_ATTACHMENTS_DIR 配下に入ります。

セキュリティ

  • すべての読み書きパスが vault ルート配下に解決されることを検証します。 シンボリックリンクは実在しない末尾コンポーネントも含めて 1 段ずつ解決するため、 リンク経由の脱出もできません。vault 外を指すパスは必ず例外になります。

  • HTTP は既定でループバック (127.0.0.1) にのみバインドします。

  • DNS rebinding 対策 (allowedHosts / allowedOrigins) を Hono ミドルウェアで一本化しています。 /mcp/health の両方に同じ検証を適用します (SDK 側の同名オプションは deprecated で、外部ミドルウェアが推奨されているため)。

  • /health は vault の絶対パスを返さず、ディレクトリ名だけを返します。

  • stdio ブリッジはループバック以外の MYNOTE_URL へは接続しません (乗っ取られた URL にノート内容を送らないため)。

  • .env はパッケージルートか MYNOTE_ENV_FILE からのみ、MYNOTE_ で始まるキーのみ読み込みます。

開発

bun run typecheck    # tsc --noEmit
bun test ./test      # 221 tests
bun run test:node    # Node 互換スモーク (serve / stdio を実プロセスで確認)
bun run test:binary  # 単一バイナリスモーク (バンドル後しか出ない不具合を拾う)
bun run compile      # dist/mynote-mcp (単一バイナリ)
bun run build:node   # tsc で dist/ を生成し bin の shebang を node に書き換える

bin (dist/src/index.js) は npm 経由でも動くよう tsc 出力を指しています (prepare が shebang を #!/usr/bin/env node に書き換えて実行権限を付けます)。 Bun で直接動かす場合はソースの src/index.ts (#!/usr/bin/env bun) を使います。

bun test を引数なしで実行すると dist/ 配下のビルド成果物まで拾ってしまうので、 必ず ./test を指定してください (bun run test は指定済みです)。

src/
  index.ts          # CLI エントリ (serve | stdio)
  config.ts         # env 読み込み + 検証 + .env ローダー
  vault/
    paths.ts        # vault ルート解決 / パス封じ込め / ファイル名サニタイズ / 命名規則
    frontmatter.ts  # 自前 frontmatter parse / stringify
    notes.ts        # ノート CRUD + 一覧走査
  tools/
    index.ts        # registerTools / createServer
    write.ts        # create_note / append_to_note / update_frontmatter
    read.ts         # search_notes / read_note / list_tags
    attachment.ts   # save_attachment
    daily.ts        # append_to_daily
  server/
    http.ts         # Hono アプリ + Web 標準 StreamableHTTP 配線 (listen だけ Bun/Node 分岐)
    stdio.ts        # stdio ブリッジ
test/               # bun test による単体・統合テスト
scripts/
  node-smoke.sh     # Node 互換スモーク

frontmatter は依存を増やさないため自前の最小パーサです。 tags / aliases のような単純なリストとスカラーだけを扱い、 書き戻しの際に既存行を壊さないようにしています。

トラブルシューティング

vault が見つからない

設定の読み込みに失敗しました: vault が見つかりません: /path/to/vault (MYNOTE_VAULT_PATH=...)
  • パスにスペースが含まれている場合、.env でクォートしていますか。 MYNOTE_VAULT_PATH="$HOME/Library/Mobile Documents/iCloud~md~obsidian/Documents/MyVault"

  • launchd の EnvironmentVariables や Codex の env では $HOME~ が展開されません。 絶対パスを書いてください (CLI から渡す ~ は展開されます)。

  • iCloud vault はまだローカルにダウンロードされていない可能性があります。 Finder で vault を開いて実体化されているか確認してください。

  • カレントディレクトリの .env は読みません。パッケージルートの .envMYNOTE_ENV_FILE を使ってください。

確認コマンド:

ls -d "$HOME/Library/Mobile Documents/iCloud~md~obsidian/Documents/MyVault"

ポートが衝突する

mynote-mcp の起動に失敗しました: listen EADDRINUSE: address already in use 127.0.0.1:7391

使用中のプロセスを確認します。

lsof -nP -iTCP:7391 -sTCP:LISTEN     # macOS / Linux

すでに mynote-mcp が常駐しているだけなら、二重起動は不要です (curl http://127.0.0.1:7391/health で確認)。 別のプロセスが使っている場合はポートを変えます。変更したらクライアント側の登録も 合わせて更新してください。

MYNOTE_PORT=7500 bun start
claude mcp remove mynote --scope user
claude mcp add --transport http mynote http://127.0.0.1:7500/mcp --scope user

stdio が繋がらない

mynote-mcp stdio は stderr に状況を出します。

stderr

意味

http://127.0.0.1:7391/mcp に接続しました (プロキシモード)

正常。常駐プロセスへ転送しています

... への接続に失敗しました: ...in-process モードで起動します

常駐プロセスが居ないので、ブリッジが直接 vault を触ります

MYNOTE_URL がループバックではないため接続しません

MYNOTE_URL127.0.0.1 / localhost / [::1] に直してください

in-process モードでも機能はすべて使えますが、MYNOTE_VAULT_PATH が そのプロセスから見えている必要があります。Codex の [mcp_servers.mynote.env] に 書いたか、パッケージルートに .env があるかを確認してください。

Codex 側でツールが 1 つも見えない場合:

  • commandnode が PATH で解決できているか (絶対パスにすると確実です)

  • commandbun (または単一バイナリ) が絶対パスで、実行可能か

  • ~/.codex/config.toml の変更後に Codex を再起動したか

Claude Code 側で繋がらない場合は、まず curl http://127.0.0.1:7391/health{"ok":true,...} を返すか確認してください。 403 Invalid Host header が返る場合は、登録した URL のホスト名が 127.0.0.1 / localhost / [::1] のいずれかになっているか確認してください (DNS rebinding 対策で他のホスト名は拒否されます)。

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    -
    quality
    D
    maintenance
    A local MCP server that wraps the Obsidian CLI to give AI assistants direct access to read, edit, and manage notes within an Obsidian vault. It enables advanced operations such as frontmatter property management, context-aware searching, and the execution of internal Obsidian commands.
    Last updated
    2
  • F
    license
    -
    quality
    A
    maintenance
    Built on Obsidian Vault, this MCP server integrates with Claude Code to provide personal knowledge management including note saving, full-text search, code graph extraction, and context resumption.
    Last updated
    1
  • A
    license
    -
    quality
    B
    maintenance
    This MCP server enables Claude to interact with an Obsidian vault for persistent, structured memory, providing tools for note creation, semantic search, graph traversal, and session memory.
    Last updated
    62
    13
    MIT
  • A
    license
    -
    quality
    C
    maintenance
    MCP server that provides read and write access to an Obsidian vault by interacting directly with markdown files on disk. Supports searching, listing, reading, creating, editing, and appending notes without requiring any Obsidian plugins.
    Last updated
    3,424
    ISC

View all related MCP servers

Related MCP Connectors

  • Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.

  • Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.

  • Markdown-first MCP server for Notion API with 8 composite tools and 39 actions.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Yatty1/mynote-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server