Skip to main content
Glama
CoraDB MCP Server

CoraDB MCP Server

Official
by apsisware

CoraDB MCP Server

An MCP server for CoraDB. Any MCP client — an AI app such as Claude, an IDE, a script or another program — can use it to read a database's schema, run SELECTs (relational and SELECT … FROM MATCH graph queries) and run other statements, and get back exactly what the engine returns.

  • Stateless. Every call names its database and carries its own login. The server opens a connection for the call, runs it, commits or rolls back, closes the connection and forgets the login. Nothing is kept between calls: no connection, no session, no password.

  • One transaction per call. All statements of a call succeed and are committed together, or nothing is saved.

  • The server setting has the last word. CORADB_WRITE_MODE decides whether changes can be saved at all; a call can only be stricter.

Quick start

Needs Node.js 20.6 or later and a running CoraDB. Nothing to install by hand: MCP clients start the server with npx, which downloads @coradb/coradb-mcp-server from npm the first time.

For the Claude desktop app: Settings → Developer → Edit Config, add this to mcpServers, then quit the app completely and reopen it:

"coradb": {
  "command": "npx",
  "args": ["-y", "@coradb/coradb-mcp-server"]
}

Then call a tool, for example execute_select with { "database": "e-commerce", "sql": "SELECT COUNT(*) FROM orders" }, or ask the AI in plain words: "How many orders are in e-commerce?"

After the server is updated, restart the client and start a new conversation: a conversation keeps the tool definitions it started with.

Contents: Quick start · How a call works · Tools · Transactions and write mode · Results · Using it from an AI app · Calling it directly · Settings · Installing and updating · Security · Development

Related MCP server: 多数据库 MCP Server

How a call works

Every database tool takes these login inputs:

Input

Required

Default

database

yes

—

host

no

CORADB_HOST setting, else localhost

port

no

CORADB_PORT setting, else 33000

user

no

dba

password

no

empty

Only host and port can be changed in the settings. Users and passwords are never stored by the server: a call that needs another user sends it.

For each call the server:

  1. connects to the broker at host:port and logs in to database as user;

  2. runs the statements one after the other, in one transaction (auto-commit is off);

  3. commits, if the call may commit and every statement succeeded — otherwise rolls back;

  4. closes the connection and drops the login.

Several databases, servers or users are simply different calls. If the connection breaks, times out or the server stops part-way, CoraDB rolls back whatever was not committed.

Tools

Tool

What it does

Changes data

connection_info

Logs in and reports the login, engine version and server settings

no

describe_schema

Tables, views, vertex and edge tables with columns, keys, indexes

no

execute_select

Runs SELECTs and returns columns and rows

never

execute_sql

Runs any statements; commits when all succeed, unless dryRun

yes

explain_query

The optimizer's plan for a SELECT, without running it

no

Inputs are strict: an input a tool does not know is refused (Unrecognized key) instead of being ignored, so a client with an outdated copy of a tool's definition finds out instead of being misunderstood.

All tools that take SQL accept several statements separated by ;. They run in order and the first error stops the call (later statements are reported as skipped). A ; inside a string, a quoted name or a comment does not split. If where a statement ends depends on server settings (for example a backslash before a quote), the call is refused: send the statements one per call.

connection_info

Logs in and reports the login used (user@host:port/database, never the password), the engine version, the round-trip time, the driver in use (version, folder, when it was loaded, how many times it was reloaded), the server's defaults, write mode and limits. Use it to check that a database is reachable.

{ "database": "e-commerce" }

describe_schema

The objects of the database as the given user sees them, read from the live catalog: tables, views, vertex (node) tables and edge tables, with columns, types, nullability, defaults, primary and foreign keys and indexes.

Input

login inputs

see above

object

one table, view, vertex or edge table (case-insensitive)

format

text (default, CREATE-like) or json (the CoraDB schema document)

refresh

true to read the catalog again instead of the copy kept for CORADB_SCHEMA_TTL_MS

