Skip to main content

Design Specification: Go-Based Model Context Protocol (MCP) Server for GitHub Backup & Observatory System

Document Version: 1.0.0
Status: DRAFT / PROPOSED
Author: Antigravity AI Pair Programmer & MishraShardendu22
Target Clients: Google Antigravity, Claude Desktop, Claude Code, Cursor, Windsurf
Implementation Language: Go 1.25+


1. Executive Summary & Objectives​

The GitHub Backup Automation & Observatory System currently features a rich ecosystem of tools distributed across its Go Backend API, Python AI Observatory, and Go Backup Worker:

  • Real-time backup telemetry and historical analytics snapshots.
  • Repository tracking, size trends, and commit verification.
  • Detailed execution logs with multi-level filtering.
  • Hybrid vector search (pgvector + PostgreSQL Full-Text Search).
  • Incident fix registration and tracking (backup_fixes).
  • Archive management: git bundles and legacy tarballs.

Currently, these tools are consumed either via the Next.js Web Dashboard or internally by the LangChain agent in the Python Observatory.

Core Objective​

This design document specifies the architecture, tool schemas, transport mechanisms, and integration patterns for building a dedicated, high-performance Go MCP Server (github-backup-mcp).

By exposing these capabilities via the open Model Context Protocol (MCP), external AI coding agents—most notably Google Antigravity and Anthropic Claude (Claude Desktop & Claude Code)—can directly connect to the backup infrastructure to:

  1. Inspect & Observe: Monitor real-time backup health, review run histories, and inspect archive growth without opening a browser.
  2. Diagnose & Correlate: Automatically triage clone failures, rate-limit lockouts, or network timeouts by aggregating run results, execution logs, and semantic past-incident memory in a single reasoning step.
  3. Fix & Remediate: Propose, apply, and permanently record incident fixes (backup_fixes) with linked commit hashes and affected run IDs.
  4. Operate & Restore: Verify archive checksums, inspect files within compressed .tar.gz snapshots without full extraction, and trigger on-demand backup runs for specific repositories.

2. Why Go for the MCP Server?​

While MCP servers can be written in TypeScript or Python, building this server in Go provides decisive engineering advantages:

DimensionGo ImplementationPython / Node Alternatives
Binary FootprintSingle static executable (~15MB), zero external runtime dependenciesRequires Python 3.12 + venv or Node.js + node_modules
Startup LatencyInstantaneous cold start (<15ms) via stdio pipe300ms - 1500ms interpreter initialization overhead
Memory Footprint~12MB RSS idle / ~25MB peak80MB - 200MB RSS idle
Codebase SynergyDirect reuse of existing Go structs (models.BackupRun, models.BackupFix) and pgxpool queriesRequires duplicate data contract definitions and serialization logic
Concurrency ModelNative lightweight goroutines for async log tailing, health checks, and concurrent tool callsEvent-loop / thread-pool management complexity
Transport VersatilityEffortlessly supports both stdio (local IDE pipe) and SSE/HTTP (remote cloud daemon) in a single binaryFrequently requires separate framework stacks

3. System Architecture & Component Interactions​

graph TD
subgraph AI Client Layer
Claude[Claude Desktop / Claude Code]
Antigravity[Google Antigravity IDE / Agent]
Cursor[Cursor / Other MCP Clients]
end

subgraph MCP Transport Boundary
StdioTransport[Stdio Transport - Local Process Pipe]
SSETransport[SSE / HTTP Transport - Port 8090]
end

Claude -->|JSON-RPC 2.0 via Stdio| StdioTransport
Antigravity -->|JSON-RPC 2.0 via Stdio or SSE| StdioTransport
Cursor -->|JSON-RPC 2.0| StdioTransport

subgraph Go MCP Server Subsystem [github-backup-mcp]
Router[MCP Dispatcher & Protocol Engine - mark3labs/mcp-go]
Sanitizer[Security Filter & Secret Redactor]

subgraph Handlers
ObsHandler[Observability & Telemetry Tools]
DiagHandler[Diagnostic & Failure Triaging Tools]
ArchiveHandler[Archive Inspection & Integrity Tools]
FixHandler[Remediation & Fix Recording Tools]
SearchHandler[Hybrid Search & Knowledge Tools]
end

