Языки: EN RU

Practice: GitHub, Databases, and Web APIs via MCP

In previous articles we covered MCP architecture and learned how to build our own servers. Now it's time for concrete integrations that are actually used in real work: the official GitHub MCP Server, PostgreSQL, and patterns for arbitrary REST APIs — along with a breakdown of the pitfalls that rarely make it into README files.

GitHub MCP Server: official integration

GitHub released an official MCP server (github/github-mcp-server) that covers a large portion of the GitHub API: repositories, branches, commits, issues, pull requests, GitHub Actions, Dependabot alerts, and code search. In total, more than 51 tools organized into 20+ functional categories.

There are two connection methods — remote and local.

The remote server runs over streamable HTTP on GitHub's infrastructure with no local process required:

claude mcp add github \
  --transport http \
  --header "Authorization: Bearer ${GITHUB_TOKEN}" \
  https://api.githubcopilot.com/mcp/

The GitHub token can be issued with minimal scopes — for example, just repo:read for read access. This approach is recommended: the principle of least privilege applies here too.

Local execution via Docker gives you more control over network access:

claude mcp add github \
  -e GITHUB_PERSONAL_ACCESS_TOKEN="${GITHUB_TOKEN}" \
  -- docker run -i --rm \
     -e GITHUB_PERSONAL_ACCESS_TOKEN \
     ghcr.io/github/github-mcp-server

Once connected, Claude has access to tools like get_pull_request, create_issue, search_code, and list_workflow_runs. A typical scenario: an agent analyzes a failed CI run — it reads logs via get_workflow_run_logs, inspects the diff via get_pull_request_files, identifies the root cause, and posts a review via create_pull_request_review.

An important note for those already using claude-code-action in GitHub Actions (the Agent SDK wrapper covered in GitHub Actions and Automated Code Review): GitHub MCP Server is a complement, not a replacement. The Actions wrapper launches an agent in CI on a @claude trigger; the MCP server gives that agent tools to interact with the GitHub API within the session.

Проверь себя
Imagine: you want an agent in CI to automatically review PRs when @claude is mentioned. Which tool is responsible for that — GitHub MCP Server or claude-code-action? And what is the second one even for?

PostgreSQL: choosing a server and staying secure

The original @modelcontextprotocol/server-postgres from Anthropic was deprecated and archived in 2025. The current alternative is Postgres MCP Pro by Crystal DBA:

# Install via pip
pip install postgres-mcp

# or in isolation via uv (preferred)
uv tool install postgres-mcp

Connecting to Claude Code:

claude mcp add postgres \
  -e DATABASE_URI="postgresql://analyst:secret@localhost:5432/mydb" \
  -- uvx postgres-mcp --access-mode=restricted

The --access-mode=restricted flag limits Claude to SELECT queries only — no INSERT, UPDATE, or DELETE. Agent mistakes (a wrong WHERE clause, an accidental DROP) are far harder to recover from in a production database than in a test environment. Beyond ordinary queries, the server can run EXPLAIN analysis on execution plans, recommend indexes, and monitor pg_stat_activity — handy for the use cases covered in Data, SQL, and Analytics.

Three security rules that almost everyone breaks:

1. A dedicated role with minimal privileges. Never give Claude a superuser role or database owner:

CREATE ROLE claude_analyst WITH LOGIN PASSWORD 'strong_password';
GRANT CONNECT ON DATABASE mydb TO claude_analyst;
GRANT USAGE ON SCHEMA public TO claude_analyst;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_analyst;

-- For tables created in the future:
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO claude_analyst;

2. Credentials via environment variables, not in .mcp.json. The .mcp.json file is committed to git — a connection string with a password in there is a credential leak for the entire team:

{
  "mcpServers": {
    "postgres": {
      "command": "uvx",
      "args": ["postgres-mcp", "--access-mode=restricted"],
      "env": {
        "DATABASE_URI": "${POSTGRES_URI}"
      }
    }
  }
}

${POSTGRES_URI} is an environment variable that each developer sets locally — via .env, 1Password CLI, direnv, or whatever approach the team uses. The config is committed safely; the secret stays private to each person.

3. Minimize network exposure. If your database is in the cloud, Tailscale, a VPN, or an SSH tunnel is more secure than an open port with an IP allowlist. An open port is a permanent attack surface; a tunnel only exists when you need it.

Проверь себя
Why can't you write the database connection string (`postgresql://user:pass@host/db`) directly in `.mcp.json` and commit it to git?

Arbitrary web APIs: three approaches

When no ready-made MCP server exists, choose from three options — from simplest to most powerful.

Approach 1: Bash tools directly. For public APIs without complex authorization, Claude Code can already make curl requests via the built-in Bash tool — no MCP needed:

