Skip to main content
Glama

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 .env file

  • MCP 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 npm

Python 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 .env

Required:

  • DB_HOST — PostgreSQL server hostname

  • DB_NAME — Database name

  • DB_USER — Database username

  • DB_PASSWORD — Database password

Optional (tuning):

  • DB_PORT — Connection port (default: 5432)

  • DB_SSLMODE — SSL mode (default: prefer)

  • DB_APPLICATION_NAME — Application identifier

  • DB_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=prefer

Optional: 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

API_BASE_URL

Base URL of the backend server, e.g. https://localhost:5004/api/v1. Resource paths are appended to it. Required for HTTP tools.

API_TIMEOUT_SECONDS

HTTP request timeout

API_MAX_RESPONSE_BYTES

Max response bytes returned by HTTP tools

API_VERIFY_SSL

true / false SSL verification (local dev certs)

API_BEARER_TOKEN

Default JWT used when a tool call does not pass jwt_token

API_USER_TIMEZONE

Timezone header forwarded as X-User-Timezone

Example call shape (with API_BASE_URL=https://localhost:5004/api/v1):

path: /breakouts/filter/1871161/dd-table?ParameterSetId=231022
method: GET

This 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:

  1. jwt_token passed in the tool call

  2. API_BEARER_TOKEN from .env or process environment

Precedence

  • If jwt_token is provided, that token is forwarded as Authorization: Bearer <jwt_token>.

  • If jwt_token is omitted or blank, the server falls back to API_BEARER_TOKEN.

  • If neither value is present, the request is sent without an Authorization header.

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

  1. An agent calls auth_start_session with the target user's email.

  2. The MCP server exchanges the shared secret + email for a scoped JWT from the backend broker (POST /api/v1/mcp/exchange).

  3. The token is cached in process memory.

  4. Every subsequent HTTP tool call that omits jwt_token uses the session token automatically.

  5. The agent can inspect the session with auth_status, switch users with auth_switch_user, or clear it with auth_clear_session.

Token precedence (highest → lowest)

Priority

Source

1

jwt_token passed in the tool call

2

Session token set by auth_start_session

3

API_BEARER_TOKEN environment variable

Required environment variables

Variable

Purpose

MCP_EXCHANGE_URL

Full URL of the backend broker endpoint

MCP_SHARED_SECRET

Shared secret sent in X-MCP-SECRET header

MCP_TOKEN_TTL_BUFFER_SECONDS

Refresh when fewer than N seconds remain (default: 60)

Session auth tools

Tool

Description

auth_start_session

Acquire a session token for the given email

auth_switch_user

Switch the active session to a different user (same as start)

auth_status

Inspect the current session (email, expiry, needs_refresh)

auth_clear_session

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-mcp
python -m workbench_mcp.server

MCP 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.server

To 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.server

After 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:

  1. workbench-mcp/.env

  2. env in .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

  • health

  • describe_object

  • list_tables_and_columns

  • preview_query

  • execute_readonly_sql

  • exec_proc_preview

  • exec_function_preview

  • insert_row

  • insert_rows

  • http_get

  • http_head

  • http_post

  • http_put

  • http_patch

  • http_delete

  • auth_start_session

  • auth_switch_user

  • auth_status

  • auth_clear_session

  • execute_path_bash_script (script name resolved via PATH)

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_query allows only SELECT statements and CTE-based reads

  • exec_proc_preview can execute PostgreSQL procedures and functions; overloaded routines should be passed with a signature such as public.my_func(integer, text)

  • execute_path_bash_script only accepts script names (not paths), resolves them via PATH, and executes through bash

Suggested First Checks

After .env is configured, a typical validation flow is:

  1. Describe the function, procedure, table, or view to inspect.

  2. Preview the supporting configuration or reference data needed to understand that object.

  3. Run exec_proc_preview, preview_query, or execute_readonly_sql with known inputs.

  4. 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 tools
auth_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, 5

  • arrays: [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-qualified

  • row: object mapping column names to values

  • returning_columns: optional list of columns to return via RETURNING

Example:

  • table_name: sales.orders

  • row: { "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-qualified

  • rows: list of objects mapping column names to values

  • returning_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

    A3.8/5.0

    Scored across 19 tools

    Disambiguation4/5

    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.

    Naming Consistency5/5

    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.

    Tool Count4/5

    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.

    Completeness5/5

    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

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      An 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 npm
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Full-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.
      36
      7 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      A 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
    • A
      license
      Not graded
      quality
      C
      maintenance
      A Python MCP server that enables schema discovery, read-only SQL queries, table previews, and index/relationship analysis on PostgreSQL databases.
      1
      MIT