workbench-mcp
workbench-mcp is a local MCP server for interactive PostgreSQL exploration, API integration, and automation on Fedora/Linux systems.
Health and configuration status checks without exposing secrets
Discover and describe database objects: tables, columns, schemas, functions, procedures
Run read-only SQL: SELECT/CTE previews (
preview_query) and multi-statement read-only batches with session temp-table support (execute_readonly_sql)Execute PostgreSQL functions and procedures with positional parameters and result limits
Insert single rows or bulk insert rows into tables with optional
RETURNINGMake backend API calls via HTTP tools (GET, HEAD, POST, PUT, PATCH, DELETE) using resource paths plus optional JWT/session auth
Manage session-scoped authentication: start, switch user, status, clear session
Execute bash scripts available in
PATHby script nameEnforced safety: persistent schema/data modifications are blocked; only batch-local temp table writes are allowed
Provides a comprehensive set of tools for interactive PostgreSQL data exploration and automation, including schema discovery, read-only query previews, execution of stored procedures and functions, and managed data insertion.
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., "@workbench-mcp show me the schema for the orders table and a preview of its data"
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.
workbench-mcp
A local Python MCP server for interactive PostgreSQL data exploration, API integration, and automation on Fedora/Linux systems.
Overview
Version 1 includes:
Python virtual environment setup for Fedora/Linux systems
PostgreSQL 18 connectivity configured via
.envfileMCP tools for:
Discovering tables, columns, and schema structure
Running read-only query previews
Executing guarded SQL batches with temporary table support
Calling PostgreSQL stored functions and procedures
Accessing your backend API through HTTP tools using resource paths (host and base come from
API_BASE_URL)Executing bash scripts available in
PATH
Enforced safety: persistent schema and data modifications are blocked
Session-scoped temporary table workflows supported within SQL batches
Related MCP server: PostgreSQL MCP Server
Fedora / Linux Setup
Start by installing required system packages:
sudo dnf install -y python3 python3-pip nodejs npmPython 3.12 or later is required. Use pyenv or similar if managing multiple versions.
Virtual Environment Setup
From the project root, create and activate a Python virtual environment:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -e .Environment Variables
Copy the example configuration and populate PostgreSQL connection details:
cp .env.example .envRequired:
DB_HOST— PostgreSQL server hostnameDB_NAME— Database nameDB_USER— Database usernameDB_PASSWORD— Database password
Optional (tuning):
DB_PORT— Connection port (default: 5432)DB_SSLMODE— SSL mode (default: prefer)DB_APPLICATION_NAME— Application identifierDB_QUERY_TIMEOUT_SECONDS— Query timeout (default: 30)DB_MAX_ROWS— Maximum rows per result set (default: 100)DB_MAX_RESULT_SETS— Maximum result sets per batch (default: 5)DB_OBJECT_PREVIEW_CHARS— Max definition preview length (default: 4000)
Example local development:
DB_HOST=localhost
DB_PORT=5432
DB_NAME=app_dev
DB_USER=app_user
DB_PASSWORD=your-secure-password
DB_SSLMODE=preferOptional: HTTP Request Tuning
The HTTP tools (http_get, http_head, http_post, http_put, http_patch, http_delete) receive only a resource path (e.g. /account/session-info) and append it to the server base URL configured with API_BASE_URL (e.g. https://localhost:5004/api/v1). They do not accept full URLs — the scheme, host, and /api/v1 prefix always come from the environment.
Supported environment settings:
Variable | Purpose |
| Base URL of the backend server, e.g. |
| HTTP request timeout |
| Max response bytes returned by HTTP tools |
|
|
| Default JWT used when a tool call does not pass |
| Timezone header forwarded as |
Example call shape (with API_BASE_URL=https://localhost:5004/api/v1):
path: /breakouts/filter/1871161/dd-table?ParameterSetId=231022
method: GETThis issues GET https://localhost:5004/api/v1/breakouts/filter/1871161/dd-table?ParameterSetId=231022.
For authenticated calls, set API_BEARER_TOKEN in .env (or process env). HTTP tools automatically use it unless the caller passes its own jwt_token.
Authorization Handling
HTTP tools support two authorization sources:
jwt_tokenpassed in the tool callAPI_BEARER_TOKENfrom.envor process environment
Precedence
If
jwt_tokenis provided, that token is forwarded asAuthorization: Bearer <jwt_token>.If
jwt_tokenis omitted or blank, the server falls back toAPI_BEARER_TOKEN.If neither value is present, the request is sent without an
Authorizationheader.
Important rule for agents
Do not place the bearer token inside headers.Authorization.
The MCP server strips Authorization from headers and only accepts auth through the dedicated jwt_token field.
This prevents accidental header collisions and makes token precedence explicit.
Example: use the default server token
With API_BASE_URL=https://localhost:5004/api/v1, pass only the resource path:
{
"path": "/sales/my-sales"
}Example: forward the caller's own token
{
"path": "/sales/my-sales",
"jwt_token": "eyJhbGciOi..."
}Example: forward caller token with extra headers
{
"path": "/sales/my-sales",
"jwt_token": "eyJhbGciOi...",
"headers": {
"Accept": "application/json"
}
}The same jwt_token field is available on http_get, http_head, http_post, http_put, http_patch, and http_delete, and all of them accept a path (never a full URL).
Session Auth
Instead of passing a per-call jwt_token, agents can acquire a session-scoped JWT once and have every HTTP tool call use it automatically for the rest of the session.
How it works
An agent calls
auth_start_sessionwith the target user's email.The MCP server exchanges the shared secret + email for a scoped JWT from the backend broker (
POST /api/v1/mcp/exchange).The token is cached in process memory.
Every subsequent HTTP tool call that omits
jwt_tokenuses the session token automatically.The agent can inspect the session with
auth_status, switch users withauth_switch_user, or clear it withauth_clear_session.
Token precedence (highest → lowest)
Priority | Source |
1 |
|
2 | Session token set by |
3 |
|
Required environment variables
Variable | Purpose |
| Full URL of the backend broker endpoint |
| Shared secret sent in |
| Refresh when fewer than N seconds remain (default: 60) |
Session auth tools
Tool | Description |
| Acquire a session token for the given email |
| Switch the active session to a different user (same as start) |
| Inspect the current session (email, expiry, needs_refresh) |
| Clear the cached session token from memory |
See docs/SESSION_AUTH.md for the full agent-facing reference.
Run Locally
After activating the virtual environment and installing dependencies, start the MCP server with either command:
workbench-mcppython -m workbench_mcp.serverMCP Inspector
For local MCP development and debugging, the MCP Inspector provides a fast manual test loop:
npx @modelcontextprotocol/inspector .venv/bin/python -m workbench_mcp.serverTo launch the MCP server under debugpy for breakpoint debugging in the Inspector:
npx @modelcontextprotocol/inspector .venv/bin/python -m debugpy --listen 127.0.0.1:5678 -m workbench_mcp.serverAfter launch, open the Inspector UI, connect over STDIO, and test tools such as health, describe_object, and exec_proc_preview.
Breakpoints (debugpy): Use port 5678 for the debugger, not 6274 (6274 is only the Inspector web UI). Step-by-step workflow and “what was wrong before” are in docs/DEBUG_MCP.md.
VS Code Setup
To register the local MCP server in VS Code, add an entry to the workspace MCP configuration file:
Workspace file:
.vscode/mcp.json
Example configuration:
{
"servers": {
"workbench-mcp": {
"type": "stdio",
"command": "/absolute/path/to/workbench-mcp/.venv/bin/python",
"args": ["-m", "workbench_mcp.server"]
}
}
}Replace the command path with the local repository path to your virtual environment Python.
Secrets and Environment Values
You can supply environment values in either place:
workbench-mcp/.envenvin.vscode/mcp.json— VS Code injects these into the MCP server process.
Precedence: process environment (including .vscode/mcp.json → env) overrides values from .env for the same key.
Example with HTTP tuning in VS Code:
{
"servers": {
"workbench-mcp": {
"type": "stdio",
"command": "/absolute/path/to/workbench-mcp/.venv/bin/python",
"args": ["-m", "workbench_mcp.server"],
"env": {
"API_TIMEOUT_SECONDS": "30",
"API_MAX_RESPONSE_BYTES": "2097152",
"API_VERIFY_SSL": "false"
}
}
}
}Do not commit real tokens. Prefer a local-only workspace configuration or omit env and use .env (which should stay out of git).
If other MCP servers are already configured, add workbench-mcp inside the existing servers object instead of replacing the entire file.
After saving .vscode/mcp.json, reload VS Code or refresh MCP servers so the new server is discovered. After the server loads, run the health tool before testing database procedures.
Initial Tools
healthdescribe_objectlist_tables_and_columnspreview_queryexecute_readonly_sqlexec_proc_previewexec_function_previewinsert_rowinsert_rowshttp_gethttp_headhttp_posthttp_puthttp_patchhttp_deleteauth_start_sessionauth_switch_userauth_statusauth_clear_sessionexecute_path_bash_script(script name resolved viaPATH)
Safety Model
Persistent DDL and DML are blocked in ad-hoc PostgreSQL batches
Only temp-table writes are allowed, and only for temp tables created in the current batch
preview_queryallows onlySELECTstatements and CTE-based readsexec_proc_previewcan execute PostgreSQL procedures and functions; overloaded routines should be passed with a signature such aspublic.my_func(integer, text)execute_path_bash_scriptonly accepts script names (not paths), resolves them viaPATH, and executes throughbash
Suggested First Checks
After .env is configured, a typical validation flow is:
Describe the function, procedure, table, or view to inspect.
Preview the supporting configuration or reference data needed to understand that object.
Run
exec_proc_preview,preview_query, orexecute_readonly_sqlwith known inputs.Compare the returned shape with the feature, investigation, or debugging scenario being evaluated.
Function Execution Example
For positional PostgreSQL function calls, use exec_function_preview.
Pass PostgreSQL arrays as normal JSON lists.
Example SQL target:
select * from sales."Fn_GetSalesChamps"(2, 2025, array[1,2,5,6,7,8,9,10,11,12,15,16,18,19], 5);Equivalent MCP tool input:
{
"function_name": "sales.\"Fn_GetSalesChamps\"",
"parameters": [2, 2025, [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16, 18, 19], 5]
}Insert Examples
Single row insert:
{
"table_name": "sales.orders",
"row": {
"customer_id": 10,
"status": "new"
},
"returning_columns": ["order_id"]
}Batch insert:
{
"table_name": "sales.orders",
"rows": [
{"customer_id": 10, "status": "new"},
{"customer_id": 11, "status": "pending"}
]
}Available Tools
19 toolsauth_clear_sessionA
Clear the active session token from memory.
After this call HTTP tools will fall back to API_BEARER_TOKEN (if
configured) or make unauthenticated requests.
Returns
dict
{"ok": True, "message": "Session cleared."}.
Inputs: no named parameters. Returns: object
auth_start_sessionA
Acquire a session-scoped JWT for email from the backend broker.
After a successful call every HTTP tool call in this session will
automatically use the returned token (unless the tool call provides
its own jwt_token).
Parameters
email: The user whose identity the MCP session will impersonate. reason: Optional free-text description of why this session is needed. Stored in the JWT claims for audit purposes.
Returns
dict
ok=True with email, display_name, user_name,
store on success; ok=False with error on failure.
Inputs: email (required), reason. Returns: object
auth_statusA
Return the current session status without exposing the raw token.
Returns
dict
active=False when no session is set; otherwise active=True
with email, display_name, expires_in_seconds, and
needs_refresh.
Inputs: no named parameters. Returns: object
auth_switch_userA
Switch the active session to a different user.
Equivalent to calling auth_start_session — provided as a semantic
alias when the intent is to change the active user rather than start a
fresh session.
Parameters
email: The new user to impersonate. reason: Optional free-text description of why the switch is needed.
Returns
dict
Same shape as auth_start_session.
Inputs: email (required), reason. Returns: object
describe_objectB
Retrieve structural details, parameters, and definition for a database object.
Inputs: object_name (required). Returns: object
exec_function_previewA
Execute a PostgreSQL function with positional parameters and return preview rows.
Use this tool for function calls such as
sales."Fn_GetSalesChamps"(2, 2025, ARRAY[1,2,5], 5).
Pass arguments in positional order using JSON-compatible values:
scalars:
2,2025,5arrays:
[1, 2, 5]null:
null
PostgreSQL array parameters should be passed as normal lists; psycopg adapts them to PostgreSQL arrays automatically.
Inputs: function_name (required), parameters, max_rows. Returns: object
exec_proc_previewB
Execute PostgreSQL functions or procedures with optional parameters and result limiting.
Inputs: proc_name (required), parameters, max_rows. Returns: object
execute_readonly_sqlC
Execute read-only SQL batches with support for temporary tables within the session.
Inputs: sql (required), max_rows. Returns: object
healthB
Provide system status and configuration details without exposing secrets.
Inputs: no named parameters. Returns: object
http_deleteA
Send an HTTP DELETE request.
Use for delete operations. Some APIs allow delete payloads; if needed,
provide body as JSON object/array or UTF-8 text.
Pass jwt_token to forward the caller's JWT for this request only.
Inputs: url (required), body, content_type, headers, +1 more. Returns: object
http_getA
Send an HTTP GET request.
Use for read-only resource retrieval. Provide a full URL.
Pass jwt_token to forward the caller's JWT for this request only.
If jwt_token is omitted, API_BEARER_TOKEN is used when configured.
headers.Authorization is ignored; use jwt_token instead.
Inputs: url (required), headers, jwt_token. Returns: object
http_headA
Send an HTTP HEAD request.
Use for metadata/status checks without retrieving a full body.
Pass jwt_token to override the default environment token for this call.
headers.Authorization is ignored; use jwt_token instead.
Inputs: url (required), headers, jwt_token. Returns: object
http_patchA
Send an HTTP PATCH request.
Use for partial updates.
body accepts JSON object/array or UTF-8 text.
Pass jwt_token to forward the caller's JWT for this request only.
Inputs: url (required), body, content_type, headers, +1 more. Returns: object
http_postA
Send an HTTP POST request.
Use for create/actions. Provide a full URL.
body accepts JSON object/array or UTF-8 text.
content_type optionally overrides the Content-Type header.
Pass jwt_token to forward the caller's JWT for this request only.
Inputs: url (required), body, content_type, headers, +1 more. Returns: object
http_putA
Send an HTTP PUT request.
Use for full updates/replacements.
body accepts JSON object/array or UTF-8 text.
Pass jwt_token to forward the caller's JWT for this request only.
Inputs: url (required), body, content_type, headers, +1 more. Returns: object
insert_rowA
Insert a single row into a PostgreSQL table.
Use this tool when you need one explicit insert with structured values.
table_name: table target, optionally schema-qualifiedrow: object mapping column names to valuesreturning_columns: optional list of columns to return viaRETURNING
Example:
table_name:sales.ordersrow:{ "customer_id": 10, "status": "new" }returning_columns:["order_id"]
Inputs: table_name (required), row (required), returning_columns. Returns: object
insert_rowsA
Insert multiple rows into a PostgreSQL table in one batch.
Use this tool for bulk inserts where every row has the same columns.
table_name: table target, optionally schema-qualifiedrows: list of objects mapping column names to valuesreturning_columns: optional list of columns to return from inserted rows
Notes:
Every row must use the same columns in the same order.
Arrays can be passed as JSON lists and psycopg adapts them automatically.
Inputs: table_name (required), rows (required), returning_columns. Returns: object
list_tables_and_columnsB
Discover tables and columns with optional filtering by schema or keyword search.
Inputs: schema_name, search_term, limit. Returns: object
preview_queryA
Execute read-only SELECT statements and CTEs with safety validation and row limits.
Inputs: sql (required), max_rows. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 19 tools
Most tools have distinct purposes, but there is some overlap between exec_function_preview and exec_proc_preview, which both execute PostgreSQL functions/procedures with similar parameters. The HTTP tools (http_get, http_post, etc.) are clearly differentiated by HTTP method, and auth tools are well-separated. Overall, the descriptions help clarify boundaries, but the function/procedure execution tools could cause confusion.
Tool names follow a highly consistent snake_case pattern with clear verb_noun structures. Auth tools use auth_ prefix (e.g., auth_clear_session), HTTP tools use http_ prefix (e.g., http_get), and database tools use descriptive verbs like describe_, exec_, insert_, list_, preview_. There are no deviations in naming style across the set.
With 19 tools, the count is slightly high but reasonable for a workbench server that combines authentication, HTTP operations, and database interactions. It covers multiple domains comprehensively without being excessive. A few tools might be consolidated (e.g., the two function execution tools), but overall the scope justifies the number.
The toolset provides complete coverage for its intended domains: authentication (session management), HTTP operations (full CRUD via different methods), and PostgreSQL database interactions (querying, inserting, describing objects, executing functions). There are no obvious gaps; agents can perform end-to-end workflows involving data retrieval, manipulation, and API calls with proper auth handling.
Maintenance
Related MCP Connectors
Text-to-SQL MCP server: read-only queries on PostgreSQL, MySQL and SQL Server with your real schema
Hosted PostgreSQL MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Hosted SQL Server MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn open-source MCP server for PostgreSQL schema introspection and guarded read-only queries. It enables MCP clients to discover schemas, tables, columns, indexes, relationships, and safe queryable data from a configured PostgreSQL database.11 npmMIT
- AlicenseAqualityCmaintenanceFull-featured MCP server that exposes 36 tools for interacting with PostgreSQL databases, covering schema introspection, query execution, data exploration, performance monitoring, security auditing, and maintenance.367 npmMIT
- AlicenseNot gradedqualityDmaintenanceA Python MCP server that provides PostgreSQL database connectivity for Text-to-SQL workflows, enabling AI agents to explore schemas and execute parameterized SQL queries across multiple data marts.MIT
- AlicenseNot gradedqualityCmaintenanceA Python MCP server that enables schema discovery, read-only SQL queries, table previews, and index/relationship analysis on PostgreSQL databases.1MIT