🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

sqemo-mcp

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sqemo-mcp

MCP server for Sqemo - query and edit ERDs with your team's naming standards

latest
Source
npmnpm
Version
1.5.0
Version published
Maintainers
1
Created
Source

sqemo-mcp

A local stdio MCP server that lets AI agents read and edit Sqemo ERDs. It works with both local .erd.json files and ERDs saved on the Sqemo server, and it can generate and check physical names against your team's word list and naming rules.

  • Node >= 22 (supabase-js requires native WebSocket — server tools and login do not work on Node 20)
  • Every local-file tool works without logging in. Only the server tools require login.

Install & register

Claude Code (.mcp.json)

{
  "mcpServers": {
    "sqemo": { "command": "npx", "args": ["-y", "sqemo-mcp"] }
  }
}

For local development (working from a checkout of this repository):

{
  "mcpServers": {
    "sqemo": { "command": "node", "args": ["./mcp/dist/index.js"] }
  }
}

Server tools (list_erds, etc.) need either a populated DEFAULT_SUPABASE_ANON_KEY in src/auth/defaults.ts or the ERDMAKER_SUPABASE_ANON_KEY environment variable (otherwise they return not_configured). Local-file tools work without any of this.

Claude Desktop

Add the same mcpServers entry to the config file. Claude Desktop has no project working directory, so use an absolute path instead of ./mcp/... when registering a local build.

  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

Codex CLI

codex mcp add sqemo -- npx -y sqemo-mcp

Or add the equivalent TOML to ~/.codex/config.toml:

[mcp_servers.sqemo]
command = "npx"
args = ["-y", "sqemo-mcp"]

Most other MCP clients (Cursor, etc.) use the same mcpServers JSON as Claude Code.

Login (for server ERDs)

npx sqemo-mcp login    # pick Google, GitHub, or email + password
npx sqemo-mcp logout   # remove stored credentials

login asks how you want to sign in. Options 1 and 2 (Google / GitHub) open a browser tab, complete a PKCE OAuth flow, and hand the session back through a one-shot loopback server on 127.0.0.1; option 3 takes an email and password in the terminal. Only a refresh token is ever stored.

Before the npm package is available (local development), use node mcp/dist/index.js login / logout.

  • Credentials are stored in ~/.erdmaker/credentials.json (mode 0600 on POSIX); your password itself is never stored.
  • Non-interactive shortcuts (no menu): --password forces the email + password path, --provider google|github forces a browser path.
  • Piped input skips the menu and goes straight to email + password, so existing automation keeps working: printf 'email\npassword\n' | npx sqemo-mcp login
  • The browser paths need a browser on the same machine (the callback returns to 127.0.0.1). Over SSH, use --password or the SQEMO_EMAIL / SQEMO_PASSWORD environment variables.

Environment variables

VariablePurpose
ERDMAKER_HOMEOverride the credentials directory (default ~/.erdmaker)
ERDMAKER_SUPABASE_URLOverride the Supabase URL (default: the Sqemo production server)
ERDMAKER_SUPABASE_ANON_KEYOverride the Supabase anon (publishable) key
ERDMAKER_MAX_REQUESTS_PER_MINUTEPer-minute cap on Supabase requests (default 120, 0 disables)
ERDMAKER_MAX_REQUESTS_PER_DAYDaily cap on Supabase requests (default 10000, 0 disables). Tracked in ERDMAKER_HOME/usage.json

If the connection settings are empty, server tools return a not_configured error.

The two caps are a safety net against an agent stuck in a loop flooding requests. When exceeded, tools fail with a rate_limited error that instructs the agent to stop and notify the user. For intentional bulk work, raise the caps via the environment variables above or set them to 0.

CLI (for CI pipelines)

Independent of the MCP server, two offline, file-based subcommands are available (no login required).

# Check naming standards — exits with code 1 on violations, failing CI
npx sqemo-mcp lint schema.erd.json

