@frontmcp/storage-sqlite

中文文档
1.12.2发布于 2026/11/15Apache-2.0TypeScriptESM + CJS构建来源已验证近 30 天下载 5337

SQLite storage for FrontMCP: sessions, background tasks, elicitations and stream events in a local file, without Redis

原始使用文档
文档目录11 节
  1. Install
  2. Usage
  3. Using a store directly
  4. Stores
  5. Options
  6. Operational notes
  7. In a Cloudflare Durable Object
  8. Docs
  9. Related packages
  10. Contributing
  11. License

@frontmcp/storage-sqlite

SQLite storage for FrontMCP: sessions, background tasks, pending elicitations and stream events in a local file, so they survive a restart without running Redis. Install it next to @frontmcp/sdk and set @FrontMcp({ sqlite }); the SDK loads it. Use it on one machine: local development, a single VM or container with a volume, a CLI or desktop server, or the cli task runner, whose worker processes share the file. When several machines must see the same state, use Redis instead: a SQLite file can't be shared across machines.

npm License

Install

npm install @frontmcp/storage-sqlite

Requires Node.js 24 or later. better-sqlite3 is a regular dependency, so it's installed with the package. It's a native module that downloads or compiles its binary at install time, so install on the platform the server runs on (in a Docker image, run npm ci inside the image). The peer dependency @frontmcp/lazy-zod comes with @frontmcp/sdk.

@frontmcp/sdk loads this package only when a sqlite option is set, so importing the SDK never loads better-sqlite3. On Cloudflare Workers the stores run in a Durable Object, on its own SQLite database: see In a Cloudflare Durable Object. Other V8-isolate runtimes have no SQLite; use Redis or Upstash there.

Usage

Most servers never import this package. Point FrontMCP at a file and the SDK builds the stores:

import { App, FrontMcp } from '@frontmcp/sdk';

@App({ id: 'help-desk', name: 'Help Desk', tools: [] })
class HelpDeskApp {}

@FrontMcp({
  info: { name: 'help-desk', version: '1.0.0' },
  apps: [HelpDeskApp],
  sqlite: { path: './data/desk.sqlite' },
})
export default class Server {}

The top-level sqlite block backs sessions, background tasks and pending elicitations. Without path, the file is <project>/dist/sessions.sqlite outside production and ~/.<info.name>/sessions.sqlite in production. FRONTMCP_SQLITE_PATH overrides both, and path too.

To give one subsystem its own file, set it there instead:

import { App, FrontMcp } from '@frontmcp/sdk';

@App({ id: 'help-desk', name: 'Help Desk', tools: [] })
class HelpDeskApp {}

@FrontMcp({
  info: { name: 'help-desk', version: '1.0.0' },
  apps: [HelpDeskApp],
  transport: { persistence: { sqlite: { path: './data/sessions.sqlite' } } },
  tasks: { enabled: true, runner: 'cli', sqlite: { path: './data/tasks.sqlite' } },
})
export default class Server {}

The cli task runner starts detached worker processes, so it needs a store they share: tasks.sqlite, a top-level sqlite, or tasks.redis.

Using a store directly

import { SqliteSessionStore } from '@frontmcp/storage-sqlite';

const store = new SqliteSessionStore({ path: './data/sessions.sqlite', defaultTtlMs: 3_600_000 });
await store.set('session-id', { userId: 'u1' }, 60 * 60_000); // TTL in milliseconds
const session = await store.get('session-id');
store.close();

Stores

ExportBacks
SqliteSessionStoreMCP transport sessions (keyPrefix, default 'mcp:session:'; defaultTtlMs, default 1 hour)
SqliteTaskStoreBackground tasks: status, outcome and cancellation
SqliteElicitationStorePending elicitation requests (keyPrefix, default 'mcp:elicit:')
SqliteEventStoreStream events for Streamable HTTP resumption (maxEvents, default 10000; ttlMs, default 5 minutes)
SqliteKvStoreA synchronous key/value store with TTL, which the stores above are built on
SqliteStorageAdapterThe async StorageAdapter interface of @frontmcp/utils over the same file (no publish/subscribe)

SqliteStorageAdapter.keys(pattern) and SqliteKvStore.keys(pattern) match letter case, as the memory and Redis storages do: keys('session:*') does not return Session:1. Up to 1.12.0 they ignored ASCII case, because they searched with SQL LIKE, and an adapter pattern lost its backslashes. In an adapter pattern a backslash makes the next character literal, as in the other storages, so escapeGlob() output finds the same keys everywhere; in 1.12.1 a backslash was matched as itself.

The package also exports openDatabase and withBusyRetry (helpers for opening a file and retrying on SQLITE_BUSY), useSqliteDriver and durableObjectSqlite (a SQLite other than better-sqlite3, below), deriveEncryptionKey, encryptValue, decryptValue and SqliteDecryptionError, and sqliteStorageOptionsSchema, the Zod schema for the options below.

Options

Every store takes these options, and so do @FrontMcp's sqlite, transport.persistence.sqlite and tasks.sqlite:

OptionDefaultNotes
pathrequiredThe database file. Its folder is created if it's missing. Optional in @FrontMcp({ sqlite }), as above
encryptionnone{ secret }: encrypt every stored value with AES-256-GCM, with a key derived from secret. Keys stay readable
walModetrueSQLite's write-ahead log, for readers that don't wait for writers
ttlCleanupIntervalMs60000How often expired entries are deleted
busyTimeoutMs5000How long a write waits for a lock another process holds before it fails with SQLITE_BUSY

A lost encryption.secret loses the data, and a changed one makes stored values unreadable (SqliteDecryptionError).

Operational notes

  • Back up the file. It's an ordinary SQLite database: copy it, or use sqlite3 .backup.
  • Write-ahead logging adds two files next to it, -wal and -shm. Copy all three, or checkpoint first.
  • One writer at a time. Several processes can read the file; writes wait for each other, up to busyTimeoutMs.

In a Cloudflare Durable Object

A Durable Object with SQLite storage has its own database, and the stores can run on it instead of better-sqlite3, which is a native module and doesn't load on Workers. Import this package in the Worker, hand it to the SDK, and set the driver in the Durable Object's constructor, before the server is created:

import { DurableObject } from 'cloudflare:workers';

import { FrontMcpInstance, registerOptionalModule } from '@frontmcp/sdk';
import * as storageSqlite from '@frontmcp/storage-sqlite';

registerOptionalModule('@frontmcp/storage-sqlite', storageSqlite);

export class HelpDeskServer extends DurableObject {
  private readonly handler: ReturnType<typeof FrontMcpInstance.createFetchHandler>;

  constructor(ctx: DurableObjectState, env: unknown) {
    super(ctx, env);
    storageSqlite.useSqliteDriver(storageSqlite.durableObjectSqlite(ctx.storage));
    this.handler = FrontMcpInstance.createFetchHandler({
      info: { name: 'help-desk', version: '1.0.0' },
      apps: [HelpDeskApp],
      events: { store: { sqlite: { path: 'help-desk.sqlite' } } },
    });
  }

  async fetch(request: Request): Promise<Response> {
    return (await this.handler)(request, this.ctx, this.env);
  }
}
  • registerOptionalModule() gives the SDK the package from the Worker's bundle: on Workers, require() can't reach a bundled module.
  • useSqliteDriver(durableObjectSqlite(ctx.storage)) makes every store open the Durable Object's database. createFetchHandler() builds the server on its first request, so the constructor is early enough. Each instance of the Durable Object sets its own driver, and a store never gets a connection that an earlier instance opened.
  • One instance per isolate. The driver is set for the whole isolate, so use it in a Durable Object class that has one instance (one id, as idFromName('main')). Instances with different ids can share an isolate, and each server opens its stores on its first request: the storage set last then opens every instance's stores, Cloudflare refuses the I/O (Cannot perform I/O on behalf of a different Durable Object), and the other instances' servers don't start.
  • Every path is the same database, the Durable Object's one. The option only names it, and no file or folder is created.
  • Writes run in ctx.storage.transactionSync(), and walMode and busyTimeoutMs do nothing: a Durable Object has one connection and refuses both pragmas.

useSqliteDriver() takes any function from a path to a database with the part of better-sqlite3's Database the stores call (the SqliteDriver and SqliteDatabase types), and useSqliteDriver(undefined) goes back to better-sqlite3. currentSqliteDriver() returns the driver that is set, if any; on an edge runtime the SDK opens a sqlite store only when one is.

Docs

  • SQLite: the sqlite option, where the file goes, what's stored, locking and encryption
  • Redis: the store to use when several machines share state
  • Background tasks: task runners and their stores
  • @frontmcp/sdk: the framework that loads this package for its sqlite options
  • @frontmcp/utils: the StorageAdapter interface SqliteStorageAdapter implements, and the other storage backends

Contributing

Source: libs/storage-sqlite. Issues and pull requests are welcome; see CONTRIBUTING.md.

License

Apache-2.0. See LICENSE.

版本与发布记录

@frontmcp/storage-sqlite 共发布 106 个版本,首次发布于 2026/02/14;过去 12 个月发布了 106 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.12.2latest2026/11/151 天前
1.12.12026/11/132 天前
1.12.02026/11/114 天前
1.12.0-rc.1rc2026/11/114 天前
1.11.32026/11/106 天前
1.11.22026/11/096 天前

其他发布通道:beta → 1.1.2-beta.1,rc → 1.12.0-rc.1。

关于 @frontmcp/storage-sqlite 的常见问题

@frontmcp/storage-sqlite 是什么?

SQLite storage for FrontMCP: sessions, background tasks, elicitations and stream events in a local file, without Redis

如何安装 @frontmcp/storage-sqlite?

在项目目录运行 npm install @frontmcp/storage-sqlite,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@frontmcp/lazy-zod(1.12.2)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@frontmcp/storage-sqlite 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@frontmcp/storage-sqlite 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@frontmcp/storage-sqlite 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@frontmcp/storage-sqlite 可以商用吗?

@frontmcp/storage-sqlite 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@frontmcp/storage-sqlite 的下载量有多少?

根据 npm 官方下载统计,@frontmcp/storage-sqlite 在 2026/10/16 – 2026/11/14 这 30 天内被下载 5,337 次,日均约 178 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@frontmcp/storage-sqlite 还在维护吗?

最新版本 1.12.2 发布于 2026/11/15(1 天前);至今共发布 106 个版本,其中过去 12 个月发布了 106 个;首次发布于 2026/02/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。