Skip to content
speleoalexPublic

About

Turn a database connection into a read-only MCP server: introspect the schema, let an AI design the query tools, publish over Streamable HTTP or stdio. TypeScript, Next.js, Effect, Bun.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

mcp-forge

Turn a database connection into a read-only MCP server in minutes.

mcp-forge reads the structure of your database, asks an AI model to design a set of query tools for it, lets you review and switch each tool on or off, and publishes the result as an MCP server that Claude Code, Claude Desktop, Cursor or any other MCP client can use.

Built with TypeScript, Next.js, TanStack Query, Effect and Bun. MySQL / MariaDB and SQLite are supported today; other engines plug into the same driver interface.

⚠️ Early development: storage format and UI can still change.

The mcp-forge UI: database connection, introspected schema, AI-proposed query tools and the published MCP endpoint

How it works

  1. Connect – create a project with the connection settings of your database (use a read-only user).
  2. Introspect – tables, columns, keys, foreign keys and comments are read from the catalog. No data is read.
  3. Propose tools – the schema is sent to the AI model, which answers with parameterized SELECT statements, names, descriptions and typed parameters. An offline generator ("basic tools": lookups, listings, searches, counts) works without any API key.
  4. Curate – every tool is validated (single read-only statement, declared parameters match the SQL). Toggle, edit, test-run or delete tools, or write your own.
  5. Publish – the project gets an access token and its enabled tools are served over MCP. Changes to the tool list are live immediately.

Features

  • Read-only by construction: a SQL guard allows one SELECT/WITH statement and rejects DML, DDL, locking clauses, SELECT ... INTO, dangerous functions (SLEEP, LOAD_FILE, ...) and system schemas. Values are bound as parameters, never interpolated.
  • Bounded queries: a LIMIT is added when missing, results are truncated to MAX_ROWS, queries are cancelled after QUERY_TIMEOUT.
  • AI providers: Claude (Anthropic), OpenAI, or any OpenAI-compatible local server (llama.cpp, Ollama, LM Studio, vLLM, ...), selectable per request from the UI. Only the schema is sent, never data.
  • Two transports: stateless Streamable HTTP endpoint per project (/mcp/<project id>, bearer token) and a stdio command for clients that spawn local processes.
  • Schema as MCP resource: published servers expose schema://database.
  • Management UI in English and Italian, light and dark theme (follows the system), usable on phone and desktop.

Requirements

  • Bun 1.2 or newer (Linux, macOS, Windows)
  • A database: MySQL 5.7+/8.x or MariaDB 10.3+ (with a read-only user), or a SQLite file readable by the server
  • For AI proposals: an Anthropic API key, an OpenAI API key, or a local OpenAI-compatible server

Quick start

git clone https://github.com/speleoalex/mcp-forge.git
cd mcp-forge
bun install
cp .env.example .env        # set ANTHROPIC_API_KEY or OPENAI_API_KEY for AI proposals
bun run dev                 # http://127.0.0.1:3000

Open the UI, create a project, test the connection, introspect the schema, generate tools, publish. The Publish card shows ready-to-paste configuration for MCP clients.

Production build:

bun run build
bun run start               # http://127.0.0.1:3000

Both scripts bind to 127.0.0.1. To listen on another interface run bun --bun next start -H 0.0.0.0 and put authentication in front (see Security).

Docker

cp .env.example .env        # optional: AI provider settings, PUBLIC_BASE_URL, ...
docker compose up -d --build

The UI is reachable on http://127.0.0.1:3000. Projects live in the forge-data volume. PORT in .env selects the published port, PUBLIC_BASE_URL the address MCP clients will use.

  • Database on the Docker host: use host.docker.internal as database host (the database must accept connections from the Docker network).
  • stdio transport from the container: docker compose run --rm -T app bun src/cli/mcp-stdio.ts --project <project id>

Connecting MCP clients

Client How
Claude Code claude mcp add --transport http <name> http://127.0.0.1:3000/mcp/<project id> --header "Authorization: Bearer <token>"
HTTP clients (Claude Desktop connectors, Cursor, custom agents) {"mcpServers": {"<name>": {"type": "http", "url": "...", "headers": {"Authorization": "Bearer <token>"}}}}
stdio clients (claude_desktop_config.json) bun <path to>/src/cli/mcp-stdio.ts --project <project id> with DATA_DIR set to this installation's data directory