{ "database": "e-commerce", "object": "product" }
VERTEX TABLE DBA.product
  id INTEGER NOT NULL
  name VARCHAR(64) NOT NULL
  description VARCHAR(32) NOT NULL
  unit_price NUMERIC(10,2) NOT NULL
  units_in_stock SHORT NOT NULL
  PRIMARY KEY (id)

A kept copy is only handed out after the call's login succeeds.

execute_select

Runs one or more SELECTs and returns the columns and rows as the engine sends them. Each statement is first compiled by the server and refused, before anything runs, unless it is a SELECT. Nothing is ever committed.

Input

sql

one or more SELECT statements separated by ;

login inputs

see above

maxRows

rows returned per SELECT (default CORADB_MAX_ROWS, 200); totalRows still gives the full count

timeoutMs

time limit for the whole call (default CORADB_CALL_TIMEOUT_MS)

params

values for ? placeholders (single statement only)

{
  "database": "e-commerce",
  "sql": "SELECT c.name, COUNT(p) AS products FROM MATCH (p:product)-[:part_of]->(c:category) GROUP BY c.name ORDER BY products DESC LIMIT 3"
}
{
"login": "dba@localhost:33000/e-commerce",
"transaction": "rolled back",
"rolledBackBecause": "execute_select only reads",
"elapsedMs": 16,
"statements": [
{"statement":1,"sql":"SELECT c.name, COUNT(p) AS products FROM MATCH …","type":"SELECT","columns":[{"name":"c.name","type":"String","nullable":false,"precision":32,"scale":0},{"name":"products","type":"Int","nullable":false,"precision":10,"scale":0}],"totalRows":3,"truncated":false,"elapsedMs":15, "rows": [
  ["Hoodies & Sweatshirts",390],
  ["Tees",385],
  ["Jackets",362]
]}
]
}

execute_sql

Runs any statements — INSERT, UPDATE, DELETE, MERGE, CREATE, ALTER, DROP, SELECT … — in one transaction. Not offered when CORADB_WRITE_MODE=off.

Input

sql

one or more statements separated by ;

login inputs

see above

dryRun

true: run everything, then roll it back. Default false: commit when every statement succeeds

maxRows, timeoutMs, params

as for execute_select

{
  "database": "e-commerce",
  "sql": "UPDATE product SET units_in_stock = 40 WHERE id = 15"
}
{
"login": "dba@localhost:33000/e-commerce",
"transaction": "committed",
"elapsedMs": 21,
"statements": [
{"statement":1,"sql":"UPDATE product SET units_in_stock = 40 WHERE id = 15","type":"UPDATE","affectedRows":1,"elapsedMs":12}
]
}

The same call with "dryRun": true returns "transaction": "rolled back", "rolledBackBecause": "dryRun was requested" and still reports "affectedRows": 1: what would have changed. COMMIT and ROLLBACK statements are refused — the call controls the transaction. Serial increments (AUTO_INCREMENT, NEXT_VALUE) are not undone by a rollback; everything else, DDL included, is.

explain_query

The plan CoraDB's optimizer chooses for each SELECT of the call, without running it (statements other than SELECT are not explained).

{ "database": "e-commerce", "sql": "SELECT c.name FROM MATCH (p:product)-[:part_of]->(c:category)" }

Transactions and write mode

What happens at the end of an execute_sql call:

CORADB_WRITE_MODE

Call without dryRun (or false)

Call with dryRun: true

write (default)

committed if every statement succeeded, otherwise rolled back

rolled back

dryrun

rolled back; the reply says the server allows only dry runs

rolled back

off

no execute_sql tool

—

A call can only be stricter than the server, never less strict. If any statement fails, the time limit runs out or the call is cancelled, everything is rolled back. The reply's transaction says committed or rolled back, and rolledBackBecause says why.

Results

