MCP server + in-app HTTP bridge for Expo SQLite and Zustand — works with Cursor, Claude, OpenAI Codex (CLI + IDE), and any MCP client (dev-only)
Server has 9 tools with basic schemas and descriptions, but significant gaps limit production readiness. Tool names follow verb_noun convention (list_, sqlite_, zustand_) which is good. However, many parameter descriptions are null or missing entirely (sql, params, mode in sqlite_query; name, path, value, mode in zustand_set; action, args in zustand_call). Output schemas are not documented, responses are wrapped in {device, data} but the inner 'data' structure is never specified. Error handling is minimal: toolResult.ts shows only okText/errText with no recovery guidance or error classification. No tool annotations (readOnlyHint/destructiveHint) despite clear risk levels. Parameter descriptions average ~40 chars where baseline is 72 chars. Several tools lack actionable guidance on when to use them vs alternatives.
List Expo bridge targets (device id, platform, app name) from EXPO_STATE_MCP_BRIDGES / EXPO_STATE_MCP_BRIDGE_URL. Probes each URL via GET /device. Use refresh=true to re-fetch.
Describe columns for a SQLite table (PRAGMA table_info).
Run EXPLAIN QUERY PLAN for a SELECT-style statement.
List SQLite table names from the running app's database.
Execute SQL via the app's expo-sqlite connection (SELECT uses getAllAsync; writes use runAsync; multi-statement uses exec inside a transaction).
Call a synchronous method on the Zustand store snapshot (store.getState()[action](...args)). Async actions are rejected by the bridge.
Critical: Multiple parameters have null descriptions (sql, params, mode in sqlite_query; name, path, value, mode in zustand_set; action, args in zustand_call). LLMs cannot infer parameter meaning from names alone.
High: Output schemas are not documented. Tools return {device, data} but the inner 'data' structure is never specified. LLMs need to know what fields to expect in responses to plan downstream calls and extract the right data.
High: No tool annotations (readOnlyHint/destructiveHint/idempotentHint) despite clear risk levels. sqlite_query and zustand_set are marked WRITE but lack destructiveHint annotation. This prevents clients from warning users or restricting dangerous operations.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 52 | 2026-07-28+ | v2 |
Read Zustand state (optionally a dot-path). Functions omitted.
List registered Zustand store names exposed to the bridge.
Update Zustand state via setState — merge or replace at optional dot-path.
Medium: Error handling is minimal. toolResult.ts shows only okText/errText with no recovery guidance or error classification.
Medium: sqlite_query accepts 'mode' enum (auto|all|run|exec) but the description is null. LLMs cannot determine when to use each mode. Baseline param description length is 72 chars; most here are 0-40 chars.