Skip to main content
Glama
Hqzdev

Lens-MCP

by Hqzdev
README.md
# Lens-MCP

Lens-MCP is a read-only Postgres MCP server that lets AI agents inspect and query approved database data safely.

The point is not to expose SQL over MCP. That is easy and dangerous. The point is to put a deliberate safety layer between the agent and Postgres: AST-based SQL validation, table allow-listing, enforced row limits, query timeouts, and a read-only database user.

## Scope

Lens-MCP provides four MCP tools:

- `list_tables`
- `describe_table(table_name)`
- `sample_table(table_name, limit)`
- `query(sql)`

The MVP uses stdio transport because it is the right default for local MCP clients such as Claude Desktop and Cursor. HTTP transport, hosted deployments, dashboards, and orchestration are intentionally out of scope until the local safety model is proven.

## Security Model

Lens-MCP uses defense in depth:

- Only single-statement `SELECT` queries are accepted.
- SQL is parsed with `sqlglot`; security does not rely on substring checks.
- Every referenced table must be present in `LENS_ALLOWED_TABLES`.
- Missing limits receive `LENS_DEFAULT_ROW_LIMIT`.
- Excessive limits are capped by `LENS_MAX_ROW_LIMIT`.
- Every database call applies `LENS_STATEMENT_TIMEOUT_MS`.
- The database connection should use a Postgres role with `SELECT` privileges only.

This does not make arbitrary databases safe by itself. It reduces the blast radius, but the Postgres role must still be read-only and the allow-list must exclude sensitive tables.

## Quick Start

Create a virtual environment and install the package:

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
```

Start the demo database:

```bash
docker compose -f infra/docker-compose.yml up -d
```

Export local settings:

```bash
export LENS_DATABASE_URL="postgresql://lens_readonly:lens_readonly@localhost:5432/lens_demo"
export LENS_ALLOWED_TABLES="public.customers,public.orders"
export LENS_DEFAULT_ROW_LIMIT="100"
export LENS_MAX_ROW_LIMIT="500"
export LENS_STATEMENT_TIMEOUT_MS="5000"
export LENS_SCHEMA_NAME="public"
```

Run the MCP server:

```bash
lens-mcp
```

## Claude Desktop

Use `examples/claude_desktop_config.json` as the starting point for local client configuration.

Useful smoke-test prompts:

- `List the tables available through Lens-MCP.`
- `Describe the customers table.`
- `Show two sample rows from orders.`
- `Run SELECT * FROM public.customers and tell me what limit was applied.`
- `Try to delete from public.customers and explain why the tool refused.`

## Configuration

| Variable | Purpose | Default |
| --- | --- | --- |
| `LENS_DATABASE_URL` | Postgres connection URL | empty |
| `LENS_ALLOWED_TABLES` | Comma-separated allow-list such as `public.customers,public.orders` | empty |
| `LENS_DEFAULT_ROW_LIMIT` | Limit added when a query has no limit | `100` |
| `LENS_MAX_ROW_LIMIT` | Maximum allowed limit | `1000` |
| `LENS_STATEMENT_TIMEOUT_MS` | Postgres statement timeout | `5000` |
| `LENS_SCHEMA_NAME` | Schema used by introspection and table samples | `public` |

Safe defaults are restrictive. If `LENS_ALLOWED_TABLES` is empty, database tables are not exposed.

## Development

```bash
ruff check .
mypy src tests
pytest
```

Run the optional live Postgres integration tests after starting Docker Compose:

```bash
LENS_INTEGRATION_DATABASE_URL="postgresql://lens_readonly:lens_readonly@localhost:5432/lens_demo" pytest tests/test_integration_postgres.py
```

## Project Judgment

Kubernetes, Terraform, service mesh, queues, and dashboards are not signs of professionalism for this project. Lens-MCP is a small stateless adapter over Postgres. The professional signal is a clean boundary between MCP protocol, security validation, data access, configuration, and tests that prove unsafe SQL cannot slip through.

TDQS

C2.1/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a distinct, clearly separate purpose: listing tables, describing schema, running queries, and sampling data. No overlap.

Naming Consistency4/5

Three tools follow 'verb_noun' pattern consistently; 'query' deviates slightly as a single verb, but this is acceptable for a common database command.

Tool Count5/5

Four tools is well-scoped for a database exploration server, covering core operations without excess.

Completeness4/5

The set covers essential data exploration operations (list, describe, sample, query). Missing write or administrative tools, but that fits the exploration focus.

Maintenance

ActivityInactive
ResponsivenessNo issues