execute_select and execute_sql reply with one JSON document: the login, transaction, rolledBackBecause, stopped (error, timeout or cancelled, when the call stopped early), elapsedMs, and per statement: type (as the server compiled it), sql, columns (name, type, precision, scale, nullable, table), rows (one array per row), totalRows, truncated, affectedRows, error (code and message from the engine) or skipped.

Values: numbers, strings, null, booleans. DATE as YYYY-MM-DD, DATETIME as YYYY-MM-DD HH:MM:SS.mmm, TIMESTAMP as YYYY-MM-DD HH:MM:SS (the stored wall-clock time, no time-zone shift). NUMERIC values that do not fit a JavaScript number exactly come back as text. Binary values and graph objects the driver does not decode come back as hex. BLOB/CLOB show their type and length only. Strings longer than CORADB_MAX_CELL_CHARS are cut; rows beyond CORADB_MAX_RESPONSE_CHARS are left out and counted in rowsOmittedForSize.

A call that stops early, and any other failure, is returned as a tool error (isError: true): engine errors as CoraDB error <code>: <message>, an unreachable broker as Could not work with CoraDB at host:port ….

Time limits and cancelling. Every call has a time limit (timeoutMs, or CORADB_CALL_TIMEOUT_MS, at most CORADB_MAX_TIMEOUT_MS), also given to CoraDB as the statement's query timeout. When it runs out, or the client cancels the call (MCP notifications/cancelled), the running statement is cancelled on the server, the rest are skipped and everything is rolled back.

Using it from an AI app

Claude desktop app (and Cowork). Settings → Developer → Edit Config, add to mcpServers, then quit the app completely (also from the system tray) and start it again. Settings go in env; leave out the ones you do not change:

"coradb": {
  "command": "npx",
  "args": ["-y", "@coradb/coradb-mcp-server"],
  "env": { "CORADB_HOST": "localhost", "CORADB_PORT": "33000", "CORADB_WRITE_MODE": "write" }
}

If the app cannot start npx on Windows, use "command": "cmd", "args": ["/c", "npx", "-y", "@coradb/coradb-mcp-server"].

Claude Code:

claude mcp add coradb --scope user -- npx -y @coradb/coradb-mcp-server

Any other MCP client: run npx -y @coradb/coradb-mcp-server (or coradb-mcp-server after a global install) as a stdio server; settings go in its environment.

Ask in plain words; the AI turns the request into calls. For example:

You say

The AI calls

"How many orders were shipped in 2025?"

execute_select on e-commerce

"Set the stock of product 15 to 40."

execute_sql (committed)

"Check whether this update would work: …"

execute_sql with dryRun: true

"Is this query valid?"

explain_query (SELECT) or execute_sql with dryRun: true

"Run it on demodb as reader, password …"

the same tool with database, user, password

Calling it directly

The server speaks MCP (JSON-RPC 2.0) over stdin/stdout, one JSON message per line. A program starts it, initializes, and calls tools:

→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-app","version":"1.0"}}}
← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18","serverInfo":{"name":"coradb",…},…}}
→ {"jsonrpc":"2.0","method":"notifications/initialized"}
→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"execute_select","arguments":{"database":"e-commerce","sql":"SELECT COUNT(*) FROM orders"}}}
← {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\n\"login\": …"}]}}

With the MCP TypeScript SDK (Node.js):

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';

const client = new Client({ name: 'my-app', version: '1.0.0' });
await client.connect(new StdioClientTransport({
  command: 'npx',
  args: ['-y', '@coradb/coradb-mcp-server'],
}));

const r = await client.callTool({
  name: 'execute_sql',
  arguments: {
    database: 'e-commerce',
    user: 'dba',
    password: '',
    sql: 'UPDATE product SET units_in_stock = 40 WHERE id = 15',
    dryRun: true,
  },
});
const result = JSON.parse(r.content[0].text);   // { login, transaction, statements: [...] }
console.log(result.transaction, result.statements[0].affectedRows);

await client.close();

scripts/smoke.mjs and test/db/live.test.mjs in the source repository are complete examples.

Settings

