Skip to main content

StackQL MCP Architecture

StackQL's MCP server is built into the engine binary and publishes the StackQL capability surface - discovery, description, validation, execution - as Model Context Protocol tools. Its design centers on three things: a small generic tool set instead of per-operation tools, a graduated safety contract for mutations, and an audit trail that records everything an agent does.

Transports and deployment modes

ModeCommandUse
stdiostackql mcp --mcp.server.type=stdioEditor-embedded clients (Claude Desktop, Cursor, Continue) that launch the process directly
HTTP (standalone)stackql mcp --mcp.server.type=httpLong-running server for standalone agents
Dual-server, in-memorystackql srv --mcp.server.type=http --pgsrv.port <port>MCP and PostgreSQL wire protocol from one process
Reverse proxystackql srv --mcp.server.type=reverse_proxyMCP requests dispatched to a backing StackQL Postgres server via DSN; supports workload separation and TLS

Configuration is a JSON (or YAML) object passed via --mcp.config, covering transport, address, TLS certificate paths, mode, audit settings, and optional enabled_tools / enabled_prompts allowlists for publishing a narrowed surface (for example, a read-only inventory server exposing only server_info and list_providers).

The tool surface

Thirteen tools, each returning a rendered text view for the LLM plus a typed structured payload:

  • Discovery: list_providers, list_services, list_resources, list_methods, describe_resource, describe_method - the hierarchy walk that reveals required WHERE parameters before any query is written.
  • Registry: list_registry (available providers and versions), pull_provider (install into the local cache).
  • Validation: validate_select_query - parse and plan a SELECT without executing.
  • Execution: run_select_query (reads), run_mutation_query (INSERT/UPDATE/REPLACE/DELETE - real side effects), run_lifecycle_operation (EXEC).
  • Identity: server_info - version, backend, registry, mode; called once at session start.

One static prompt, write_safe_select, teaches the method-discovery workflow.

The safety contract

server.mode selects one of four contracts; all allow SELECT and metadata, differing on writes:

ModeINSERT / UPDATE / REPLACEDELETEEXEC
read_onlyrefuserefuserefuse
safe (default)needs approvalneeds approvalneeds approval
delete_safeallowneeds approvalneeds approval
full_accessallowallowallow

"Needs approval" is implemented with MCP elicitation: the server sends the pending action - tool, query class, SQL - to the client, and a human accepts or declines. Clients that do not advertise elicitation get a refusal pointing the operator at full_access, which makes unattended mutation an explicit opt-in rather than a default. The mode is global per server; there are no per-tool overrides.

The audit subsystem

Every tool call writes one JSONL record - timestamp, tool, mode, decision (allow, refuse_immediate, needs_approval_accepted, and so on), query class, SQL, arguments, duration, error - to a file sink with size/age/backup rotation. The log answers "what did the agent do", deliberately not "what did the agent see": SELECT result rows are excluded as potentially large and sensitive. The write happens after execution but before the response returns; under the default strict failure mode, an audit failure on a successful mutation returns an error to the client - an intentional choice that no DELETE completes unaudited.