Navigácia
ELOWEN · Dokumentácia

Posledná aktualizácia: 20. októbra 2026

Prechádzať dokumentáciu · MCP persistence

Tento článok zatiaľ nie je preložený. Je dostupný v angličtine.

Developer reference

MCP persistence

Schema and migrations

MCP uses the asynchronous PluginDb returned by await ctx.db(), with shared API 14. All plugin objects are explicitly qualified with the quoted db.schema, which is plugin_mcp. The schema owns servers, meta and oauth_pending; server and callback account references point to elowen.users.

The initial PostgreSQL migration creates the current layout directly at version 4. A fresh store records version 4 only, while existing stores keep their earlier ledger rows, which already cover versions 1 to 4, so the step is skipped there and every store stands at version 4: the next step is numbered 5. Server identifiers are bigint identities, returned by INSERT ... RETURNING id.

The host awaits the entry point's canonical migrate(db) export before calling register(ctx) during daemon loading. The export uses only PluginDb's transactional migration runner and never imports runtime configuration; the host binding it receives throws on any store access. A migration failure prevents registration. Registration consumes the migrated database and awaits the atomic configuration import before loading server specifications in one query. Direct fixtures await migrate(db) before registration. The import claims legacy_config_imported with ON CONFLICT DO NOTHING RETURNING inside the same transaction as all imported rows. Concurrent initializers cannot publish a marker without its servers, and a failed import rolls both back.

Registration and tool order

Specifications are ordered with instance servers first, then account id and the binary server name order. Connection discovery can finish in any order, but registration sorts the collected tools by owner and then by the namespaced tool name, so the composed tool order never follows connect latency. Inherited instance snapshots retain their own registration order; personal and managed-project definitions come from the persisted cache. Tool cache writes finish before connection state, cached definitions or reload decisions are published. Null instance ownership uses IS NOT DISTINCT FROM for every scoped update and delete.

OAuth credentials and callbacks

OAuth credential bag reads, writes and authority checks are awaited. The existing host credential lock spans refresh and management writes, including external OAuth requests. Management finishes its database operation before releasing the lock or republishing retained credentials. Callback state is claimed by one DELETE ... RETURNING statement before account, expiry and revision checks, so concurrent callbacks cannot exchange the same authorization code twice.

OAuth tokens remain in the host's encrypted instance or account secret namespace. They never enter server specifications, tool snapshots, diagnostics or public projections. Native provider response bodies are replaced with the existing safe phase and HTTP-status errors.

Focused test suites

Run npx vitest run tests/plugins/mcpPlugin.test.ts tests/plugins/mcpOAuth.test.ts --maxWorkers=2 inside the repository's required isolation boundary. Both suites open a real PostgreSQL database through coreOptions() in packages/db/tests/core/fixture.ts and build the plugin adapter with createPluginDb(database, 'mcp', dbOnlyHost), whose host stores throw rather than answer (plugins/sandbox/tests/db.ts). Each fixture derives its vault key path from the connection URL, allows key initialization, awaits migrate(db) before registration, and closes every database handle in afterEach. The OAuth runner fixture spawns a child process against the same database and the same vault key file with initialization refused (allowKeyInitialization: false).