mcp-business-data-server
Reads named ranges or A1 ranges from Google Sheets using a service account with read-only scope, allowing AI assistants to query spreadsheet data alongside database results.
Provides read-only access to PostgreSQL databases for answering business questions, with SQL guard validation, row and byte caps, pagination, timeouts, PII masking, and audit logging.
Provides read-only access to SQLite databases opened with mode=ro and query_only, enabling local or demo data querying with the same safeguards as the PostgreSQL integration.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-business-data-serverWhat were last month's top customers by revenue?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
๐ MCP Server โ secure AI access to Postgres & Google Sheets
A Model Context Protocol server that lets Claude, ChatGPT, Cursor or any MCP client answer questions about company data โ sales, customers, orders, spreadsheets โ without exporting files and without write access. Read-only by design (SQL guard + read-only DB role), with row limits, pagination, PII masking, bearer-token auth for remote use and a full audit log.

The problem
Managers want to ask "What were last month's top customers?" or "Which orders are late?" in plain English. Today that means CSV exports or giving an AI tool a production connection string. This server gives AI assistants a narrow, audited, read-only window into the data instead.
Related MCP server: db-connector
Tools, resources, prompts
Type | Name | What it does |
tool |
| allowed tables with row counts and descriptions (sensitive tables are hidden) |
tool |
| columns, types, PII flags, 3 masked sample rows |
tool |
| one |
tool |
| revenue / orders / AOV for a period ( |
tool |
| fuzzy search by name/company/email with lifetime revenue and last order |
tool |
| undelivered orders past their promised date, most overdue first |
tool |
| customers with no orders in N days (churn risk), by lifetime value |
tool |
| read a named range / A1 range from a Google Sheet (service account, read-only scope) |
resource |
| schema docs + business definitions (what "revenue" means) |
prompt |
| reusable analysis workflows |
All tools carry typed JSON input/output schemas and readOnlyHint annotations.
Security model (defense in depth)
SQL guard (sqlglot AST): exactly one statement; only
SELECT/set operations; rejects INSERT/UPDATE/DELETE/MERGE/DDL,SELECT โฆ INTO,FOR UPDATE,COPY,SET,PRAGMA,ATTACH, transactions, dangerous functions (pg_sleep,pg_read_file,load_extension,dblinkโฆ), system catalogs, and tables outsideALLOWED_TABLES.Read-only database: Postgres role
mcp_readonlywithSELECTgrants only (not onstaff_salaries) anddefault_transaction_read_only; every connection also runsBEGIN READ ONLY+statement_timeout. SQLite is opened withmode=ro+PRAGMA query_only. Tests bypass the guard on purpose to prove the DB still refuses.Result limits:
MAX_ROWS(500),MAX_RESULT_BYTES, pagination, query timeout.PII masking: configurable columns (
PII_COLUMNS=email,phone) are masked in every result (m***@example.com,***67); PII columns can't be wrapped in expressions/aliases to dodge the mask.PII_MASKING=offfor trusted users.Auth: Streamable HTTP requires
Authorization: Bearer <token>(per-user tokens, constant-time compare); optional DNS-rebinding protection viaMCP_ALLOWED_HOSTS.Audit log: every tool call โ JSONL with timestamp, user (token owner /
local-stdio), tool, arguments, status (ok/rejected/error), row count, duration.
Architecture
flowchart LR
C1[Claude Desktop / Claude Code] -- stdio --> S
C2[Cursor] -- stdio --> S
C3[ChatGPT connectors / remote agents] -- Streamable HTTP + Bearer --> AUTH[Bearer auth] --> S
subgraph S[MCP server ยท Python MCP SDK]
T[Tools ยท Resources ยท Prompts] --> G[SQL guard<br/>AST allow-list]
G --> LIM[Row/byte caps<br/>pagination ยท timeout]
LIM --> PII[PII masking]
T --> AUD[(Audit log JSONL)]
end
LIM -->|read-only role<br/>BEGIN READ ONLY| PG[(PostgreSQL / SQLite<br/>shop data)]
T -->|spreadsheets.readonly| GS[(Google Sheets<br/>SalesTargets)]Screenshots
|
|
|
|
|
|
|
|
Produced by scripts/demo_screenshots.py. Agent screenshots 05โ07 use a real LLM (Kimi K3 on Amazon Bedrock) via
scripts/ask_agent.py; 11 uses the offline scripted plan (the provider was rate-limiting at capture time) โ the
MCP calls, auth and audit entries are identical either way.
Quick start (local, SQLite, 2 minutes)
python -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt
python scripts/seed.py # data/shop.db with ~8k rows of fake data + data/sheets/SalesTargets.csv
npx @modelcontextprotocol/inspector --web $PWD/scripts/run_stdio.sh # poke at it in MCP Inspector
python scripts/ask_agent.py "Top 5 customers by revenue last month and who hasn't ordered in 60 days?"ask_agent.py is a tiny tool-calling agent (any OpenAI-compatible LLM via LLM_BASE_URL/LLM_API_KEY/LLM_MODEL;
scripted offline plan if unset) that prints each MCP tool call โ useful to demo the server without a desktop client.
Docker (Postgres + server)
docker compose up # Postgres 17 seeded + read-only role, MCP over HTTP on http://localhost:8000/mcpRemote (Streamable HTTP)
MCP_API_TOKENS="alice@acme:$(openssl rand -hex 24)" python -m bizdata_mcp.server --transport http --host 0.0.0.0 --port 8000Put it behind HTTPS (Caddy/nginx/Cloudflare Tunnel) and set MCP_ALLOWED_HOSTS.
Client configuration
Claude Desktop (claude_desktop_config.json) โ see docs/client-configs/claude_desktop_config.json:
{ "mcpServers": { "business-data": {
"command": "/ABSOLUTE/PATH/mcp-business-data-server/scripts/run_stdio.sh",
"env": { "DATABASE_URL": "postgresql://mcp_readonly:CHANGE_ME@localhost:5432/shop" } } } }Claude Code
claude mcp add business-data -e DATABASE_URL=sqlite:///$PWD/data/shop.db -- $PWD/scripts/run_stdio.sh
claude mcp add --transport http business-data https://mcp.example.com/mcp --header "Authorization: Bearer $MCP_TOKEN"Cursor (.cursor/mcp.json) โ see docs/client-configs/cursor_mcp.json.
ChatGPT โ add the HTTPS /mcp URL as a custom connector (developer mode) with the bearer token.
Google Sheets
Create a service account, download its JSON key, share the sheet with the service-account email as Viewer, then set
GOOGLE_APPLICATION_CREDENTIALS and SHEETS_SPREADSHEET_ID. Scope is spreadsheets.readonly. Without them the tool
reads data/sheets/<name>.csv (same shape) so the demo runs offline.
Acceptance criteria โ evidence
# | Criterion | Evidence |
1 | stdio + Streamable HTTP with bearer token |
|
2 | Rejects writes/DDL/multi-statements; DB read-only anyway |
|
3 | Descriptions + typed schemas; capped & paginated results |
|
4 | Configurable PII masking; audit log |
|
5 | Sheets named range |
|
6 |
|
|
7 | โฅ 15 tests in CI | 50 tests; |
8 | MCP Inspector screenshot | screenshots 01โ04 |
Tests
pytest -v # 49 tests (SQLite)
TEST_PG_ADMIN_URL=postgresql://postgres@localhost:5432/shop pytest -v # + Postgres read-only-role test
python scripts/demo_screenshots.py # scripted demo โ docs/screenshots/*.pngPortfolio write-up & demo video script
See PORTFOLIO.md.
License
MIT โ all data is fake.
This server cannot be deployed
Maintenance
Related MCP Connectors
Query your warehouse or a CSV with Claude/ChatGPT over MCP, governed by table-level ACL + audit.
Query 40 databases from Claude, ChatGPT, or Cursor โ on any device. Read-only, encrypted, audited.
Query your org's data in natural language โ read-only MCP access to SQL, NoSQL, files & warehouses.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Related MCP Servers
- FlicenseAqualityCmaintenanceEnables read-only exploration and querying of PostgreSQL or MySQL databases via MCP, with schema discovery, safe SQL validation, natural language to SQL conversion, and CSV export.111-
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to query business databases directly via natural language, with enforced read-only access and secure query limits. Supports SQLite and PostgreSQL, and works with any OpenAI-compatible model.0ISC
- AlicenseNot gradedqualityCmaintenanceEnables read-only, SELECT-only querying of any Postgres database through MCP-compatible clients like Claude, with schema introspection and guarded SQL execution.MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI assistants and MCP clients to ask natural-language questions about DuckDB or CSV data and receive safe, read-only SQL-generated tabular insights with automatic schema discovery and multi-table joins.-
MCP Inspector: typed, read-only tools
PII masked + pagination
Assistant asked to delete a table
Google Sheet targets vs DB actuals
Audit log
Remote HTTP with bearer token
50 tests incl. Postgres