Router --> Sanitizer
Sanitizer --> ObsHandler
Sanitizer --> DiagHandler
Sanitizer --> ArchiveHandler
Sanitizer --> FixHandler
Sanitizer --> SearchHandler
end

StdioTransport --> Router
SSETransport --> Router

subgraph Backend Infrastructure
NeonDB[(Neon PostgreSQL 16 + pgvector)]
GoBackend[Go Backend REST API :8080]
PythonObs[Python AI Observatory :8000]
LocalArchives[Local Archive Storage _Repos/ & Backups]
end

ObsHandler -->|Direct pgxpool Query| NeonDB
DiagHandler -->|Direct pgxpool Query| NeonDB
ArchiveHandler -->|Direct File I/O & SHA-256| LocalArchives
FixHandler -->|SQL Insert / Update| NeonDB
SearchHandler -->|HTTP POST /search| PythonObs
ObsHandler -.->|HTTP Fallback| GoBackend

Architectural Highlights:​

  1. Dual-Mode Data Access:
    • Direct PostgreSQL Access (pgxpool): When DATABASE_URL is available, the MCP server queries Neon PostgreSQL directly with sub-10ms latency.
    • HTTP Client Fallback: When running in isolated or remote environments, the server falls back to calling the Go Backend REST API (http://localhost:8080 or Render URL). Every fallback call sends INTERNAL_SECRET as X-Internal-Secret (required by the API when API_REQUIRE_AUTH=true), and a non-2xx answer is a tool error.
  2. Secret Redaction Layer: A tool handler middleware passes every tool result, errors included, through the sanitizer (see 8.3), for every transport.
  3. Transports (--transport or MCP_TRANSPORT):
    • stdio: Default mode when spawned directly by Antigravity, Claude Desktop or Claude Code. Logs go to stderr only.
    • http: Streamable HTTP at /mcp on MCP_PORT or --port (default 8090; it never reads PORT/SERVER_PORT, which belong to the API), stateless (no session ID, nothing kept in memory between requests), with a public GET /health. Use this for containers, several replicas and remote access.
    • sse: The legacy SSE transport (/sse + /message). Its sessions live in one process's memory, so it only works with a single instance; prefer http.
    • The Vercel entry point (api/index.go) serves Streamable HTTP at /mcp (with /rpc and POST / as aliases) and still serves /sse and /message for existing clients.
  4. Logging: slog JSON through src/internal/logging (service github-backup-mcp, LOG_LEVEL), always on stderr, with one record per MCP request and per tool call (names, durations and outcomes, never arguments).

4. MCP Tools Specification​

The server exposes 15 tools in 5 groups. The tool definitions in src/backend/github-backup-mcp/tools/*.go are the source of truth for names and parameters:

github-backup-mcp
├── 1. Observability & Telemetry (Read-only)
│ ├── get_system_health
│ ├── get_dashboard_summary
│ ├── get_backup_metrics
│ └── list_tracked_repositories
├── 2. Diagnostics & Failure Triaging (Read-only)
│ ├── list_backup_runs
│ ├── get_backup_run_details
│ ├── get_execution_logs
│ └── diagnose_backup_failure
├── 3. Semantic Search & Memory (Read-only)
│ └── search_backup_knowledge
├── 4. Archive & File Inspection (Read-only / Safe Sandbox)
│ ├── verify_archive_integrity
│ ├── inspect_archive_contents
│ └── extract_backup_file
└── 5. Remediation & Operations (State-Modifying / HITL-Gated)
├── trigger_backup_run
├── record_backup_fix
└── send_backup_report

Category 1: Observability & Telemetry​

1. get_system_health​

  • Description: Verifies connectivity to Neon PostgreSQL, checks backup directory disk availability, reports active worker status, and returns API health indicators.
  • Parameters: None.
  • Output:
    {
    "database": {"status": "connected", "latency_ms": 14, "pool_open_connections": 3},
    "storage": {"archive_path": "_Repos", "total_disk_bytes": 107374182400, "available_disk_bytes": 68719476736},
    "backend_api": {"status": "reachable", "url": "http://localhost:8080"},
    "status": "HEALTHY"
    }

2. get_dashboard_summary​

  • Description: Retrieves high-level aggregated metrics across all backup history: total runs, overall success rate, distinct repos, total archive size, and latest analytics snapshot.
  • Parameters: None.
  • Output:
    {
    "total_runs": 150,
    "total_repos": 1250,
    "total_successful": 1180,
    "total_failed": 45,
    "success_rate": "94.40%",
    "last_run_status": "completed",
    "last_run_at": "2026-09-18T10:45:30Z",
    "total_size_bytes": 536870912,
    "largest_repository": "MishraShardendu22/large-repo"
    }

3. get_backup_metrics​

  • Description: Returns historical time-series metrics over a specified number of days, including daily run counts, success rates, and average duration.
  • Parameters:
    • days (integer, optional, default: 30): Days of history to analyze.
  • Output:
    {
    "period_days": 30,
    "average_run_duration_ms": 870000,
    "aggregated_success_rate": 0.944,
    "history": [
    {"date": "2026-09-17", "runs": 1, "successful": 42, "failed": 2, "avg_duration_ms": 850000}
    ]
    }

4. list_tracked_repositories​

  • Description: Lists tracked GitHub repositories, indicating privacy status, last backup timestamp, archive size, and repository URL.
  • Parameters:
    • page (integer, optional, default: 1)
    • limit (integer, optional, default: 50, max: 200)

Category 2: Diagnostics & Failure Triaging​

5. list_backup_runs​

  • Description: Retrieves paginated backup runs, optionally filtered by status (completed, failed, running).
  • Parameters:
    • page (integer, optional, default: 1)
    • limit (integer, optional, default: 20, max: 100)
    • status (string, optional): completed, failed or running.

6. get_backup_run_details​

  • Description: Retrieves complete execution details of a specific backup run, including all individual repository outcomes, durations, commit hashes, and error messages.
  • Parameters:
    • run_id (integer, required): The unique ID of the backup run.

7. get_execution_logs​

  • Description: Queries stored operational logs with filtering by severity level, backup run ID, or target repository.
  • Parameters:
    • run_id (integer, optional): Filter by backup run.
    • repository (string, optional): Filter by repository full name (e.g. owner/repo).
    • level (string, optional): One of INFO, WARN, ERROR, DEBUG (case-insensitive); omit it for every level.
    • limit (integer, optional, default: 50, max: 200).

8. diagnose_backup_failure​

  • Description: Compound Diagnostic Tool. Given a run_id (or defaulting to the latest failed run), this tool collects the failed repositories with their errors and error logs, attaches the three newest recorded fixes from backup_fixes, and returns one diagnostic packet for the LLM. For similar past incidents, follow up with search_backup_knowledge.
  • Parameters:
    • run_id (integer, optional): Run ID to diagnose. If omitted, finds the most recent failed run.
  • Output:
    {
    "run_id": 149,
    "failed_at": "2026-09-17T02:15:00Z",
    "failed_repos_count": 1,
    "failures": [
    {
    "repository": "MishraShardendu22/legacy-tool",
    "error_message": "fatal: early EOF / index-pack failed",
    "error_logs": [
    "2026-09-17T02:14:55Z [ERROR] fatal: read error: Connection reset by peer",
    "2026-09-17T02:15:00Z [ERROR] Clone failed after 3 retries"
    ],
    "last_successful_commit": "e5b8d4f",
    "similar_past_incidents": [
    {
    "run_id": 112,
    "resolution": "Increased git http.postBuffer to 524288000 in backup worker config"
    }
    ]
    }
    ],
    "recommended_actions": [
    "Check network buffer limits in src/services/github-backup-worker/config",
    "Verify GitHub API rate-limit headers"
    ]
    }

Category 3: Semantic Search & AI Knowledge Base​

9. search_backup_knowledge​

  • Description: Performs hybrid search (combining dense vector embeddings in pgvector and PostgreSQL full-text search with Reciprocal Rank Fusion) across historical logs, errors, past incident fixes, and chat investigations.
  • Parameters:
    • query (string, required): Search query (e.g. "clone timeout RPC failed", "SSH authentication failure").
    • limit (integer, optional, default: 5, max: 20).

Category 4: Archive & File Inspection​

Archives live in BACKUP_ARCHIVE_PATH (set it to the worker's _Repos directory) and are resolved by exact file name only, never by substring or outside that root. repo_name must be owner/name (GitHub naming rules) or, for legacy archives, a bare repository name. Candidates, in order:

  1. worker_repo_state.archive_key for the repository (when the worker's table from migration 000008 exists; keys that leave the root are ignored),
  2. <owner>__<repo>.bundle, then <owner>__<repo>.tar.gz (lower case),
  3. the legacy <repo>.tar.gz (as given, then case-insensitively when exactly one file matches).

Files are opened through os.Root, so neither .. nor a symbolic link leaves the root. .bundle archives need git on the MCP host (a clear tool error otherwise); each git command has a 3 minute timeout, bundles over 2 GiB are not unpacked, and scratch clones are always removed.

10. verify_archive_integrity​

  • Description: Computes the archive's SHA-256 and compares it with worker_repo_state.archive_sha256 when recorded (a mismatch is an error). Git bundles are checked with git bundle verify (header, refs, prerequisites) and unpacked into a scratch repository with git bundle unbundle, which checks every object (verify alone accepts a corrupted or truncated pack). tar.gz archives have every tar header read.
  • Parameters:
    • repo_name (string, required): owner/name, or a bare name for legacy archives.
  • Output (bundle):
    {
    "repository": "octo/repo",
    "archive": "octo__repo.bundle",
    "format": "bundle",
    "resolved_by": "worker_repo_state",
    "archive_size_bytes": 1048576,
    "sha256_checksum": "3a7b9c...",
    "expected_sha256": "3a7b9c...",
    "refs": ["refs/heads/main", "HEAD"],
    "pack_verified": true,
    "integrity_status": "VALID_UNCOMPROMISED"
    }

11. inspect_archive_contents​

  • Description: Lists files without extracting the archive: tar headers for tar.gz, the tree of the bundle's default branch (its HEAD, else main, master or the first branch) for bundles, read from a bounded scratch clone.
  • Parameters:
    • repo_name (string, required)
    • prefix (string, optional): Filter paths starting with this prefix (e.g. .github/, src/).
    • limit (integer, optional, default: 50, max 200).

12. extract_backup_file​

  • Description: Returns the content of one file (at most 10 MB) from the tar.gz archive or from the bundle's default branch (git cat-file).
  • Parameters:
    • repo_name (string, required)
    • file_path (string, required): Relative path within the archive (e.g. README.md, package.json); .., absolute paths, backslashes and NUL are rejected.

Category 5: Remediation & Operational Actions​

13. trigger_backup_run​

  • Description: Queues an on-demand backup run by inserting a row into backup_run_requests (created by the worker's migration 000008) with requested_by = 'mcp'. The worker claims pending requests at its next scheduled run; the tool does not start the worker. If a pending request for the same target exists, that request is returned with already_queued: true instead of queuing a duplicate. Needs DATABASE_URL; without it, or while the table does not exist, the tool returns an error.
  • Parameters:
    • target_repo (string, optional): owner/name, validated and stored in lower case; omit it for all tracked repositories.
    • reason (string, optional): Stored with the request (at most 500 characters).
  • Output:
    {
    "request_id": 12,
    "status": "pending",
    "target_repo": "octo/repo",
    "requested_by": "mcp",
    "reason": "config changed",
    "created_at": "2026-09-24T07:00:00Z",
    "already_queued": false,
    "message": "Backup run request queued; the worker picks it up on its next run."
    }
  • Safety Guardrail: Marked as an operational action. Antigravity and Claude will surface user confirmation when invoked.

14. record_backup_fix​

  • Description: Registers a permanent remediation resolution in the backup_fixes database table, optionally linked to one affected run. This preserves institutional knowledge so the AI agent and future runs know how an issue was resolved.
  • Parameters:
    • title (string, required): Concise description of the fix (e.g. "Increased git clone postBuffer to 500MB").
    • description (string, required): Detailed explanation of the root cause and applied fix.
    • author (string, required): Author identifier (e.g. "Antigravity Agent", "Claude Code", or human user).
    • commit_hash (string, optional): Git commit hash containing the code fix.
    • affected_run_id (integer, optional): The backup run this fix addresses.
  • Output: the stored fix with "status": "RECORDED_IN_DATABASE".

15. send_backup_report​

  • Description: POSTs {"subject", "content_markdown"} with X-Internal-Secret to <OBSERVATORY_URL>/reports/send. It succeeds only when the Observatory answers 2xx; a connection failure, any other status or an empty OBSERVATORY_URL is a tool error naming the status and message. Note: the Observatory's current /reports/send expects {"report_id"} and a user JWT, so this tool reports that refusal until the Observatory accepts MCP requests.
  • Parameters:
    • subject (string, required)
    • content_markdown (string, required)

5. MCP Resources & Prompts Specifications​

In addition to tools, the MCP protocol supports Resources (data URIs readable by agents) and Prompts (pre-composed agent workflows):

5.1 MCP Resources​

URI PatternNameMIME TypeDescription
backup://system/healthSystem Health Stateapplication/jsonLive connectivity, database latency, and storage stats
backup://runs/latestLatest Backup Run Summaryapplication/jsonSummary of the most recent backup execution

Repository and analytics resources are not implemented; use the list_tracked_repositories and get_backup_metrics tools.

5.2 MCP Prompts​

Prompt 1: diagnose-latest-failure​

  • Description: Automatically loads the latest failed run, queries execution logs, searches semantic past resolutions, and guides the LLM to provide a step-by-step remediation plan.
  • Arguments: None.
  • Template Context: Pre-fetches backup://runs/latest and injects system diagnostic instructions.

Prompt 2: audit-backup-health​

  • Description: Performs a complete health and storage audit of the backups: system health, tracked repositories, recent runs and archive storage.

A disaster-recovery prompt is not implemented; verify_archive_integrity, inspect_archive_contents and extract_backup_file cover a test restore.


6. Go Server Technical Architecture & Package Layout​

6.1 Package Layout​

The MCP server is part of the root Go module (github.com/MishraShardendu22/github-backup), not a separate module:

src/backend/github-backup-mcp/
├── cmd/github-backup-mcp/main.go # Entrypoint (--transport stdio|http|sse, --port)
├── internal/app/ # run.go (startup), http.go (Streamable HTTP), sse.go (legacy SSE)
├── config/config.go # Settings (DATABASE_URL, BACKEND_URL, OBSERVATORY_URL, MCP_AUTH_TOKEN, ...)
├── server/server.go # mcp-go server, tool/resource registration, result sanitizing middleware
├── transport/ # Bearer auth and the stateless Streamable HTTP handler
├── sanitizer/sanitizer.go # Token and secret redaction
├── tools/ # observability, diagnostics, search, archives (+ archive_bundle, archive_resolve), remediation, backend API fallback
├── resources/resources.go # backup:// resources and the two prompts
├── storage/db.go # pgxpool connection and queries
├── Dockerfile
└── README.md

The Vercel entry point is api/index.go at the repository root.

  1. MCP SDK: github.com/mark3labs/mcp-go
    • Most robust, standard-compliant Go implementation of Model Context Protocol (v2024-11-05).
    • Built-in support for server.NewStdioServer, server.NewStreamableHTTPServer (used in stateless mode) and server.NewSSEServer.
    • Automatic JSON Schema generation from Go struct parameters via mcp.NewTool.
  2. Database Driver: github.com/jackc/pgx/v5/pgxpool
    • High-performance, native PostgreSQL driver with connection pooling.
    • Matches the Go backend stack in src/backend/github-backup-api/.
  3. Structured Logging: log/slog through src/internal/logging (shared with the API).
    • Logs write strictly to stderr so they do not corrupt the JSON-RPC pipe on stdout in stdio mode.
  4. CLI Flags: github.com/spf13/pflag or standard flag package.

6.3 Core Code Implementation Patterns​

A. Entry Point & Transports (src/backend/github-backup-mcp/internal/app/run.go)​

The entry point parses --transport (stdio, http or sse; anything else is an error) and --port, builds the logger with server.NewLogger (stderr) and the optional pgxpool pool, and calls server.NewServer, which registers the tools, resources and prompts, installs the result sanitizer and registers the configured secrets with it. For http it serves transport.NewStreamableHTTP (stateless Streamable HTTP, standalone GET stream disabled) at /mcp behind transport.RequireBearerToken, plus a public GET /health, and shuts down gracefully on SIGINT/SIGTERM. The HTTP transports refuse to start without MCP_AUTH_TOKEN.

B. Tool Registration Example: Compound Diagnostic Tool (tools/diagnostics.go)​

package tools

import (
"context"
"fmt"
"log/slog"

"github.com/jackc/pgx/v5/pgxpool"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)

func registerDiagnosticTools(s *server.MCPServer, db *pgxpool.Pool, logger *slog.Logger) {
diagnoseTool := mcp.NewTool("diagnose_backup_failure",
mcp.WithDescription("Compound diagnostic tool that gathers failed repos, specific error logs, stack traces, and similar past incidents for a backup run."),
mcp.WithNumber("run_id",
mcp.Description("Optional backup run ID to diagnose. If omitted, triages the most recent failed run."),
),
)

s.AddTool(diagnoseTool, func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
var runID int64

if val, ok := req.Params.Arguments["run_id"]; ok && val != nil {
if num, ok := val.(float64); ok {
runID = int64(num)
}
}

// If no runID provided, find latest failed run
if runID == 0 {
err := db.QueryRow(ctx, "SELECT id FROM backup_runs WHERE status = 'failed' ORDER BY id DESC LIMIT 1").Scan(&runID)
if err != nil {
return mcp.NewToolResultError("No failed backup runs found in history"), nil
}
}

// 1. Fetch failing repos
rows, err := db.Query(ctx,
"SELECT repo_full_name, COALESCE(error_message, 'Unknown error') FROM backup_results WHERE run_id = $1 AND status = 'failed'",
runID)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("Failed to query run results: %v", err)), nil
}
defer rows.Close()

type FailureInfo struct {
Repo string `json:"repository"`
Error string `json:"error"`
Logs []string `json:"logs"`
}

var failures []FailureInfo
for rows.Next() {
var f FailureInfo
if err := rows.Scan(&f.Repo, &f.Error); err == nil {
failures = append(failures, f)
}
}

// 2. Fetch error logs for this run
logRows, err := db.Query(ctx,
"SELECT message FROM execution_logs WHERE run_id = $1 AND level = 'ERROR' ORDER BY id DESC LIMIT 10",
runID)
if err == nil {
defer logRows.Close()
for logRows.Next() {
var msg string
if err := logRows.Scan(&msg); err == nil && len(failures) > 0 {
failures[0].Logs = append(failures[0].Logs, msg)
}
}
}

resultJSON := fmt.Sprintf(`{"run_id": %d, "failures": %v}`, runID, failures)
return mcp.NewToolResultText(resultJSON), nil
})
}

7. Client Configuration & Integration Guide​

7.1 Integration with Google Antigravity​

Antigravity natively discovers and manages MCP servers via its global configuration file ~/.gemini/config/mcp_config.json or within workspace plugins.

Configuration (~/.gemini/config/mcp_config.json):​

{
"mcpServers": {
"github-backup": {
"command": "<path-to-repo>/src/backend/github-backup-mcp/bin/github-backup-mcp",
"args": ["--transport", "stdio"],
"env": {
"DATABASE_URL": "postgresql://DB_USER:DB_PASSWORD@DB_HOST/DB_NAME?sslmode=require",
"BACKEND_URL": "http://localhost:8080",
"BACKUP_ARCHIVE_PATH": "<path-to-repo>/src/services/github-backup-worker/_Repos"
}
}
}
}

Note: Once configured, Antigravity instantly populates all 15 tools in its agent context, visible via the UI under Additional Options (...) > MCP Servers.


7.2 Integration with Claude Desktop​

Claude Desktop starts local MCP servers over standard input/output (stdio); no token is needed because only the process that started the server can reach it.

Configuration:​

  • Linux: ~/.config/Claude/claude_desktop_config.json
  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"github-backup": {
"command": "<path-to-repo>/src/backend/github-backup-mcp/bin/github-backup-mcp",
"args": ["--transport", "stdio"],
"env": {
"DATABASE_URL": "postgresql://DB_USER:DB_PASSWORD@DB_HOST/DB_NAME?sslmode=require",
"BACKEND_URL": "http://localhost:8080"
}
}
}
}

To use a remote server (the Vercel deployment or --transport http), bridge it through the mcp-remote package, which forwards stdio to a Streamable HTTP endpoint and adds the header. This follows mcp-remote's documented --header usage; keeping the token in env avoids problems with spaces in arguments:

{
"mcpServers": {
"github-backup-remote": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://<your-deployment>/mcp", "--header", "Authorization:${MCP_AUTHORIZATION}"],
"env": { "MCP_AUTHORIZATION": "Bearer <MCP_AUTH_TOKEN>" }
}
}
}

7.3 Integration with Claude Code (CLI)​

Local server over stdio:

claude mcp add github-backup \
--env DATABASE_URL="postgresql://DB_USER:DB_PASSWORD@DB_HOST/DB_NAME?sslmode=require" \
-- /path/to/github-backup-mcp --transport stdio

Remote server over Streamable HTTP (the Vercel deployment's /mcp, or a local --transport http server):

claude mcp add --transport http github-backup https://<your-deployment>/mcp \
--header "Authorization: Bearer $MCP_AUTH_TOKEN"

or in a project .mcp.json (Claude Code expands ${VAR} from the environment):

{
"mcpServers": {
"github-backup": {
"type": "http",
"url": "http://localhost:8090/mcp",
"headers": { "Authorization": "Bearer ${MCP_AUTH_TOKEN}" }
}
}
}

Verify connection:

claude mcp list

7.4 Integration with Cursor​

In Cursor, configure MCP tools under .cursor/mcp.json in the workspace root:

{
"mcpServers": {
"github-backup": {
"command": "./src/backend/github-backup-mcp/bin/github-backup-mcp",
"args": ["--transport", "stdio"],
"env": {
"DATABASE_URL": "postgresql://...neon.tech/neondb?sslmode=require"
}
}
}
}

7.5 Remote Docker / HTTP Deployment (Multi-Agent & Team Access)​

For teams or agents running in cloud environments, the server can run as a container serving Streamable HTTP at /mcp on port 8090. The transport is stateless, so it can run as several replicas behind a load balancer. The image needs git for the .bundle archive tools and BACKUP_ARCHIVE_PATH pointing at the archives:

The image (src/backend/github-backup-mcp/Dockerfile) starts the Streamable HTTP transport (--transport http) and is already part of docker-compose.yml:

services:
github-backup-mcp:
build:
context: .
dockerfile: src/backend/github-backup-mcp/Dockerfile
ports:
- "8090:8090"
environment:
DATABASE_URL: *database-url
BACKEND_URL: http://github-backup-api:8080
OBSERVATORY_URL: http://github-backup-observatory:8000
INTERNAL_SECRET: ${INTERNAL_SECRET:?...}
MCP_AUTH_TOKEN: ${MCP_AUTH_TOKEN:?...} # required; the server refuses to start without it
MCP_PORT: "8090"
# The worker's git sink keeps its archives in _Repos on the shared volume.
BACKUP_ARCHIVE_PATH: /data/archives/_Repos
volumes:
- backups_data:/data/archives:ro

GET /health is served without the token for container health checks; every other route requires Authorization: Bearer $MCP_AUTH_TOKEN.

Clients use http://<host>:8090/mcp with Authorization: Bearer <MCP_AUTH_TOKEN> (see 7.2 and 7.3); GET /health is public. Requests that arrive over a loopback connection must name a localhost Host (DNS rebinding protection), so a reverse proxy on the same host must rewrite Host. The legacy --transport sse (/sse, /message) still works for a single instance only, because its sessions live in memory.

Client configuration for the HTTP transport:

{
"mcpServers": {
"github-backup-remote": {
"type": "http",
"url": "http://localhost:8090/mcp",
"headers": { "Authorization": "Bearer <MCP_AUTH_TOKEN>" }
}
}
}

8. Security, Guardrails & Human-In-The-Loop (HITL)​

8.1 Read-Only vs State-Modifying Segregation​

Tools are explicitly classified into safety tiers:

  • Safe / Read-Only (Unconditional): get_system_health, get_dashboard_summary, get_backup_metrics, list_tracked_repositories, list_backup_runs, get_backup_run_details, get_execution_logs, diagnose_backup_failure, search_backup_knowledge, verify_archive_integrity, inspect_archive_contents.
  • Operational / Mutation (Requires Confirmation):
    • trigger_backup_run: Queues a backup_run_requests row; the worker runs the backup (clones and uploads) on its next run.
    • record_backup_fix: Writes permanent data to PostgreSQL.
    • send_backup_report: Dispatches emails via external SMTP.

8.2 HTTP Transport Authentication​

Every network transport (the local --transport http and --transport sse servers and the serverless handler in api/index.go) requires Authorization: Bearer $MCP_AUTH_TOKEN on every request except GET /health.

  • If MCP_AUTH_TOKEN is not set, the local HTTP servers refuse to start and the serverless handler answers MCP requests with 503, so the tools are never exposed without a token.
  • The token is compared in constant time (src/backend/github-backup-mcp/transport/auth.go).
  • No CORS headers are sent. MCP clients are not browsers, and a wildcard origin would let any web page call the tools.
  • Generate a token with openssl rand -hex 32 and pass it to MCP clients as a request header.
  • Stdio mode is unaffected: it is only reachable by the local process that started it.

8.3 Sensitive Secret Redaction​

A tool handler middleware passes the text of every tool result, errors included, through sanitizer.Sanitize, which redacts:

  1. GitHub tokens: ghp_ (classic PAT), gho_ (OAuth), ghu_ (App user-to-server), ghs_ (App installation), ghr_ (refresh) with 36 or more characters, and fine-grained github_pat_ tokens.
  2. Passwords in PostgreSQL URLs, including driver suffixes such as postgresql+asyncpg://.
  3. OpenRouter API keys (sk-or-v1-[a-f0-9]{64}) and Bearer tokens.
  4. The configured secret values, raw and JSON-escaped: INTERNAL_SECRET, MCP_AUTH_TOKEN, the DATABASE_URL password, and SMTP_PASSWORD / JWT_SECRET when they are set in the MCP environment (values under 8 characters are skipped).

8.4 Resource Bounds & Tar Bomb Protection​

  • Single-file extraction (extract_backup_file) is restricted to files $\le 10\text{MB}$ to prevent memory exhaustion.
  • Path traversal protection enforces that extracted paths cannot escape the sandbox boundary (rejects ../ sequences).
  • Archives are resolved by exact name inside BACKUP_ARCHIVE_PATH through os.Root (see Category 4), so repo_name cannot select files elsewhere on the host.
  • Bundle operations run git through src/internal/gitexec (argv only, no prompts, process group killed on timeout) with a 3 minute timeout per command, skip unpacking bundles over 2 GiB and remove their scratch clones.
  • Database queries use strict context timeouts (15s limit) to avoid hanging client requests.

9. Phased Implementation Roadmap​

┌───────────────────────────────────────────────────────────────────────────────┐
│ MCP SERVER IMPLEMENTATION PHASES │
├───────────────────────────────────────────────────────────────────────────────┤
│ Phase 1: Foundation & Stdio Transport │
│ • Initialize Go module `mcp-server` │
│ • Setup `mark3labs/mcp-go` and Stdio lifecycle │
│ • Establish pgxpool database connection & health check tool │
│ │
│ Phase 2: Observability & Diagnostics Tools │
│ • Port dashboard statistics, run history, and execution log queries │
│ • Implement compound `diagnose_backup_failure` triage tool │
│ • Connect `search_backup_knowledge` to Python Observatory / pgvector │
│ │
│ Phase 3: Archive Inspection & Fix Management │
│ • Implement tar header inspection and SHA-256 integrity verification │
│ • Implement `record_backup_fix` for logging permanent hotfixes │
│ • Add safe single-file extraction sandbox │
│ │
│ Phase 4: MCP Resources, Prompts & Client Wiring │
│ • Register `backup://` resources and diagnostic prompt templates │
│ • Generate client configs for Antigravity, Claude Desktop, and Claude Code │
│ • Add Makefile targets: `make mcp-build`, `make mcp-run` │
└───────────────────────────────────────────────────────────────────────────────┘

Next Steps & Action Items​

  1. Review and approve the design document.
  2. Create feature branch: MishraShardendu22/main/go-mcp-server.
  3. Implement Phase 1 skeleton in src/backend/github-backup-mcp/.
  4. Register the MCP server in ~/.gemini/config/mcp_config.json to immediately test with Antigravity.