Skip to content

MCP integration

LiveStore includes MCP (Model Context Protocol) integration that allows AI assistants like Claude to access LiveStore documentation, examples, and development tools.

For installation and general CLI usage, see the LiveStore CLI documentation.

MCP (Model Context Protocol) is a standard for providing AI assistants with access to external resources and tools. LiveStore’s MCP server gives AI assistants access to:

  • LiveStore documentation and guides
  • Schema examples for common app types
  • Development tools and utilities

Start the MCP server:

Terminal window
bunx @livestore/cli mcp

Starts an AI coaching assistant with access to LiveStore documentation and best practices.

Provides development tools and utilities for working with LiveStore projects.

  • livestore_instance_connect

    • Connects a single in-process LiveStore instance by dynamically importing a module that exports schema and a syncBackend factory (and optionally syncPayload).

    • Notes:

      • Only one instance can be active at a time; connecting again shuts down and replaces the previous instance.
      • Reconnecting creates a fresh, in-memory client database. The visible state is populated by your backend’s initial sync. Until sync completes, queries may return empty or partial results.
    • Module contract (generic example):

      import {
      const makeWsSync: (options: WsSyncOptions) => SyncBackendConstructor<SyncMetadata>

      Creates a sync backend that uses WebSocket to communicate with the sync backend.

      @example

      import { makeWsSync } from '@livestore/sync-cf/client'
      const syncBackend = makeWsSync({ url: 'wss://sync.example.com' })

      makeWsSync
      } from '@livestore/sync-cf/client'
      export {
      export schema
      schema
      } from './schema.ts'
      export const
      const syncBackend: SyncBackendConstructor<Struct.ReadonlySide<{
      readonly _tag: tag<"SyncMessage.SyncMetadata">;
      readonly createdAt: String;
      }, "Type">, Json>
      syncBackend
      =
      function makeWsSync(options: WsSyncOptions): SyncBackendConstructor<SyncMetadata>

      Creates a sync backend that uses WebSocket to communicate with the sync backend.

      @example

      import { makeWsSync } from '@livestore/sync-cf/client'
      const syncBackend = makeWsSync({ url: 'wss://sync.example.com' })

      makeWsSync
      ({
      WsSyncOptions.url: string

      URL of the sync backend

      The protocol can either http/https or ws/wss

      url
      :
      var process: NodeJS.Process
      process
      .
      NodeJS.Process.env: NodeJS.ProcessEnv

      The process.env property returns an object containing the user environment. See environ(7).

      An example of this object looks like:

      {
      TERM: 'xterm-256color',
      SHELL: '/usr/local/bin/bash',
      USER: 'maciej',
      PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
      PWD: '/Users/maciej',
      EDITOR: 'vim',
      SHLVL: '1',
      HOME: '/Users/maciej',
      LOGNAME: 'maciej',
      _: '/usr/local/bin/node'
      }

      It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other Worker threads. In other words, the following example would not work:

      node -e 'process.env.foo = "bar"' &#x26;&#x26; echo $foo

      While the following will:

      import { env } from 'node:process';
      env.foo = 'bar';
      console.log(env.foo);

      Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.

      import { env } from 'node:process';
      env.test = null;
      console.log(env.test);
      // => 'null'
      env.test = undefined;
      console.log(env.test);
      // => 'undefined'

      Use delete to delete a property from process.env.

      import { env } from 'node:process';
      env.TEST = 1;
      delete env.TEST;
      console.log(env.TEST);
      // => undefined

      On Windows operating systems, environment variables are case-insensitive.

      import { env } from 'node:process';
      env.TEST = 1;
      console.log(env.test);
      // => 1

      Unless explicitly specified when creating a Worker instance, each Worker thread has its own copy of process.env, based on its parent thread's process.env, or whatever was specified as the env option to the Worker constructor. Changes to process.env will not be visible across Worker threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of process.env on a Worker instance operates in a case-sensitive manner unlike the main thread.

      @sincev0.1.27

      env
      .
      string | undefined
      LIVESTORE_SYNC_URL
      ?? 'ws://localhost:8787' })
      export const
      const syncPayload: {
      authToken: string;
      }
      syncPayload
      = {
      authToken: string
      authToken
      :
      var process: NodeJS.Process
      process
      .
      NodeJS.Process.env: NodeJS.ProcessEnv

      The process.env property returns an object containing the user environment. See environ(7).

      An example of this object looks like:

      {
      TERM: 'xterm-256color',
      SHELL: '/usr/local/bin/bash',
      USER: 'maciej',
      PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
      PWD: '/Users/maciej',
      EDITOR: 'vim',
      SHLVL: '1',
      HOME: '/Users/maciej',
      LOGNAME: 'maciej',
      _: '/usr/local/bin/node'
      }

      It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other Worker threads. In other words, the following example would not work:

      node -e 'process.env.foo = "bar"' &#x26;&#x26; echo $foo

      While the following will:

      import { env } from 'node:process';
      env.foo = 'bar';
      console.log(env.foo);

      Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.

      import { env } from 'node:process';
      env.test = null;
      console.log(env.test);
      // => 'null'
      env.test = undefined;
      console.log(env.test);
      // => 'undefined'

      Use delete to delete a property from process.env.

      import { env } from 'node:process';
      env.TEST = 1;
      delete env.TEST;
      console.log(env.TEST);
      // => undefined

      On Windows operating systems, environment variables are case-insensitive.

      import { env } from 'node:process';
      env.TEST = 1;
      console.log(env.test);
      // => 1

      Unless explicitly specified when creating a Worker instance, each Worker thread has its own copy of process.env, based on its parent thread's process.env, or whatever was specified as the env option to the Worker constructor. Changes to process.env will not be visible across Worker threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of process.env on a Worker instance operates in a case-sensitive manner unlike the main thread.

      @sincev0.1.27

      env
      .
      string | undefined
      LIVESTORE_SYNC_AUTH_TOKEN
      ?? 'insecure-token-change-me' }
    • Params example: { "configPath": "livestore-cli.config.ts", "storeId": "<store-id>" }

    • Returns example: { "storeId": "<store-id>", "clientId": "client-123", "sessionId": "session-abc", "schemaInfo": { "tableNames": ["..."], "eventNames": ["..."] } }

  • livestore_instance_query

    • Executes raw SQL against the client database (read-only).
    • Notes:
      • SQLite dialect; use valid SQLite syntax.
      • bindValues must be an array (positional ?) or a record (named $key). Do not pass stringified JSON.
    • Params example (positional): { "sql": "SELECT * FROM my_table WHERE userId = ?", "bindValues": ["u1"] }
    • Params example (named): { "sql": "SELECT * FROM my_table WHERE userId = $userId", "bindValues": { "userId": "u1" } }
    • Returns example: { "rows": [{ "col": "value" }], "rowCount": 1 }
  • livestore_instance_commit_events

    • Commits one or more events defined by your connected schema.
    • Notes:
      • Use the canonical event name declared in your schema (e.g., v1.EntityCreated).
      • args must be a non-stringified JSON object matching the event schema. Date fields typically accept ISO 8601 strings.
    • Params example: { "events": [{ "name": "v1.EntityCreated", "args": { "id": "e1", "title": "Hello", "createdAt": "2024-01-01T00:00:00.000Z" } }] }
    • Returns example: { "committed": 1 }
  • livestore_instance_status

    • Reports instance/runtime info.
    • Returns example (connected): { "_tag": "connected", "storeId": "<store-id>", "clientId": "client-123", "sessionId": "session-abc", "tableCounts": { "my_table": 12 } }
    • Returns example (not connected): { "_tag": "disconnected" }
  • livestore_instance_disconnect

    • Disconnects the current LiveStore instance and releases resources.
    • Returns: { "_tag": "disconnected" }

These tools connect directly to the sync backend (without creating a full LiveStore instance) to export or import events. Useful for backup, migration, and debugging.

  • livestore_sync_export

    • Exports all events from a sync backend to JSON data.
    • Notes:
      • Connects directly to the sync backend and pulls all events.
      • Returns the export data as a JSON object that can be saved or passed to import.
    • Params example: { "configPath": "livestore-cli.config.ts", "storeId": "my-store" }
    • Returns example: { "storeId": "my-store", "eventCount": 127, "exportedAt": "2024-01-15T10:30:00.000Z", "data": { "version": 1, "storeId": "my-store", "events": [...] } }
  • livestore_sync_import

    • Imports events from export data to a sync backend.
    • Notes:
      • The sync backend must be empty before importing.
      • Use force: true to import even if the store ID in the data doesn’t match.
      • Use dryRun: true to validate the import without actually importing.
    • Params example: { "configPath": "livestore-cli.config.ts", "storeId": "my-store", "data": { "version": 1, "storeId": "my-store", "events": [...] } }
    • Params with options: { "configPath": "...", "storeId": "...", "data": {...}, "force": true, "dryRun": true }
    • Returns example: { "storeId": "my-store", "eventCount": 127, "dryRun": false }

Run a local Cloudflare sync backend:

  1. Start the sync worker (wrangler):

    • cd tests/integration/src/tests/adapter-cloudflare/fixtures
    • wrangler dev
    • You should see an info page at http://localhost:8787/.
  2. Start the MCP server in another terminal:

    • bunx @livestore/cli mcp server
  3. From your MCP client (e.g., Claude Desktop), call tools:

    • Use your own config file path and storeId. The contrib repo provides an example: examples/cf-chat/livestore-cli.config.ts.
    • Connect: livestore_instance_connect with { "configPath": "livestore-cli.config.ts", "storeId": "<store-id>" }
    • Commit: livestore_instance_commit_events with [ { "name": "v1.EntityCreated", "args": { "id": "e1", "title": "Hello", "createdAt": "2024-01-01T00:00:00.000Z" } } ]
    • Query: livestore_instance_query with { "sql": "SELECT * FROM my_table ORDER BY createdAt DESC LIMIT 5" }
    • Status: livestore_instance_status
    • Disconnect: livestore_instance_disconnect

To use with Claude Desktop, add the MCP server to your Claude configuration:

{
"mcpServers": {
"livestore": {
"command": "bunx",
"args": ["@livestore/cli", "mcp"]
}
}
}

The MCP server provides access to:

  • Documentation: Overview, features, getting started guides
  • Architecture: Technical design and principles
  • Schema Examples: Pre-built schemas for todo, blog, e-commerce, and social apps
  • Development Tools: Project scaffolding and utilities

This enables AI assistants to provide context-aware help with LiveStore development.