MCP Hostingでデータが消える理由と対策:memory・SQLite・filesystemサーバーの永続ストレージ実践ガイド【2026年】
memory・SQLite・filesystemのMCPサーバーをホスティングすると、なぜ再起動でデータが消えるのか。server-memory 2.0.0で、npxキャッシュへの既定保存、相対パスのMEMORY_FILE_PATH、ロックファイルのENOENT、ファイル単体マウントのEBUSY、WALで1,000行が消えたSQLiteを検証。Cloud Run・Lambda・Workers・Railway・Renderの制約、書き込み手を1つにするルール、Docker手順、バックアップまで解説。
最終更新:2026年10月22日 / 対象:
@modelcontextprotocol/server-memory2.0.0、@modelcontextprotocol/server-filesystem2.0.0、mcp-server-sqlite2025.4.25、SQLite 3.45.1、および2026年10月時点の各プラットフォームのストレージ仕様。検証は2026年10月22日、Linux上のNode.js 22.22.0とPython 3.13、クライアントにMCP TypeScript SDK 1.32.1を使って実施
結論(30秒で読める要約)
MCPサーバーの永続ストレージとは、状態を持つMCPサーバーがツールで書き込んだデータを、再起動・再デプロイ・スケールトゥゼロのあとも残しておくためのディスクやデータベースのことです。手元のPCではディスクが消えないので意識しませんが、MCP Hostingでは既定のファイルシステムが一時的なものであることがほとんどです。そのため、memory(ナレッジグラフ)、SQLite、filesystemといったサーバーは、気づかないうちに空の状態に戻ります。
- 既定の保存場所がいちばん危険です。
server-memory2.0.0 はmemory.jsonlを自分のパッケージのディレクトリに書きます。npx -yで起動すると、そこはnpxのキャッシュです。検証では~/.npm/_npx/<hash>/node_modules/.../dist/memory.jsonlに保存され、キャッシュを消すとグラフは空に戻りました。 - マウントするのはディレクトリです。ファイル単体ではありません。memoryサーバーは一時ファイルを書いてから名前を付け替える方式で保存します。ファイル単体をバインドマウントする(
docker run -v ./memory.jsonl:/data/memory.jsonlと同じ)と、書き込みのたびにEBUSY: resource busy or locked, renameで失敗しました。WALモードのSQLiteでは-walファイルがマウントの外に作られ、コンテナを作り直すとコミット済みの1,000行が消えました。 - サーバーレスのファイルシステムは保存先になりません。Cloud Runのファイルシステムはメモリ上にあり、インスタンスが止まると消えます。Workersの
/tmpはリクエストごと、Lambdaの/tmpは実行環境ごとに別物です。 - 1つのファイルに書き込むのは1台だけにします。RailwayとRenderのボリュームは1インスタンスでしか使えません。SQLiteのWALモードはネットワークファイルシステム上では動きません。複数台で動かすなら、データはデータベースに移します。
検証した失敗パターンは4章、保存先の比較は5章、SQLiteのルールは6章にまとめています。
目次
- MCPサーバーにとっての永続ストレージとは
- どのMCPサーバーが、どこに書き込むか
- データが消えるタイミング:プラットフォーム別
- 検証:memoryサーバーのデータが消える4つのパターン
- MCP Hostingの保存先の比較
- MCP HostingでSQLiteを使うときの5つのルール
- 1ファイル1書き込み手:レプリカ、ブリッジ、ロック
- 手順:ボリューム付きでmemoryサーバーを動かす
- バックアップ
- チェックリスト
- トラブルシューティング(症状→原因→対処)
- NodeFlareならこう解決できる
- よくある質問
1. MCPサーバーにとっての永続ストレージとは
MCPサーバーの永続ストレージとは、ツールが書いたデータをサーバーのプロセスより長く残せる場所のことで、マウントしたボリューム、永続ディスク、外部のデータベースが該当します。必要になるのは、呼び出しをまたいでデータを持つサーバーだけです。GitHub、Slack、検索APIのように外部APIへ取り次ぐだけのサーバーは、データを接続先に持っているので不要です。
ホスティングしたMCPサーバーが持つ状態は3種類あり、それぞれ置き場所が違います。
| 状態の種類 | 例 | 寿命 | 置き場所 | 扱っている記事 |
|---|---|---|---|---|
| 接続・セッションの状態 | 2025年版の Mcp-Session-Id、開いたままのブラウザ |
1回の接続 | プロセスのメモリ(同じレプリカに振り分ける) | MCPサーバーを複数レプリカに広げる |
| ジョブの状態 | 長時間かかるレポートの job_id |
数分〜数時間 | 再デプロイで消えない保存先 | タイムアウトの記事 |
| データ | ナレッジグラフ、SQLiteの行、メモ、ファイル | 数か月 | ボリューム、永続ディスク、データベース | この記事 |
この記事が扱うのは3行目、つまり「来週もそこにあるはず」と利用者が思っているデータです。
2. どのMCPサーバーが、どこに書き込むか
GitHubで見つけたサーバーをホスティングする前に、何をどこに書くのかを確かめます。READMEの環境変数とオプションを見て、次にソースを writeFile、open(、sqlite3.connect などで検索するのが早道です。よく使われるサーバーを調べた結果がこちらです。
| サーバー | 書き込むもの | 既定の場所 | 変更方法 | 注意点 |
|---|---|---|---|---|
@modelcontextprotocol/server-memory 2.0.0 |
ナレッジグラフ(memory.jsonl)と、書き込み中の memory.jsonl.lock |
パッケージの dist ディレクトリ内の memory.jsonl |
MEMORY_FILE_PATH(絶対パス) |
相対パスも作業ディレクトリではなくパッケージのディレクトリ基準で解決される |
@modelcontextprotocol/server-filesystem 2.0.0 |
モデルが書いたファイル | 引数で渡した許可ディレクトリだけ | コマンドライン引数 | 2026-07-28の接続ではRootsが使えず、引数のディレクトリが許可リストのすべてになる |
mcp-server-sqlite 2025.4.25(アーカイブ済みのリファレンス実装) |
SQLiteデータベース | 指定したパス | --db-path |
親ディレクトリがなければ自分で作る |
| Playwright MCP | ブラウザのプロファイル(ログイン、Cookie) | 0.0.83では ~/.cache/ms-playwright-mcp/... |
--user-data-dir、または --storage-state で初期状態を渡す |
Playwright MCPのホスティング記事で詳しく解説 |
| 自作のサーバー | SQLite、JSONのキャッシュ、アップロード | たいていコードの隣 | 設定項目にする | 最初から環境変数で保存先を受け取る |
この表で意外に思われやすい点が2つあります。
- memoryサーバーの既定の保存先は、自分のコードの中です。ソースのコメントにも、パッケージのディレクトリが既定のグラフファイルの置き場所であり、相対パスの基準でもあると書かれています。コードが置き換わる操作(新しいイメージ、npxキャッシュの削除、
npm install)をすると、データも一緒に置き換わります。 - 公式のDocker例は、コードのディレクトリにボリュームをかぶせています。
server-memoryのREADMEは-v claude-memory:/app/distを使い、古いボリュームに入っているindex.jsが新しいコンテナで上書きされる可能性があると注意しています。データ専用のディレクトリを用意してMEMORY_FILE_PATHで指す方が、コードとデータが混ざりません。
3. データが消えるタイミング:プラットフォーム別
ほとんどのホスティング先では、ボリュームとして宣言した場所以外に書いたものは、再起動・再デプロイ・スケールトゥゼロで消えます。各社のドキュメントの記述は次のとおりです。
| プラットフォーム | 既定のファイルシステム | ドキュメントの記述 | 永続化の手段 |
|---|---|---|---|
| Docker/一般的なVPS | コンテナの書き込み層 | コンテナと一緒に消える(--rm、新しいイメージ、ビルド後の docker compose up) |
名前付きボリューム、またはディレクトリのバインドマウント |
| Google Cloud Run | メモリ上 | メモリ上のファイルシステムなので、書き込むとインスタンスのメモリを使う。インスタンスが止まるとデータは残らない | ボリュームマウント(Cloud Storage FUSE、NFS)かデータベース |
| AWS Lambda | /tmp(512MB〜10,240MB) |
一時的で、実行環境ごとに別のもの | Amazon EFS、S3、データベース |
| Cloudflare Workers | メモリ上の仮想ファイルシステム | /tmp の中身は永続せず、リクエストごとに別のもの |
Durable Objects(SQLite API、1オブジェクト10GB)、D1、KV、R2 |
| Railway | コンテナのファイルシステム | ボリュームはレプリカと併用できない。ボリュームがあると再デプロイ時に短いダウンタイムが出る | 1サービス1ボリューム(Free/Trial 0.5GB、Hobby 5GB、Pro 50GB) |
| Render | コンテナのファイルシステム | ディスクのマウントパス配下の変更だけがデプロイや再起動のあとも残る | 有料サービスの永続ディスク(1インスタンスのみ、ゼロダウンタイムデプロイは使えない) |
ここから言えることは2つです。
- Cloud Runでは「保存」がメモリの消費になります。memoryサーバーがメモリ上のファイルシステムに書くとインスタンスのメモリ使用量が増え、それでもインスタンスが止まればデータは消えます。
- スケールトゥゼロは再起動と同じです。アイドル時に止まるプラットフォームでは、マウントしていないデータはいずれ消えます。「1週間は動いていた」のは、たまたまアクセスが途切れなかっただけです。
4. 検証:memoryサーバーのデータが消える4つのパターン
server-memory 2.0.0 を、よくあるホスティングのやり方で起動し、書いたエンティティが残るかを確かめました。クライアントはstdio接続のMCP TypeScript SDK 1.32.1です。毎回 create_entities で1件書いてから read_graph で読みました。Dockerのマウントを再現するために mount --bind を使いました。LinuxでDockerのバインドマウントがしていることと同じです。
| # | 構成 | 結果 | データは残ったか |
|---|---|---|---|
| 1 | npx -y @modelcontextprotocol/server-memory@2.0.0、MEMORY_FILE_PATH なし |
~/.npm/_npx/73bfbdd03ce645db/node_modules/@modelcontextprotocol/server-memory/dist/memory.jsonl に保存された。新しいコンテナと同じ状態にするため ~/.npm/_npx を消すと、read_graph は {"entities":[],"relations":[]} を返した |
残らない |
| 2 | MEMORY_FILE_PATH=memory.jsonl(相対パス) |
パッケージの dist ディレクトリ基準で解決され、既定と同じファイルになった |
残らない |
| 3 | /data がない状態で MEMORY_FILE_PATH=/data/memory.jsonl |
ツールエラー:ENOENT: no such file or directory, open '/data/memory.jsonl.lock' |
書き込めない |
| 4 | memory.jsonl をファイル単体でバインドマウント |
ツールエラー:EBUSY: resource busy or locked, rename '…/memory.jsonl.<random>.tmp' -> '…/memory.jsonl' |
書き込めない |
| 5 | /data にディレクトリをバインドマウントし、MEMORY_FILE_PATH=/data/memory.jsonl |
書き込み成功。ボリューム側に memory.jsonl ができた |
残る |
3と4が失敗する理由は保存の仕組みにあります。このサーバーは、memoryファイルの隣にロックファイルを作り、同じディレクトリに一時ファイルを書いてから元のファイルへ名前を付け替えて保存します。READMEにも、アトミックな保存のためにディレクトリが書き込み可能である必要があると書かれています。Linuxではファイル単体のマウントポイントに名前を付け替えられないので、保存が完了しません。モデルにはツールエラーが返るので、黙って消えるよりはましですが、ディレクトリをマウントするまでツールは使えません。
4をLinuxで再現する手順です(rootで、作業用ディレクトリで実行)。
mkdir -p vol app && touch vol/memory.jsonl app/memory.jsonl
mount --bind "$PWD/vol/memory.jsonl" "$PWD/app/memory.jsonl" # docker -v file:file と同じ
MEMORY_FILE_PATH="$PWD/app/memory.jsonl" npx -y @modelcontextprotocol/server-memory@2.0.0
# 任意のMCPクライアントから create_entities を呼ぶ → rename で EBUSY
なお、server-memory 2.0.0 は "engines": {"node": ">=24"} を宣言しています。今回Node.js 22.22.0でも動きましたが、本番ではNode.js 24のイメージを使ってください。
5. MCP Hostingの保存先の比較
多くのMCPサーバーには、1インスタンスに付けたボリュームか永続ディスクで十分です。データベースに切り替えるのは、複数のレプリカで動かす場合や、複数のサーバーでデータを共有する場合だけです。
| 保存先 | 再起動・再デプロイ後も残る | 複数レプリカから書ける | SQLiteを置けるか | 主な用途 | 注意点 |
|---|---|---|---|---|---|
| コンテナのファイルシステム(ボリュームなし) | 残らない | 不可 | 一時用途のみ | キャッシュ、一時ファイル | スケールトゥゼロで消える。Cloud RunではRAMを使う |
| 1インスタンスのボリューム・永続ディスク | 残る | 不可 | 可 | memory.jsonl、SQLite、メモ |
1インスタンス限定。デプロイ時に短い停止が出ることがある |
| ネットワークファイルシステム(NFS、EFS) | 残る | 理屈の上では可 | WALモードは不可 | 読み取り中心の共有ファイル | SQLite公式も、一部のネットワークファイルシステムではロックが正しく動かないことがあると書いている |
| Cloud Storage FUSE | 残る | 可(ただし安全ではない) | 不可 | 大きな読み取り専用ファイル | 完全なPOSIX互換ではない。ファイルロックがなく、最後の書き込みが勝つ |
| オブジェクトストレージ(S3、R2、GCSのAPI) | 残る | 可(オブジェクト単位) | 不可 | エクスポート、添付、バックアップ | ファイルパスではなくAPIで扱うようサーバー側の対応が必要 |
| マネージドDB(Postgres、MySQL、D1) | 残る | 可 | SQLiteの代わりになる | 複数レプリカ・複数ユーザーのサーバー | GitHubのサーバーの多くはコード変更が必要 |
| Durable ObjectsのSQLite(Workers) | 残る | 1オブジェクトが1書き込み手 | 組み込み | Workers向けに書かれたサーバー | ctx.storage.sql。1オブジェクト10GB |
選び方の目安です。
- GitHubのサーバーをそのまま動かす場合:ボリュームか永続ディスクにして、ディレクトリをマウントし、サーバーのパス設定をその中のファイルに向けます。
- レプリカを2台以上にしたい場合:データをデータベースに移す必要があります。たいていはサーバーをフォークするか、Postgresなどに対応したサーバーを選ぶことになります。
- Workers向けに新しく書く場合:最初からDurable ObjectsかD1に置きます。頼れるファイルシステムはありません。
6. MCP HostingでSQLiteを使うときの5つのルール
SQLiteはGitHubのMCPサーバーでいちばんよく使われる保存先で、1台のマシンがファイルを持ち、ディレクトリごと永続化すれば、ホスティングでも安全に使えます。
- ファイルではなくディレクトリを永続化します。WALモードのSQLiteは、データベースの隣に
-walと-shmのファイルを作ります。検証では、ファイル単体のマウントだとapp.dbはボリューム側に、app.db-wal(1,000行挿入後に20,632バイト)はコンテナ側に置かれました。チェックポイント前にプロセスを強制終了し、コンテナ側のディレクトリを消すと、ボリューム上のデータベースは0行でした。ディレクトリをマウントした場合は3つのファイルがすべてボリューム側にあり、1,000行が残りました。 - 1台のホストからだけ使います。SQLiteのドキュメントは、WALはネットワークファイルシステム上では動かないこと、データベースを使うプロセスはすべて同じホストにある必要があることを明記しています。2台のレプリカから同じファイルをNFS越しに開かないでください。
- Cloud Storage FUSEには置きません。ファイルロックがなく、上書きは最後のものだけが残ります。
- 正しく終了させます。接続を正常に閉じると、SQLiteはWALの内容を本体に書き戻します。
SIGTERMを受けたら、プラットフォームに強制終了される前に接続を閉じます。 - アプリとデータがネットワークで隔てられるなら、クライアント/サーバー型のDBにします。SQLite自身がそう勧めています。
7. 1ファイル1書き込み手:レプリカ、ブリッジ、ロック
永続ストレージを持たせると、そのサーバーは「書き込み手が1つ」という制約を負い、スケールのしかたが限られます。2つ目の書き込み手が紛れ込む場所は3つあります。
- レプリカ:Railwayはボリュームとレプリカを併用できないとしており、Renderもディスク付きのサービスは1インスタンスしか動かせないとしています。2台から同じネットワークボリュームをマウントできる環境でも、ネットワークファイルシステム上のSQLiteやロックファイルは信頼できません。
- stdioブリッジ:supergatewayの
--statefulのような状態ありブリッジは、セッションごとに子プロセスを1つ起動します。クライアントが4つつながれば、4つのserver-memoryプロセスが1つのファイルに書くことになります。server-memory2.0.0 はローカルディスクならこれに対応しています。書き込みのたびにmemory.jsonl.lockを排他的に取り、検証では4プロセスが25回ずつ書いて100件がそろい、エラーは0件でした。ただしREADMEには、排他的なファイル作成を守らないネットワークファイルシステムでは安全に共有できないとあります。自分のサーバーがファイルをロックしているかは確認してください。ロックしていないサーバーは、2つのプロセスが同時に保存すると書き込みを失うことがあります。ブリッジのプロセス管理の違いはstdioのMCPサーバーをリモートで動かす方法で解説しています。 - 新旧のデプロイ:ローリングデプロイの間は、古い版と新しい版が同時に動くことがあります。1インスタンス限定のボリュームを使うプラットフォームでは、これが「止めてから起動する」動きに置き換わり、Railwayのいう短いダウンタイムになります。
ロックがなく、プロセスを1つに保てないサーバーなら、1つのファイルを共有するのではなく、ユーザーごとにサーバーと保存先を分けます。
8. 手順:ボリューム付きでmemoryサーバーを動かす
うまくいく形は「データ用ディレクトリ → そこを指す環境変数 → そのディレクトリにボリュームをマウント」です。supergateway経由でmemoryサーバーを動かすDockerfileの例です。
FROM node:24-slim
RUN npm install -g supergateway@4.2.0 @modelcontextprotocol/server-memory@2.0.0 \
&& mkdir -p /data && chown node:node /data
USER node
ENV MEMORY_FILE_PATH=/data/memory.jsonl
VOLUME ["/data"]
EXPOSE 8000
CMD ["supergateway", "--stdio", "mcp-server-memory", \
"--outputTransport", "streamableHttp", "--stateful", \
"--sessionTimeout", "600000", "--port", "8000"]
名前付きボリュームをディレクトリにマウントして起動します。
docker build -t memory-mcp .
docker run -d --name memory-mcp -p 8000:8000 -v memory-data:/data memory-mcp
# 再デプロイ(新しいコンテナ、同じボリューム)してもグラフは残る
docker rm -f memory-mcp && docker run -d --name memory-mcp -p 8000:8000 -v memory-data:/data memory-mcp
SQLiteのサーバーも考え方は同じで、/data をマウントして --db-path /data/app.db で起動します。filesystemサーバーは、モデルに作業させたいディレクトリをマウントし、それを引数で渡します。2026-07-28のクライアントはRootsを送れないからです。
最後に、意味のある確認は1つだけです。書く、再デプロイか再起動をする、読み戻す。ClaudeやCursorにつなぐ前に一度、最初のスケールトゥゼロのあとにもう一度確かめます。
9. バックアップ
ボリュームが守ってくれるのは再起動からだけで、操作ミスからは守ってくれません。戻せるコピーを取っておきます。
| データ | 動作中に安全にコピーする方法 | 理由 |
|---|---|---|
memory.jsonl |
普通のファイルコピー | サーバーはアトミックな名前の付け替えでファイルを置き換えるので、読む側には古いか新しいファイルの全体が見え、書きかけは見えない |
| SQLiteデータベース | sqlite3 /data/app.db ".backup /backups/app.db" または VACUUM INTO '/backups/app.db' |
.db ファイルだけをコピーすると、-wal に残っている分が抜ける |
| ファイルの入ったディレクトリ | プラットフォームのスナップショット、または tar でオブジェクトストレージへ |
ボリュームを自動でスナップショットするプラットフォームもある(Renderは24時間ごと、7日以上保持) |
データの形式が変わるデプロイの前には、必ずバックアップを取ります。コードをロールバックしても、データは元に戻りません。
10. チェックリスト
- [ ] サーバーが書き込むパスをすべて把握している(README、オプション、ソース検索)
- [ ] 各パスを絶対パスで明示している(
MEMORY_FILE_PATH、--db-path、ディレクトリ引数) - [ ] マウントしているのはファイル単体ではなくディレクトリで、存在し、サーバーの実行ユーザーが書き込める
- [ ] 使うプラットフォームで、ボリュームが再起動・再デプロイ・スケールトゥゼロのあとも残ることを「書く→再デプロイ→読む」で確認した
- [ ] 各ファイルに書くのは1台だけ。レプリカは1つにしているか、データをDBに置いている
- [ ] SQLiteをNFSやCloud Storage FUSEに置いておらず、
SIGTERMでDBを閉じている - [ ] SQLiteは
.backupかVACUUM INTO、JSONLはファイルコピーでバックアップしている - [ ] ボリュームの容量と月額(停止中の課金を含む)を把握している
- [ ] データ形式が変わるデプロイの前にバックアップを取っている
11. トラブルシューティング(症状→原因→対処)
| 症状 | 原因 | 対処 |
|---|---|---|
| 再起動のたびにmemoryサーバーが空になる | データがパッケージのディレクトリかnpxキャッシュにある | MEMORY_FILE_PATH をボリューム上の絶対パスにする |
EBUSY: resource busy or locked, rename |
ファイル単体をバインドマウントしている | 親ディレクトリをマウントする |
ENOENT … memory.jsonl.lock |
memoryファイルの親ディレクトリがない | イメージで作成するか、そこにボリュームをマウントする |
/data への書き込みで EACCES |
ボリュームの所有者がrootで、サーバーは別ユーザーで動いている | イメージ内で chown するか、ボリュームの権限を直す |
.db はボリュームにあるのに、再デプロイ後に行が消えている |
-wal ファイルがボリュームの外にあった |
ディレクトリをマウントし、終了時にDBを閉じる |
負荷をかけると database is locked |
複数のプロセスやレプリカが1つのSQLiteファイルを共有している | 1ファイル1プロセスにするか、クライアント/サーバー型DBに移す |
| あるレプリカにはデータがあり、別のレプリカにはない | レプリカごとに別のディスクを持っている | 1インスタンスにするか、共有DBに移す |
| アクセスは増えていないのにCloud Runのメモリ使用量が増える | 書き込みがメモリ上のファイルシステムに入っている | ボリュームマウントかDBを使う |
| Workersで書いたファイルが次のリクエストで消えている | Workersの /tmp はリクエストごとに別 |
Durable Objects、D1、R2を使う |
| 一部のクライアントでfilesystemサーバーがすべてのパスを拒否する | 2026-07-28のクライアントはRootsを送れず、ディレクトリ引数もない | マウントしたディレクトリをコマンドライン引数で渡す |
12. NodeFlareならこう解決できる
NodeFlareは、GitHubリポジトリのMCPサーバー(stdio専用のものも含む)をHTTPSのエンドポイントとしてデプロイするMCPホスティングサービスです。この記事で挙げた課題に、次のように対応しています。
| この記事の課題 | NodeFlareでの対応 |
|---|---|
| スケールトゥゼロ・再デプロイ・再起動でデータが消える | 既定のファイルシステムは一時的です。オプションの永続ディスクは、スケールトゥゼロのスナップショット、再デプロイ、VMの再起動のあとも残ります。必要な分だけ確保され、容量の上限は自分で決められます |
| 1つのファイルやSQLiteに2つの書き込み手 | 永続ディスク付きのサーバーは1台のVMで動き、並列のフォークを作りません。ドキュメントによると、これでディスクのスプリットブレインを防いでいます |
| 状態ありブリッジがセッションごとにプロセスを起動する | 同梱の stdio-adapter.cjs がサーバーを1つの子プロセスとして動かし、リクエストIDを付け替えて同時接続のクライアントで共有します。落ちた場合は1秒から30秒のバックオフで再起動します |
MEMORY_FILE_PATH や --db-path の設定 |
環境変数は暗号化して保存され、VMの起動時に注入されます。起動コマンドを明示すると自動検出より優先されるので、オプションを正確に指定できます |
| ストレージのエラーとツールの不具合の切り分け | リクエストログに tool_name、outcome、http_status、duration_ms、error_message が残り、ツール名やエラーで検索できます。保存期間はFreeが7日、ProとTeamが30日です |
| 1日の大半はアイドルな、状態ありサーバーの費用 | アイドルが数分続くとスナップショットを取って停止し、停止中のコンピュート料金はかかりません。次のリクエストで1秒未満で復元します |
使う前に知っておきたい点です。
- 永続ディスクはPro以上の機能です。Freeのストレージは一時的なので、memoryやSQLiteのサーバーはスケールトゥゼロのたびに空に戻ります。Freeはサーバーの動作確認に使い、データの保管には使わないでください。
- ディスクの料金は1GBあたり月¥15で、ディスクが存在する間はサーバーの停止中も課金されます。ProとTeamには10GBのストレージが含まれます。
- マウントパスは公開されていません。ドキュメントでは永続ディスクをホスト側のoverlayの上位層と説明しており、パスの記載はありません。
MEMORY_FILE_PATHや--db-pathは絶対パスで指定し、再デプロイ後もデータが残ることを確かめてください。 - 複数レプリカでデータを共有したい場合は、ここでもDBが必要です。書き込み手が1つという制約は変わりません。
料金:Freeは¥0で、MCPサーバー1つと月30GB時間のコンピュート。Proは月¥2,980で、サーバー数無制限、300GB時間のコンピュートと10GBのストレージを含み、超過分のコンピュートは1GB時間あたり¥5です。
最小の始め方:
- nodeflare.techにGitHubでサインインし、MCPサーバーのリポジトリを選びます。
- Proで永続ディスクを追加し、サーバーの設定で
MEMORY_FILE_PATH(またはサーバーのパス指定)を入れてデプロイします。NodeFlareは実際にMCPのinitializeが通ることを確認してから公開します。 - 1件書き込み、再デプロイして、読み戻せることを確かめます。
1サーバーまで無料で試せます → nodeflare.tech
13. よくある質問
ホスティングしたMCPサーバーのデータが再起動で消えるのはなぜ?
コンテナ自身のファイルシステムに書いていて、多くのホスティング先はそれを再起動・再デプロイ・スケールトゥゼロで捨てるからです。Cloud Runのファイルシステムはメモリ上、Lambdaの /tmp は実行環境ごと、Workersの /tmp はリクエストごとです。サーバーの保存先を、マウントしたボリューム、永続ディスク、DBのいずれかに向けてください。
MCPのmemoryサーバーはデータをどこに保存している?
@modelcontextprotocol/server-memory 2.0.0 は、MEMORY_FILE_PATH を設定しない限り、自分のパッケージのディレクトリにある memory.jsonl にナレッジグラフを保存します。npx -y で起動した場合はnpxのキャッシュの中で、新しいコンテナにはそのキャッシュがありません。MEMORY_FILE_PATH を永続ストレージ上の絶対パスにしてください。
リモートのmemoryサーバーでMEMORY_FILE_PATHはどう設定する?
サーバーの環境変数として、たとえば MEMORY_FILE_PATH=/data/memory.jsonl を設定し、/data にボリュームをマウントします。相対パスは作業ディレクトリではなくパッケージのディレクトリ基準になるので、絶対パスにしてください。サーバーはそこにロックファイルと一時ファイルを作るため、ディレクトリが存在し、書き込める必要があります。
Dockerでマウントしたファイルに保存するとEBUSYになるのはなぜ?
memoryサーバーは一時ファイルを memory.jsonl に名前を付け替えて保存しますが、Linuxではファイル単体のバインドマウントに名前を付け替えられないからです。検証ではすべての書き込みが EBUSY: resource busy or locked, rename で失敗しました。ファイルではなく、それを含むディレクトリをマウントしてください。
SQLiteのMCPサーバーをCloud Runで動かせる?
既定のファイルシステムでは無理です。メモリ上にあり、インスタンスが止まると消えます。Cloud Storage FUSEのボリュームも、ファイルロックがなく最後の書き込みが勝つので向きません。本物のボリュームを付けられる1インスタンスのホストを使うか、クライアント/サーバー型のDBに切り替えてください。
SQLiteをNFSやネットワークボリュームに置いても大丈夫?
WALモードは、ネットワークファイルシステム上では動かないので使えません。書き込み手が複数の場合も危険です。SQLiteのドキュメントは、一部のネットワークファイルシステムではロックが正しく動かないことがあるとし、データとアプリがネットワークで隔てられるならクライアント/サーバー型DBを勧めています。1台のマシンに付けたブロックボリュームなら問題ありません。
状態を持つMCPサーバーを複数レプリカにできる?
データを共有のDBに置いている場合だけです。RailwayとRenderのボリュームは1インスタンスでしか使えず、SQLiteのファイルを複数のマシンで共有すべきではありません。ファイルに保存するサーバーは1インスタンスで動かすか、ユーザーごとにサーバーと保存先を分けてください。
Cloudflare WorkersにはMCPサーバー用のファイルシステムがある?
メモリ上の仮想ファイルシステムはありますが、/tmp はリクエストごとに別で、残りません。Workersで永続化するデータは、Durable Objects(ctx.storage.sql のSQLite API、1オブジェクト10GB)、D1、KV、R2に置きます。普通のディスクを前提にしたサーバーは書き直しが必要です。
すべてのMCPサーバーに永続ストレージが必要?
いいえ。GitHub、Slack、検索サービスのように外部APIを呼ぶだけのサーバーは、データを接続先に持っているので、一時的なファイルシステムで問題なく動きます。必要なのは、memory、メモ、SQLite、ファイル編集、保存したブラウザのログインのように、自分でデータを書くサーバーです。
ホスティングしたMCPサーバーのデータはどうバックアップする?
SQLiteなら sqlite3 app.db ".backup backup.db" か VACUUM INTO を使います。WALに残っている分も含めて取れます。memoryサーバーの memory.jsonl はアトミックに置き換えられるので、普通にコピーして構いません。コピーはボリュームの外に置き、データ形式が変わるデプロイの前にも取ってください。
まとめ
ホスティングしたMCPサーバーのデータは、置き場所を自分で決めない限り残りません。サーバーが書くパスをすべて洗い出し、絶対パスで明示し、ファイルではなくディレクトリをボリュームか永続ディスクにマウントして、1ファイルに書くのは1台だけにします。検証では、既定の npx 構成でmemoryサーバーのグラフが消え、ファイル単体のマウントではすべての書き込みが EBUSY で失敗し、SQLiteのファイル単体マウントではコミット済みの1,000行が消えました。3つともディレクトリのマウントで解決しました。レプリカが必要ならDBを使い、利用者が頼る前に「書く→再デプロイ→読む」で永続化を確かめてください。ファイルを書くサーバーに余計な場所へ触らせないための対策は、MCPサーバーのサンドボックス化で解説しています。
参考資料
- @modelcontextprotocol/server-memory(npm、README:MEMORY_FILE_PATH、ロック)
- modelcontextprotocol/servers(GitHub、memoryとfilesystemサーバー)
- SQLite: Write-Ahead Logging
- SQLite Over a Network, Caveats and Considerations
- Google Cloud Run: Container runtime contract(ファイルシステム)
- Google Cloud Run: Cloud Storage volume mounts
- AWS Lambda: Configure ephemeral storage
- Cloudflare Workers: node:fs
- Cloudflare Durable Objects: Limits
- Railway: Volumes reference
- Render: Persistent Disks