# Export the schema — result goes to stdout
npx sqemo-mcp export schema.erd.json --format sql --dialect postgres > schema.sql
npx sqemo-mcp export schema.erd.json --format dbml > schema.dbml
  • lint: checks logical names for unregistered words (missing from the word list) and physical-name drift (mismatch with the standard-generated name; manualOverride and FK columns excluded). Exit codes: 0 = clean, 1 = violations, 2 = argument/file error. Violations and the summary go to stderr. The unregistered-word check only runs when namingRules.unknownWordMode === "warn"; projects set to keep/romanize do not flag unregistered words.
  • export: --format sql|dbml (default sql); for sql, pick a dialect with --dialect (defaults to the project dialect). Output on stdout, errors on stderr (exit code 2).

GitHub Actions example:

- run: npx sqemo-mcp lint schema.erd.json

Drift check in CI (Pro)

# .github/workflows/schema-drift.yml
- run: npx sqemo-mcp lint erd/app.erd.json --db "$DATABASE_URL" --ignore "flyway_*"
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}   # read-only account recommended
    SQEMO_EMAIL: ${{ secrets.SQEMO_EMAIL }}     # Sqemo Pro account (password sign-in;
    SQEMO_PASSWORD: ${{ secrets.SQEMO_PASSWORD }} # OAuth-only accounts: set a password first)

No database credentials ever reach Sqemo servers — introspection runs inside your CI job and queries only information_schema. Prefer zero credentials in CI? Compare against a dump instead: npx sqemo-mcp lint erd/app.erd.json --schema schema.sql --dialect postgres.

The source parameter

Most read/write tools take the target ERD as source — specify exactly one of the two (passing both is rejected at the schema level).

  • { "file": "C:/path/to/model.erd.json" } — a local file
  • { "erdId": "<uuid>" } — a server ERD (get ids from list_erds)

Exception: the three dictionary lookup tools (search_dictionary · check_naming · generate_physical_name) also accept { "workspaceId": "<uuid>" } — they check against the latest workspace-standard master (word list + naming rules), not a project's cached copy. Get ids from list_workspaces. Write tools do not accept the workspaceId source (lookup only).

diff_erds additionally accepts {sql, dialect?} and {dbml} text sources for before/after — useful as a dry run before a full-replace import_sql/import_dbml.

Workspace standard lookup

You can query and check your team's naming standard directly, without a project:

list_workspaces
→ [{ "workspaceId": "…", "name": "Our Team", "role": "owner",
     "glossary": { "version": 7, "updatedAt": "…" } }]

check_naming { source: { workspaceId: "…" }, logicalName: "member number" }
→ checked against the latest workspace-standard master (not a project cache)

glossary: null means the workspace has no standard yet (create one by linking a standard in the web app). Editing the standard master directly is not supported, but you can request new words through the proposal queue: submit with propose_dictionary_word → the owner approves/rejects in the web app → check status with list_proposals, withdraw with withdraw_proposal. Proposal sources accept {workspaceId} or a standard-linked ERD ({file}/{erdId}). Submitting and listing proposals is workspace-member only — a shared editor of a standard-linked ERD who is not a member gets no_permission.

Tools (36)

Read

ToolDescription
list_erdsList server ERDs (role: owner/editor, shared). Owner and shared editors can both write. Requires login
list_workspacesList my workspaces (owner first) + whether a standard (word list + naming rules) exists. Requires login
get_erd_overviewName, dialect, entity/relationship/domain/word-list stats, subject areas, standard link status
list_entitiesList entities (logical name, physical name, attribute count)
get_entityEntity detail (attributes, keys, domains, logical/physical mapping). Prefers entityId; falls back to exact logicalName match
list_relationshipsList relationships (endpoint entity names, cardinality, identifying flag)
list_domainsList domain definitions (name, data type). Accepts the {workspaceId} source (standard domain dictionary)
search_dictionaryPartial-match word-list search (logical/physical/abbreviation/English/synonyms, max 50). Accepts {workspaceId}
check_namingCheck a logical name against the naming standard (+ optional physicalName comparison). Accepts {workspaceId}
generate_physical_nameLogical name → physical name (unregistered words reported in warnings). Accepts {workspaceId}
export_sqlGenerate CREATE TABLE SQL — 7 dialects (mysql/postgres/cubrid/oracle/sqlserver/sqlite/h2)
export_dbmlGenerate DBML text
validate_erdValidate the project ({ valid, errors })
lint_erdFull project lint — structure (PK, attributes, descriptions, domains), referential integrity, duplicate physical names, naming standard (unregistered words, drift)
diff_erdsCompare two sources (unchanged omitted) — before/after each accept {file}, {erdId}, {sql, dialect?}, {dbml}. Dry run before imports. Summary is entity-based
check_db_driftCheck drift between the ERD and a live database or schema dump (Pro)
list_proposalsList the workspace-standard proposal queue (word/domain, mine flag, status filter). Requires login