Environment variables, from the env block of the client's configuration. When the server runs from a source checkout, they can also come from .env in its folder (.env.example, included in the package, lists them all); the environment wins over .env, and only CORADB_* variables are read from it. Restart the client after a change. connection_info shows which came from .env (names only).

Variable

Default

Meaning

CORADB_HOST

localhost

Broker host for calls that give none

CORADB_PORT

33000

Broker port for calls that give none

CORADB_DATABASES

*

Databases a call may name, comma-separated; * for any

CORADB_WRITE_MODE

write

write, dryrun or off (see above)

CORADB_MAX_ROWS

200

Rows per SELECT when the call does not say

CORADB_MAX_ROWS_LIMIT

5000

Most rows a call may ask for

CORADB_MAX_STATEMENTS

50

Most statements in one call

CORADB_CALL_TIMEOUT_MS

120000

A call's time limit when it gives none; 0 for none

CORADB_MAX_TIMEOUT_MS

600000

Longest time limit a call may ask for

CORADB_QUERY_TIMEOUT_MS

60000

Server-side limit per statement when the call has no limit

CORADB_CONNECT_TIMEOUT_MS

5000

How long to wait for the broker

CORADB_MAX_CELL_CHARS

20000

Longer strings in a cell are cut

CORADB_MAX_RESPONSE_CHARS

200000

Rows beyond this size are left out of a reply

CORADB_SCHEMA_TTL_MS

600000

How long a schema read from the catalog is kept

Installing and updating

  • With npx (recommended): nothing to install. npx downloads the package the first time and may keep using that copy; to always start the newest version use @coradb/coradb-mcp-server@latest in args, and to pin one, for example @coradb/coradb-mcp-server@1.0.0.

  • Global install: npm install -g @coradb/coradb-mcp-server, then use "command": "coradb-mcp-server" with no args. Update with npm update -g @coradb/coradb-mcp-server.

  • The CoraDB driver is the npm package @coradb/node-coradb, installed with the server. When its files change (an update), the server loads the new version before the next call, with no restart. If the new code does not load, the previous version keeps working and connection_info shows the error under driver.reloadError; connection_info also shows the driver's version, folder, load time and number of reloads.

Security

  • No stored logins. The server keeps no users or passwords, in files or in memory between calls; each call brings its own and it is dropped when the call ends. Replies and connection_info never show passwords.

  • The client holds the credentials. Whoever calls the server sends the password. When the caller is an AI app, the AI sees the password it sends.

  • CoraDB's rights apply. A call can do exactly what its user may do in that database. Use a user with only SELECT rights for reading.

  • Guards. execute_select and explain_query let the server compile each statement and refuse anything that is not a SELECT before it runs. COMMIT/ROLLBACK statements are refused. CORADB_WRITE_MODE=dryrun or off prevents saving whatever a call asks.

  • Local only. The server talks to its client over stdio on the same computer; it opens no network port of its own.

Development

git clone https://github.com/apsisware/coradb-mcp-server.git && cd coradb-mcp-server
npm install          # installs and builds dist/
npm test             # unit tests, no database needed
npm run test:db      # live tests against e-commerce on localhost:33000 as dba

To run a local build from a client, use "command": "node" with "args": ["<path to the checkout>/dist/index.js"].

Task

What it does

npm run build

Compiles src/ to dist/

npm test