curl -H "Authorization: Bearer $API_KEY" \
     "https://api.example.com/v1/data?limit=10"

The limitation: Claude has no knowledge of the API schema, there's no parameter typing, and no prompt autocompletion. Suitable for one-off tasks or quick prototypes.

Approach 2: A custom MCP wrapper server. If the API is used regularly, wrap it in FastMCP as covered in Building Your Own MCP Server. The server encapsulates authorization, transforms responses, and filters sensitive fields. Claude sees clean tools with clear names and good descriptions.

Approach 3: Puppeteer MCP. For services without an API — corporate portals, legacy SPAs, forms — a Puppeteer-based MCP server gives Claude control over a browser: clicks, form filling, and scraping. This is a powerful tool: it requires a sandbox and a clear permissions policy to prevent the agent from causing unintended side effects.

flowchart LR CC["Claude Code"] CC -->|"Path 1\nBash + curl"| P1["Public API\n(one-off tasks)"] CC -->|"Path 2\nMCP wrapper"| MCP["FastMCP server"] CC -->|"Path 3\nPuppeteer MCP"| BR["Browser"] MCP -->|"auth, transform,\nfiltering"| API["Corporate API\n/ internal DB"] BR -->|"clicks, forms,\nscraping"| WEB["Web portal\nwith no REST API"]
flowchart LR
    CC["Claude Code"]

    CC -->|"Path 1\nBash + curl"| P1["Public API\n(one-off tasks)"]
    CC -->|"Path 2\nMCP wrapper"| MCP["FastMCP server"]
    CC -->|"Path 3\nPuppeteer MCP"| BR["Browser"]

    MCP -->|"auth, transform,\nfiltering"| API["Corporate API\n/ internal DB"]
    BR -->|"clicks, forms,\nscraping"| WEB["Web portal\nwith no REST API"]
Three approaches to integrating Claude Code with arbitrary web services — from simple to complex

Common pitfalls

Large result sets pollute the context. Running SELECT * FROM events on a table with a million rows is not a query — it's a context window fire. Use a two-layer defense: restrict access to heavy tables at the role level, and explicitly document in CLAUDE.md: "always add a LIMIT, use aggregates instead of raw data." Claude Code follows instructions from CLAUDE.md reliably — it's configuration, not a suggestion.

Tokens and passwords in config files. .mcp.json is committed to git; settings.local.json is not (it's in .gitignore by default). Local secrets belong in settings.local.json or environment variables. Team-wide secrets should go through Vault, AWS Secrets Manager, or Doppler with injection at process startup.

Overly broad tools. A single run_query(sql: str) tool with no constraints is an anti-pattern. Claude has no way to know what's permitted and what isn't. Explicit, narrowly scoped tools (search_orders, get_customer_by_id, update_order_status) give the model a predictable contract and reduce the likelihood of unwanted side effects.

Mixing scopes. A server with broad permissions in the project scope (.mcp.json) automatically becomes available to everyone who clones the repository. Privileged servers belong in the user scope (~/.claude/), not in the project. Scope separation is covered in detail in Connecting MCP Servers in Claude Code.

No protection against cyclic calls. An agent can call an API endpoint in a loop — for example, iterating over 500 users one by one. Implement rate limiting at the server level, or design tools with an explicit limit parameter and pagination support.


Быстрое повторение
Какой выбор делаешь между curl в Bash, собственным MCP-сервером и Puppeteer MCP, если для API нет готового сервера?
Быстрое повторение
Почему при работе Claude с PostgreSQL нужна отдельная роль с минимальными правами вместо суперпользователя?
Быстрое повторение
Когда нужно выбрать локальный запуск GitHub MCP через Docker вместо удалённого сервера на инфраструктуре GitHub?

See also

  • Model Context Protocol: Architecture and Fundamentals — the tools/resources/prompts primitives that underpin all integrations
  • Connecting MCP Servers in Claude Code — scopes, .mcp.json, transports, and OAuth
  • Building Your Own MCP Server — FastMCP, the TypeScript SDK, and MCP Inspector for custom integrations
  • GitHub Actions and Automated Code Review — how GitHub MCP Server works alongside claude-code-action
  • Data, SQL, and Analytics — practical database workflows via MCP
  • CLAUDE.md and the Memory System — how to configure persistent instructions for working with specific tools

Источники

  1. GitHub's official MCP Server — github/github-mcp-server
  2. List of all 51 MCP tools on GitHub official Remote MCP server (June 2025)
  3. How to Set Up a Secure PostgreSQL MCP Server for AI Clients
  4. 3 Ways to Connect to PostgreSQL with Claude Code
  5. Securely connect Claude Code to Postgres via MCP