Write

ToolDescription
create_erdCreate a new ERD, empty or from SQL/DBML text — target: {file} or {server:true}; a given dialect becomes the project dialect
upsert_entity / delete_entityCreate/update/delete entities (physical table and name derived automatically)
upsert_attribute / delete_attributeEdit attributes — setting PK forces nullable=false and propagates to child FKs; with a domain, the domain decides the data type
upsert_relationship / delete_relationshipEdit relationships (FKs derived automatically; specify cardinality or ends; onDelete/onUpdate referential actions and constraintName supported — noAction/empty string revert to defaults)
upsert_domain / delete_domainEdit domain definitions (existing description preserved when omitted)
upsert_dictionary_word / delete_dictionary_wordEdit the word list — rejected for standard-linked (glossaryLink) dictionaries
update_naming_rulesPartially edit naming rules (delimiter, case, unknown-word handling). Existing physical names are not regenerated retroactively (noted in warnings). Rejected for standard-linked ERDs
import_sql / import_dbmlFully replace an existing ERD with the parse result (ids preserved). Rejected when zero tables
introspect_dbImport a live PostgreSQL/MySQL schema into an ERD (read-only, Pro)
auto_layoutAuto-arrange entities/tables (dagre) — view: logical/physical/both (default). Reference copies, notes, and waypoints preserved
propose_dictionary_wordPropose a word for the standard's word list (owner approves in the web app). Duplicates: already_exists / already_proposed
withdraw_proposalWithdraw your own pending proposal (others' or processed ones: not_found)

Server write rules

Writing to a server ERD is allowed for the owner or a shared editor. Concurrent saves on shared ERDs go through CAS 3-way auto-merge; merge conflicts return save_conflict. Saves are protected by a version CAS — if another session saved first, save_conflict is returned. Standard-linked dictionaries stay locked to the standard master (dictionary_is_linked). When an auto-merge pulls in another session's word list changes, write-tool results include a note in warnings (e.g. existing physical names are not regenerated automatically). Every write-tool result always includes warnings: string[].

Error codes

Every tool error is returned as { code, message } — handle errors by code.

codeMeaning
not_configuredSupabase connection settings missing
not_authenticatedLogin required (npx sqemo-mcp login)
no_permissionWrite attempted on a server ERD where you are neither owner nor shared editor
save_conflictVersion CAS conflict — re-fetch and retry
not_foundTarget (file/ERD/entity/attribute/…) not found
dictionary_is_linkedAttempted to edit a standard-linked dictionary
invalid_project_fileNot a valid .erd.json
validation_failedProject/input validation failed
unsupported_dialectUnsupported SQL dialect
invalid_sourceInvalid source/input combination (empty SQL, zero-table import, …)
already_existsThe proposed word is already in the standard word list
already_proposedA pending proposal for the same word already exists
plan_limit_exceededPlan quantity limit reached (cloud projects, snapshots, members, …) or a Team-only feature
rate_limitedRequests exceeded the per-minute/daily cap — the agent may be stuck in a loop; stop and notify the user. For intentional bulk work, adjust the caps via environment variables
internal_errorUnexpected internal failure (anything not covered above)

Development

cd mcp
npm install
npm test        # vitest
npm run lint    # tsc --noEmit
npm run build   # tsup → dist/index.js

Keywords

sqemo

FAQs

Package last updated on 30 Jul 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts