Skip to main content
@frontmcp/react/state bridges your application state with MCP. State slices become MCP resources that agents can read, and actions become MCP tools that agents can call.
import { useStoreResource, useReduxResource, useValtioResource } from '@frontmcp/react/state';

useStoreResource

The generic hook that works with any state management library. useReduxResource and useValtioResource are thin wrappers around it.
import { useStoreResource } from '@frontmcp/react/state';

function StoreProvider() {
  useStoreResource({
    name: 'app',
    getState: () => store.getState(),
    subscribe: (cb) => store.subscribe(cb),
    selectors: {
      count: (state) => (state as { count: number }).count,
      user: (state) => (state as { user: unknown }).user,
    },
    actions: {
      increment: () => store.dispatch({ type: 'INCREMENT' }),
      reset: () => store.dispatch({ type: 'RESET' }),
    },
  });

  return null;
}

What Gets Registered

MCP EntityURI / NameDescription
Resourcestate://{name}Full state snapshot
Resourcestate://{name}/{selectorKey}Each selector as a sub-resource
Tool{name}_{actionKey}Each action as a callable tool

Options

OptionTypeDefaultDescription
namestringRequired. Name prefix for resources and tools
getState() => unknownRequired. Returns current state snapshot
subscribe(cb: () => void) => () => voidRequired. Subscribe to changes, return unsubscribe
selectorsRecord<string, (state) => unknown>Named selectors, each becomes a sub-resource
actionsRecord<string, (...args) => unknown>Named actions, each becomes a tool
serverstringTarget a named server

Live Updates

When the store changes, the main resource’s read function automatically returns fresh state. The hook subscribes to your store and notifies the DynamicRegistry on every change so consumers re-read the latest value.

useReduxResource

A thin wrapper for Redux stores. Automatically binds getState, subscribe, and wraps action creators to auto-dispatch.
import { useReduxResource } from '@frontmcp/react/state';
import { store } from './store';
import { increment, addTodo } from './slices';

function ReduxBridge() {
  useReduxResource({
    store,
    name: 'redux',
    selectors: {
      todos: (state) => (state as { todos: unknown }).todos,
      count: (state) => (state as { counter: { value: number } }).counter.value,
    },
    actions: {
      increment: () => increment(),
      addTodo: (text: unknown) => addTodo(text as string),
    },
  });

  return null;
}

Options

OptionTypeDefaultDescription
store{ getState, dispatch, subscribe }Required. Redux store
namestring'redux'Name prefix
selectorsRecord<string, (state) => unknown>Named selectors
actionsRecord<string, (...args) => action>Action creators (auto-dispatched)
serverstringTarget a named server

useValtioResource

A thin wrapper for Valtio proxies. Supports deep path selectors with dot notation.
import { useValtioResource } from '@frontmcp/react/state';
import { subscribe } from 'valtio/utils';
import { state } from './store';

function ValtioBridge() {
  useValtioResource({
    proxy: state,
    subscribe,
    name: 'valtio',
    paths: {
      userName: 'user.profile.name',
      theme: 'settings.theme',
      cartCount: 'cart.items.length',
    },
    mutations: {
      setTheme: (theme: unknown) => {
        state.settings.theme = theme as string;
      },
      clearCart: () => {
        state.cart.items = [];
      },
    },
  });

  return null;
}

Options

OptionTypeDefaultDescription
proxyRecord<string, unknown>Required. Valtio proxy object
subscribe(proxy, cb) => () => voidRequired. Valtio’s subscribe function
namestring'valtio'Name prefix
pathsRecord<string, string>Deep path selectors (dot notation)
mutationsRecord<string, (...args) => void>Named mutations (each becomes a tool)
serverstringTarget a named server
You must pass valtio’s subscribe function yourself since valtio is an optional peer dependency. Import it from valtio/utils.

Provider-Level Store Adapters

Instead of using hooks inside components, you can register stores directly on the FrontMcpProvider via the stores prop. This is useful when you want store registration to happen once at the top level.
import { FrontMcpProvider, reduxStore, valtioStore, createStore } from '@frontmcp/react';

<FrontMcpProvider
  server={server}
  stores={[
    reduxStore({
      store: reduxStore,
      selectors: { count: (s) => s.count },
      actions: { increment: () => increment() },
    }),
    valtioStore({
      proxy: state,
      subscribe,
      paths: { userName: 'user.name' },
    }),
    createStore({
      name: 'custom',
      getState: () => customState,
      subscribe: (cb) => customSubscribe(cb),
    }),
  ]}
>
  <App />
</FrontMcpProvider>

reduxStore

Adapter factory for Redux stores. Wraps action creators to auto-dispatch.
import { reduxStore } from '@frontmcp/react/state';

reduxStore({
  store: myReduxStore,
  name: 'redux',                    // optional, defaults to 'redux'
  selectors: { count: (s) => s.counter.value },
  actions: { increment: () => increment() },
})
OptionTypeDefaultDescription
store{ getState, dispatch, subscribe }Required. Redux store
namestring'redux'Logical name
selectorsRecord<string, (state) => unknown>Named selectors
actionsRecord<string, (...args) => action>Action creators (auto-dispatched)

valtioStore

Adapter factory for Valtio proxies. Supports deep path selectors.
import { valtioStore } from '@frontmcp/react/state';
import { subscribe } from 'valtio/utils';

valtioStore({
  proxy: state,
  subscribe,
  name: 'valtio',                   // optional, defaults to 'valtio'
  paths: { userName: 'user.profile.name' },
  mutations: { setName: (name) => { state.user.profile.name = name; } },
})
OptionTypeDefaultDescription
proxyRecord<string, unknown>Required. Valtio proxy
subscribe(proxy, cb) => () => voidRequired. Valtio subscribe
namestring'valtio'Logical name
pathsRecord<string, string>Deep path selectors (dot notation)
mutationsRecord<string, (...args) => void>Named mutations

createStore

Generic pass-through adapter for any custom store.
import { createStore } from '@frontmcp/react/state';

createStore({
  name: 'myStore',
  getState: () => store.getState(),
  subscribe: (cb) => store.subscribe(cb),
  selectors: { count: (s) => s.count },
  actions: { reset: () => store.reset() },
})
OptionTypeDefaultDescription
namestringRequired. Logical name
getState() => unknownRequired. Returns state snapshot
subscribe(cb) => () => voidRequired. Subscribe to changes
selectorsRecord<string, (state) => unknown>Named selectors
actionsRecord<string, (...args) => unknown>Named actions

StoreAdapter Interface

All adapter factories return a StoreAdapter:
interface StoreAdapter {
  name: string;
  getState: () => unknown;
  subscribe: (cb: () => void) => () => void;
  selectors?: Record<string, (state: unknown) => unknown>;
  actions?: Record<string, (...args: unknown[]) => unknown>;
}
You can also create a StoreAdapter directly without using a factory.