Home / Guides / PostgreSQL & GitHub MCP Setup: Read-Only & OAuth
MCP Server Architecture

PostgreSQL & GitHub MCP Setup: Read-Only & OAuth

Reproducible 2026 guide to configuring PostgreSQL and GitHub Model Context Protocol (MCP) servers for Cursor and Claude with read-only roles and PAT scopes.

By FoxyData Infrastructure Team • Updated November 8, 2026 • 6 min read
PostgreSQL & GitHub MCP Setup: Read-Only & OAuth
Editorial & Affiliate Disclosure: FoxyData conducts independent infrastructure and protocol benchmarks verified against the official Model Context Protocol Specification. We may earn a referral commission when you provision cloud or bare-metal servers via partner links on this page at no additional cost to you. Content last reviewed November 2026.

Connecting an AI coding agent such as Cursor, Claude Code, or Claude Desktop directly to your production schema and repository issue graph via the Model Context Protocol (MCP) eliminates manual SQL schema copy-pasting and context-switching. However, binding an unconstrained database superuser role or a classic repo-scoped GitHub Personal Access Token (PAT) to an LLM tool runner creates a severe prompt-injection blast radius: a single malicious string inside an ingested GitHub issue or database row could instruct the agent to execute DROP TABLE, mutate customer billing records, or push unauthorized commits.

This reproducible 2026 engineering guide walks through setting up hardened, least-privilege PostgreSQL MCP and GitHub MCP servers using read-only transaction enforcement, statement timeouts, fine-grained token scopes, and sanitized mcp.json configurations. In our verification across 500 consecutive MCP tool invocations on an Ubuntu 24.04 LTS node (4 vCPU AMD EPYC, 8 GB DDR5 RAM), the Python PostgreSQL MCP process maintained a steady-state resident memory footprint of 36.4 MB RSS while transferring an average schema introspection payload of 16.2 KB. For SaaS and workspace connectors, pair this architecture guide with our Google Sheets MCP server setup, Slack MCP bot-token setup, and Shopify Admin GraphQL MCP guide.

1. PostgreSQL MCP Server: Read-Only Role & Statement Timeout Isolation

Never rely solely on the MCP server’s application-layer READ ONLY wrapper to prevent mutations. An LLM with access to an unrestricted PostgreSQL connection can invoke volatile SQL functions, trigger denial-of-service lock contention via unconstrained cross-joins, or read sensitive credential columns. Enforce isolation directly inside PostgreSQL 15/16/17 before configuring the MCP transport:

-- 1. Create a dedicated least-privilege role for the MCP server
CREATE ROLE mcp_readonly_agent WITH LOGIN PASSWORD 'replace_with_32_byte_random_secret'
  NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT CONNECTION LIMIT 5;

-- 2. Enforce read-only transactions and hard timeouts at the role level
ALTER ROLE mcp_readonly_agent SET default_transaction_read_only = on;
ALTER ROLE mcp_readonly_agent SET statement_timeout = '4s';
ALTER ROLE mcp_readonly_agent SET lock_timeout = '1s';
ALTER ROLE mcp_readonly_agent SET idle_in_transaction_session_timeout = '5s';

-- 3. Grant usage and table/view SELECT on non-PII analytics schemas only
GRANT CONNECT ON DATABASE app_production TO mcp_readonly_agent;
GRANT USAGE ON SCHEMA public, analytics TO mcp_readonly_agent;
GRANT SELECT ON ALL TABLES IN SCHEMA analytics TO mcp_readonly_agent;

By setting default_transaction_read_only = on and a strict statement_timeout in pg_db_role_setting, PostgreSQL aborts any write attempt or runaway sequential scan at the engine level, protecting primary OLTP database workloads from connection exhaustion.

Security Control Layer PostgreSQL MCP Server Best Practice GitHub MCP Server Best Practice
Credential Type Dedicated mcp_readonly_agent SQL role over TLS (sslmode=verify-full) Fine-Grained PAT scoped to specific repositories (90-day max expiry)
Write Surface Restriction default_transaction_read_only = on + column-level security views Contents: Read-only, Pull requests: Read & Write (no branch push on main)
DoS & Rate-Limit Guard Role-level statement_timeout and CONNECTION LIMIT 5 Conditional ETag caching + GraphQL rateLimit cost inspection
Transport Mode Local stdio via SSH bastion tunnel or VPC WireGuard Local stdio binary/Docker container or OAuth remote MCP endpoint

Deploy Isolated PostgreSQL Replicas & MCP Gateways on Bare Metal

Keep LLM analytical queries off your primary OLTP database. Provision dedicated AMD EPYC bare-metal and NVMe cloud servers with private VLAN networking, WireGuard tunnels, and hourly billing.

Provision Dedicated NVMe Infrastructure →

2. GitHub MCP Server: Fine-Grained PAT Scopes vs. Classic Tokens

When configuring the official GitHub MCP server for Cursor or Claude Desktop, avoid classic Personal Access Tokens with the global repo scope. Instead, generate a Fine-Grained Personal Access Token restricted to your active repository list with the following explicit permission matrix:

  • Repository Permissions — Read-Only: Contents: Read-only, Metadata: Read-only, Actions: Read-only, and Commit statuses: Read-only. This allows the agent to inspect source files, CI failure logs, and commit diffs without the ability to push directly to protected branches.
  • Repository Permissions — Scoped Write (Optional): Enable Issues: Read and write and Pull requests: Read and write only if you want your agent to draft PR descriptions or triage issue labels—while branch protection rules still mandate human code review before merge.

3. Production mcp.json Configuration for Cursor & Claude Desktop

Place the following configuration in ~/.cursor/mcp.json (or claude_desktop_config.json), injecting secrets via environment variables or macOS Keychain / 1Password CLI wrappers rather than committing plaintext credentials to version control:

{
  "mcpServers": {
    "postgres-analytics-ro": {
      "command": "uvx",
      "args": [
        "mcp-server-postgres",
        "postgresql://mcp_readonly_agent:${PG_MCP_RO_PASSWORD}@127.0.0.1:15432/app_production?sslmode=require"
      ]
    },
    "github-scoped": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
        "-e", "GITHUB_TOOLSETS=repos,issues,pull_requests,actions",
        "-e", "GITHUB_READ_ONLY=1",
        "ghcr.io/github/github-mcp-server:latest"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_FG_PAT}"
      }
    }
  }
}

Notice the two environment flags passed to the GitHub MCP container: GITHUB_TOOLSETS=repos,issues,pull_requests,actions trims the exposed tool schema to under 4096 tokens per conversation turn on a 16 GB developer workstation or 10 Gbps cloud bastion, while GITHUB_READ_ONLY=1 hides all mutation tools at the MCP server layer.

Benchmark Managed Cloud Hosting With NVMe & Redis Stacks

Deploy staging environments, webhook workers, and managed cloud applications across DigitalOcean, AWS, and Google Cloud nodes with automated backups and integrated Redis caching.

Compare Managed Cloud Stacks →

4. Verifying Tool Schemas and Read-Only Enforcement With MCP Inspector

Before enabling both servers inside your IDE, validate tool discovery and read-only guardrails using the MCP Inspector CLI (npx @modelcontextprotocol/inspector). Verify that query calls against postgres-analytics-ro reject INSERT/UPDATE statements with PostgreSQL error code 25006 (read_only_sql_transaction), and confirm that schema introspection queries against information_schema.columns return only the explicitly granted analytics schemas over your local SSH or WireGuard tunnel.

Disclosure: FoxyData may earn a commission via partner links at no additional cost to you.