The UI generates all three snippets with the right values. The HTTP endpoint is stateless: each POST carries a complete JSON-RPC exchange and gets a JSON response; GET and DELETE return 405.

The stdio command can also be run by hand:

bun run mcp:stdio -- --project "Shop analytics"      # by name or id
bun run mcp:stdio -- --project <id> --allow-draft      # serve an unpublished project

Configuration

Settings are environment variables; .env in the project directory is read by Next.js and by Bun. Empty values count as unset, so the placeholders in .env.example can stay.

Variable Default Description
PORT 3000 Port of the HTTP server (UI, API and MCP endpoint)
PUBLIC_BASE_URL request origin Base URL written in client snippets; set it behind a reverse proxy
DATA_DIR ./data Where projects are stored as JSON documents
MAX_ROWS 200 Maximum rows returned by one tool call
QUERY_TIMEOUT 15 seconds Maximum duration of one query (Effect duration syntax)
MCP_REQUIRE_AUTH true Require Authorization: Bearer <project token> on the MCP endpoint
SQLITE_ROOT – When set, SQLite projects may only open database files inside this directory
AI_PROVIDER anthropic Provider preselected in the UI: anthropic or openai (the latter also for OpenAI-compatible servers). Both stay available
MAX_PROPOSED_TOOLS 25 Default upper bound of tools per proposal request
ANTHROPIC_API_KEY – Anthropic credential (sk-ant-...); ANTHROPIC_AUTH_TOKEN and ant auth login profiles also work
ANTHROPIC_MODEL claude-opus-5 Anthropic model used to propose tools
ANTHROPIC_SERVER_FALLBACKS true Server-side refusal fallbacks (fallbacks: "default")
OPENAI_API_KEY – OpenAI credential; optional for local servers
OPENAI_BASE_URL https://api.openai.com/v1 OpenAI-compatible endpoint, e.g. http://127.0.0.1:8080/v1
OPENAI_MODEL gpt-5.5 Model name as known to the endpoint (for Ollama the tag, e.g. qwen3:32b)
OPENAI_REASONING_EFFORT – none, minimal, low, medium, high, xhigh or max; sent only when set

Local OpenAI-compatible model

Any server implementing POST /v1/chat/completions works. A JSON-schema response_format is requested; if the server rejects it, one retry is made in json_object mode and the answer is validated locally either way. Nothing leaves your machine.

llama-server -m ./models/qwen3-32b-q4_k_m.gguf --port 8080 -c 32768
# .env
AI_PROVIDER=openai
OPENAI_BASE_URL=http://127.0.0.1:8080/v1
OPENAI_MODEL=qwen3-32b

Large schemas produce long prompts: give the server enough context and prefer models that follow JSON schemas reliably.

Security

mcp-forge is meant to run inside a trusted network by the person who owns the database credentials.

  • Use a read-only database user. The SQL guard is a second line of defence, not a replacement for privileges. SQLite files are always opened read-only, with extension loading disabled; set SQLITE_ROOT to confine projects to one directory.
  • Credentials are stored in DATA_DIR as JSON files with mode 0600. The password is never returned by the API.
  • The UI and REST API have no authentication. Keep the default 127.0.0.1 bind or put an authenticating reverse proxy in front.
  • MCP endpoints require a per-project bearer token unless MCP_REQUIRE_AUTH=false. Tokens can be rotated from the UI.
  • Only the schema is sent to the AI provider, and with a local server nothing leaves your machine. Tool execution never involves the AI.
  • AI output is validated, not trusted: non-SELECT statements, dangerous functions and mismatched parameters are rejected before a tool is saved and again at execution time.

Development

bun run dev          # UI + API + MCP endpoint with live reload
bun run typecheck    # tsc --noEmit
bun test             # unit tests
bun run build        # production build
bun run e2e          # end-to-end test against a MySQL seeded with scripts/e2e-seed.sql

Architecture, REST API and how to add a database engine or an AI provider: see CONTRIBUTING.md.

Roadmap

  • PostgreSQL driver
  • Optional authentication for the management UI
  • Encrypted credential storage
  • Per-tool usage statistics and query log

License

MIT

About

Turn a database connection into a read-only MCP server: introspect the schema, let an AI design the query tools, publish over Streamable HTTP or stdio. TypeScript, Next.js, Effect, Bun.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages