Vizru MCP server
Click on "Install 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., "@Vizru MCP serverQuery EMP001 for employees in the Sales department"
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.
Vizru MCP server
Reads the PostgreSQL mirrors of Vizru spreadsheets on Neon, for the two workflow blocks that need relational access.
Block | Uses |
Relational Filter |
|
Agent Node |
|
Sys\Workflow\Block\McpClient in v1-web-app is the client. Its expectations are
the contract: HTTP basic auth, a bare JSON array of row objects from
/api/query, and a 200 with a JSON body from /api/schema. Anything else is
read by the caller as the service being unavailable.
POST /mcp offers the same two capabilities as MCP tools over JSON-RPC, for
clients that speak the protocol rather than REST.
Before you deploy: there is already an mcp-server
The vizru-docker compose project defines a service called mcp-server
(D:\Platform\Vizru-Docker\mcp-server, image mcp-server:5.1). It serves the
same two endpoints on 9101, plus write endpoints and an MCP SSE server on 9100,
and it points at a local mcp-postgres container rather than Neon.
Two containers cannot share a name, so decide which you are doing:
Replacing it — the clean blocks only ever read, so
/api/executeand the insert/update/delete/upsert endpoints have no caller left in the new code. Check nothing else uses them, and note that this service exposes MCP as JSON-RPC on9101/mcprather than SSE on9100; anything pointed at 9100 needs moving.Running both — set
MCP_CONTAINER_NAMEhere andMcpServerUrlinconfig/env-*.phpto the same new name.
Related MCP server: django-mcp-sql
Pointing the blocks at this server
Nothing to configure in the blocks themselves. McpClient falls back to
http://mcp-server:9101 with vizru / vizru_secret_key when the platform
defines no McpServerUrl / McpApiUser / McpApiSecret, and .env.example
ships those same values — so a container named mcp-server on the platform's
network is picked up by both blocks with no further wiring. Override all three
in config/env-*.php for production, keeping them in step with .env here.
Two prerequisites are outside this service and easy to miss:
The mirrors have to be in the database this service reads.
ss-sync-pipelinewrites them, and it points at whateverPG_HOSTit is given. If it still writes to the localmcp-postgreswhile this service reads Neon, every query finds noss_*tables and every schema lookup 404s.Nothing else may hold the
mcp-servercontainer name — see below.
Configuration
Copy .env.example to .env and fill it in. Two values have to agree with the
platform or every block call fails:
This service | Platform ( |
|
|
|
|
container name + |
|
McpServerUrl, McpApiUser and McpApiSecret are optional on the platform
side; leaving them undefined falls back to http://mcp-server:9101 with
vizru / vizru_secret_key. Set them in production.
Use Neon's pooled endpoint (the host containing -pooler). This service
holds a small pool of its own, and the direct endpoint has a lower connection
ceiling.
Run it
Option A — standalone
cp .env.example .env && docker compose up -d --buildIt joins the platform's existing network as an external one. Check it:
docker compose logs -f mcp-serverOption B — inside the platform's compose project
Drop the directory in next to the other services and add this to
Vizru-Docker/docker-compose.yaml, which matches the conventions there
(project-local network name, image tag variables, profiles, file secrets):
mcp-server:
restart: always
build:
context: ./mcp-server
dockerfile: Dockerfile
container_name: mcp-server
environment:
- MCP_API_USER=vizru
- STATEMENT_TIMEOUT_MS=10000
- MAX_ROWS=500
secrets:
- neon-url
expose:
- 9101
networks:
- vizru-network
image: ${DOCKER_IMAGE}mcp-server:${DOCKER_TAG}
profiles:
- dev
- prodReading the URL and secret from files rather than the environment needs two
lines in db.py / main.py (open("/run/secrets/neon-url").read().strip());
the rest is unchanged. Doing it that way also lets mcp-postgres be removed
from the project.
Endpoints
GET /health liveness plus a real database round trip
POST /api/query {"query": "SELECT ..."} -> [ {...}, ... ]
GET /api/schema?shortcode=EMP001 -> {"table":"ss_emp001","columns":[...]}
POST /mcp JSON-RPC: initialize, tools/list, tools/callAll except /health require basic auth.
A spreadsheet's short code names its mirror table: EMP001 is ss_emp001,
lower-cased because Postgres folds unquoted identifiers and the blocks reference
these tables unquoted.
What stops a bad query
Four layers, because the SQL is written by people and by language models:
The block.
SqlReadGuard.phprefuses anything but a single read-only SELECT before the request is even made, and the Agent Node additionally restricts the query to the spreadsheets that block was configured with.This service.
guard.pyapplies the identical rules again — the workflow engine is not the only thing that can reach this port.The session. Every pooled connection runs with
default_transaction_read_only = on, so Postgres itself refuses a write. This catches what a regex cannot:SELECT … FOR SHAREtakes row locks and trips no keyword, and the database rejects it.The clock and the row count.
statement_timeout(10s by default) kills a runaway query, andMAX_ROWS(500) caps what comes back.
For a fifth, give the service a Postgres role with only SELECT on the ss_*
tables. Nothing here depends on being able to write.
Local development
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
DATABASE_URL='postgresql://...?sslmode=require' \
MCP_API_SECRET=dev \
uvicorn main:app --port 9101 --reloadFiles
main.py FastAPI app: auth, the REST endpoints, the MCP entry point
tools.py the two capabilities, shared by both surfaces
guard.py read-only SQL check, mirroring SqlReadGuard.php
db.py Neon connection pool, read-only session, row serialization
mcp.py JSON-RPC framing for tools/list and tools/callThis server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables secure querying of PostgreSQL databases through MCP-compatible clients. Supports read-only SQL execution, table exploration, and connection management with built-in security validation.3339MIT
- Alicense-qualityAmaintenanceProvides a read-only PostgreSQL SQL surface for LLM agents via MCP, with defense-in-depth security layers for safe database queries.3MIT
- AlicenseAqualityCmaintenanceA self-hostable PostgreSQL MCP server for exploring database schemas and running guarded read/write queries with selectable access modes (readonly, readwrite, admin), plus a dry-run confirm workflow for safety.141MIT
- Flicense-qualityDmaintenanceProvides read-only SQL query access to Postgres and DuckDB databases via MCP tools, with extensive security hardening for public endpoints.1
Related MCP Connectors
Query your Google Sheets as structured JSON: list sheets and tabs, read schemas, filter rows.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Read-only MCP server for wafergraph.com's semiconductor & AI supply-chain data: 30 tools, no auth.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/abhijithvs680/Vizru-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server