Unit tests (test/*.test.mjs), no database; includes time-limit and cancel checks for every tool against a fake broker that never answers

npm run test:db

Live tests (test/db/) through the MCP protocol against a running CoraDB with the e-commerce dataset. Nothing is saved. Another login: CORADB_TEST_DATABASE, _HOST, _PORT, _USER, _PASSWORD

npm run smoke

Calls every tool once and prints the replies (SMOKE_DATABASE etc. to change the login; a query as argument)

npm publish

Builds and runs the unit tests first (prepublishOnly), then publishes dist/, README.md, LICENSE and .env.example

Files

File

src/index.ts

Starts the server (stdio)

src/tools.ts

The tools and their inputs

src/run.ts

Runs a call's statements: type checks, time limits, cancelling, commit or rollback, results

src/db.ts

Login resolution and the one-connection-per-call wrapper

src/driver.ts

Loads @coradb/node-coradb, and loads it again when its files change

src/config.ts

Settings and defaults

src/dotenv.ts

CORADB_* settings from .env

src/schema.ts, src/coradbSchema.ts

Reading and printing the schema

src/sqlText.ts

Splitting a script into statements

src/format.ts

Turning values into JSON

test/*.test.mjs

Unit tests (no database; limits.test.mjs uses a fake broker that never answers)

test/db/live.test.mjs

Live tests against e-commerce

scripts/smoke.mjs

npm run smoke

Available Tools

5 tools
connection_infoCoraDB connection infoA
Read-only

Log in to a CoraDB database and report the login used (never the password), the engine version and this server's settings. Use it to check that a database is reachable with a given login.

Inputs: database (required), host, port, user, +1 more.

describe_schemaDescribe the CoraDB schemaA
Read-only

The tables, views, vertex (node) tables and edge tables of a database with their columns, keys and indexes, read from the live catalog as the given user sees it. Give object for a single table. Read this before writing queries.

Inputs: database (required), host, port, user, +4 more.

execute_selectRun CoraDB SELECT statementsA
Read-only

Run one SELECT, or several separated by ;, and return the columns (name, type, precision, scale) and rows exactly as the engine returns them. Works for relational SQL and graph queries (SELECT … FROM MATCH …). Each statement is compiled first and refused unless it is a SELECT; nothing is ever committed. Statements run in order and the first error stops the script.

Inputs: sql (required), database (required), host, port, +5 more.

execute_sqlRun CoraDB statementsA
Destructive

Run any statements — INSERT, UPDATE, DELETE, MERGE, CREATE, ALTER, DROP, SELECT … — one or several separated by ;, in order, in one transaction. If every statement succeeds, the changes are committed; if any fails, nothing is saved. dryRun: true runs everything and then rolls it back, to see what would change. Returns the rows of each SELECT and the number of rows each other statement changed. COMMIT and ROLLBACK statements are refused: the call controls the transaction. Serial increments (AUTO_INCREMENT, NEXT_VALUE) are not undone by a rollback.

Inputs: sql (required), database (required), host, port, +6 more.

explain_queryShow a CoraDB query planA
Read-only

The plan the CoraDB optimizer chooses for a SELECT (or for each SELECT of a script separated by ;), without running it.

Inputs: sql (required), database (required), host, port, +2 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 5 tools

    Disambiguation5/5

    Each tool targets a distinct activity: connection verification, schema introspection, read-only querying, mutating/DDL execution, and plan inspection. The only potential overlap is that execute_sql can also run SELECTs, but its description explicitly frames it as the transactional read-write path while execute_select is the guarded read-only path. Boundaries are clear enough that misselection is unlikely.

    Naming Consistency4/5

    Four tools follow a clean verb_noun snake_case pattern (describe_schema, execute_select, execute_sql, explain_query). connection_info breaks the pattern as a noun phrase, a minor deviation but still unambiguous and readable.

    Tool Count5/5

    Five tools is a tight, well-scoped surface for a database MCP: connect, inspect, read, write, explain. Nothing feels redundant or missing at the count level.

    Completeness4/5

    The lifecycle is well covered: reachability check, live catalog introspection, read queries, transactional writes/DDL with dry-run, and plan explanation. Minor gaps exist around multi-database enumeration/switching and any explicit result-pagination or cancellation path, but agents can work around these.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Enables MCP clients to securely query databases, list tables, inspect table schemas, and test connections across Oracle, SQL Server, MySQL, PostgreSQL, and SQLite using read-only SQL tools.
      4
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables database querying and modification through an MCP server where each action is gated by human-granted scopes, per-call confirmations for destructive operations, and revocable access.
      MIT