Skip to main content
Glama

Portero

A self-hosted MCP (Model Context Protocol) gateway that sits between Claude Code and multiple MCP servers, providing:

  • MCP Aggregation — Connect multiple MCPs and expose them as one unified endpoint

  • Data Anonymization — Bidirectional fake↔real data replacement for privacy

  • Async 2FA Approvals — Non-blocking Telegram approval flow with task tracking

  • Permission Policies — Allow/deny/require-approval per tool

  • Remote Access — HTTPS endpoint accessible from anywhere

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    TELEGRAM BOT                             │
│  /status, /grant, /revoke, /tasks, approval callbacks       │
│  Executes approved tasks asynchronously                     │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                      PORTERO                                │
│  ┌────────────────────────────────────────────────────────┐│
│  │ HTTP Server (Express)                                  ││
│  │ - POST /mcp/message (JSON-RPC, Bearer auth)           ││
│  │ - GET /health                                          ││
│  └────────────────────────────────────────────────────────┘│
│  ┌────────────────────────────────────────────────────────┐│
│  │ Middleware Pipeline                                    ││
│  │ 1. Anonymization (fake→real on requests)              ││
│  │ 2. Policy Check (allow/deny/require-approval)         ││
│  │ 3. If approval needed → create task, return pending   ││
│  │ 4. If allowed → route to child MCP immediately        ││
│  │ 5. Anonymization (real→fake on responses)             ││
│  └────────────────────────────────────────────────────────┘│
│  ┌────────────────────────────────────────────────────────┐│
│  │ Task Store (data/tasks.json)                          ││
│  │ pending-approval → approved → executing → completed   ││
│  └────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
                      │ stdio
        ┌─────────────┼─────────────┬─────────────┐
        ▼             ▼             ▼             ▼
   ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
   │ MCP 1   │  │ MCP 2   │  │ MCP 3   │  │ MCP 4   │
   │(github) │  │(filesys)│  │(google) │  │(stripe) │
   └─────────┘  └─────────┘  └─────────┘  └─────────┘

Related MCP server: MCPHub

Prerequisites

  • Node.js 20+ (LTS recommended)

  • Telegram Bot (create via @BotFather)

  • Your Telegram Chat ID (get from @userinfobot)

Quick Start

1. Clone and Install

git clone <your-repo-url>
cd portero
npm install

2. Configure Environment

cp .env.example .env
# Edit .env with your settings

Required settings in .env:

# Generate a secure token
BEARER_TOKEN=$(openssl rand -hex 32)

# Get from @BotFather
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11

# Get from @userinfobot
TELEGRAM_ADMIN_CHAT_ID=123456789

# Your real info (for anonymization)
REAL_NAME="Your Name"
REAL_EMAIL="your@email.com"

3. Configure MCP Servers

Edit config/mcps.json to define which MCP servers to connect:

{
  "mcps": [
    {
      "name": "filesystem",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
      "env": {}
    },
    {
      "name": "github",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  ]
}

4. Configure Google Workspace (Optional)

To add Gmail, Calendar, and Drive integration via workspace-mcp:

  1. Create a Google Cloud project at console.cloud.google.com

  2. Enable APIs: Gmail API, Google Calendar API, Google Drive API

  3. Create OAuth 2.0 credentials: APIs & Services → Credentials → Create Credentials → OAuth client ID → Desktop app

  4. Set environment variables in .env:

    GOOGLE_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
    GOOGLE_OAUTH_CLIENT_SECRET=your-client-secret
  5. First run: The workspace-mcp server will open a browser for OAuth consent. Approve the requested scopes.

  6. Headless / Docker: Run once locally to complete the OAuth flow, then copy the token cache into the container.

If GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET are not set, Portero will skip the Google MCP and start without it.

The Google tools appear as google/send_email, google/list_events, google/search_files, etc. Write operations (send, create, delete) require Telegram approval; reads are allowed by default. See config/policies.json for the full list.

5. Configure Notion (Optional)

To add Notion integration:

  1. Create a Notion integration at notion.so/my-integrations

  2. Copy the Internal Integration Secret (starts with ntn_)

  3. Share pages/databases with the integration: Open a page → ... → Connections → Add your integration

  4. Set environment variable in .env:

    NOTION_API_TOKEN=ntn_your-token-here

If NOTION_API_TOKEN is not set, Portero will skip the Notion MCP and start without it. Read operations (search, retrieve pages/blocks) are allowed by default; write operations (create/update/delete) require Telegram approval.

6. Configure Stripe (Optional)

To add Stripe integration for payment management:

  1. Get your Stripe API key from dashboard.stripe.com/apikeys

  2. Set environment variable in .env:

    STRIPE_API_KEY=sk_test_your-key-here

If STRIPE_API_KEY is not set, Portero will skip the Stripe MCP and start without it.

Default policies:

  • Read tools (list/get customers, invoices, payments, subscriptions, balance) — allow

  • Write tools (create customer, invoice, payment, refund, subscription) — require-approval

7. Configure Data Anonymization

Edit config/replacements.json to define fake↔real mappings:

{
  "replacements": [
    {
      "fake": "John Doe",
      "real": "${REAL_NAME}",
      "bidirectional": true
    },
    {
      "fake": "john@example.com",
      "real": "${REAL_EMAIL}",
      "bidirectional": true,
      "caseSensitive": false
    }
  ]
}

8. Configure Policies

Edit config/policies.json to set permission rules:

{
  "policies": {
    "github/create_issue": "allow",
    "github/create_pull_request": "require-approval",
    "filesystem/write_file": "require-approval",
    "filesystem/read_file": "allow",
    "filesystem/delete_file": "deny",
    "*": "allow"
  },
  "defaultPolicy": "allow"
}

9. Generate SSL Certificates (Optional)

./scripts/generate-certs.sh

Or skip SSL for local testing (uses HTTP).

10. Start the Gateway

# Development mode (with hot reload)
npm run dev

# Production mode
npm run build
npm start

Docker Deployment

# Build and start with docker-compose
docker-compose up -d

# View logs
docker-compose logs -f

# Stop
docker-compose down

Connect from Claude Code

Add to your Claude Code MCP configuration:

{
  "mcpServers": {
    "portero": {
      "transport": "http",
      "url": "https://your-server:8443/mcp/message",
      "headers": {
        "Authorization": "Bearer your-bearer-token-here"
      }
    }
  }
}

Add to Claude Code system prompt:

Your identity:
- Name: John Doe
- Email: john@example.com
Use these when asked for personal information.

Telegram Bot Commands

Once running, message your bot:

  • /status - Show connected MCPs, active grants, pending approvals

  • /grant <pattern> <duration> - Grant temporary access

    • Examples: /grant github/* 30m, /grant * 1h

  • /revoke - Revoke all active grants

  • /allow <pattern> - Persistently allow a tool/pattern (no approvals needed)

  • /deny <pattern> - Persistently deny a tool/pattern

  • /rules - List persistent rules

  • /unrule <id> - Remove a persistent rule

  • /tasks - Show recent tasks grouped by status

  • /pending - Show pending approval requests

  • /logs - Show recent audit logs

  • /help - Show all commands

How Async Approval Works

Portero uses a fully asynchronous approval flow — the HTTP request is never blocked waiting for Telegram approval.

  1. Claude Code calls a tool (e.g., github/create_pull_request)

  2. Gateway checks policy: requires approval

  3. Gateway creates a task (status: pending-approval), sends Telegram message with Approve/Deny buttons, and returns immediately with a task ID

  4. Claude Code receives { status: "pending-approval", taskId: "..." } and can continue working

  5. Admin approves/denies via Telegram buttons

  6. If approved, Portero executes the tool in the background and stores the result

  7. Claude Code calls portero/check_task with the task ID to retrieve the result

  8. If not ready yet, Claude Code can call portero/check_task again later

This means:

  • No timeout pressure — approvals can happen whenever

  • Claude Code stays responsive while waiting

  • Multiple approvals can be pending simultaneously

Virtual Tools

Portero injects these virtual tools alongside your MCP tools:

Tool

Description

portero/search_tools

Search available tools by keyword or category

portero/call

Call any tool by its full name (useful for non-pinned tools)

portero/check_task

Check status/result of a pending or completed async task

portero/list_tasks

List recent tasks with optional status filter

Configuration Reference

Data Anonymization

Replacements support:

  • Bidirectional — Replace in both directions (fake↔real)

  • One-way — Replace only fake→real, use responseReplacement for responses

  • Case sensitivity — Set caseSensitive: false for case-insensitive matching

Permission Policies

Policy actions:

  • allow — Allow without approval

  • deny — Block completely

  • require-approval — Request Telegram approval (async)

Patterns support wildcards:

  • github/* — All GitHub tools

  • */delete_* — All delete operations

  • * — All tools

Policy priority (highest first):

  1. Persistent rules (from Telegram /allow, /deny commands)

  2. Config exact matches (from config/policies.json)

  3. Config pattern matches (wildcards)

  4. Default policy

Temporary Grants

Skip approval for a limited time:

/grant github/* 30m      # Grant GitHub access for 30 minutes
/grant * 1h              # Grant all access for 1 hour
/revoke                   # Revoke all grants immediately

Security Considerations

  1. Bearer Token — Generate a strong random token:

    openssl rand -hex 32
  2. SSL/TLS — Use HTTPS in production (Let's Encrypt, self-signed, or reverse proxy)

  3. Telegram — Only your admin chat ID can control the bot

  4. Firewall — Restrict gateway port (8443) to authorized IPs

  5. Environment Variables — Never commit .env to git

Development

Project Structure

portero/
├── src/
│   ├── index.ts                 # Entry point
│   ├── config/                  # Config loader & types
│   ├── gateway/                 # HTTP server & MCP handler
│   ├── mcp/                     # MCP client management
│   ├── middleware/              # Anonymizer, policy, approval
│   ├── telegram/                # Telegram bot & admin store
│   ├── db/                      # File-backed JSON storage
│   ├── storage/                 # Atomic file operations & paths
│   └── utils/                   # Logger, crypto
├── config/                      # JSON config files
├── data/                        # Runtime data (auto-created)
└── scripts/                     # Helper scripts

Build Commands

npm run dev      # Development with hot reload
npm run build    # Compile TypeScript
npm start        # Start production build

Storage

File-backed JSON storage in ./data/:

  • approvals.json — Legacy pending approvals (kept for backward compatibility)

  • tasks.json — Async task tracking (pending → approved → executing → completed)

  • grants.json — Temporary access grants

  • rules.json — Persistent policy rules (from /allow, /deny commands)

  • audit.ndjson — Append-only audit log (NDJSON format)

Troubleshooting

Gateway won't start

  • Check Node.js version: node -v (should be 20+)

  • Verify .env file exists and has all required variables

  • Check logs in ./logs/combined.log

MCP connection fails

  • Verify MCP command is correct in config/mcps.json

  • Check MCP is installed: npx -y @modelcontextprotocol/server-github --version

  • Check environment variables are set (e.g., GITHUB_TOKEN)

  • MCPs with missing env vars are skipped automatically (non-blocking)

Telegram bot not responding

  • Verify bot token is correct

  • Check admin chat ID matches your Telegram ID

  • Ensure bot was started with /start

Claude Code can't connect

  • Verify bearer token matches in Claude Code config

  • Check SSL certificates if using HTTPS

  • Test with curl:

    curl -X POST https://localhost:8443/health

Contributing

Contributions welcome! Please:

  1. Fork the repository

  2. Create a feature branch

  3. Make your changes

  4. Submit a pull request

License

MIT License - see LICENSE file for details

Support

  • GitHub Issues: [Report bugs or request features]


Built for Claude Code users who want privacy, security, and control over their MCP connections.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An MCP server for communication service connectors that currently provides multi-account Telegram integration with granular tool access and security controls. It allows AI models to manage messages, chats, and media across various accounts through a flexible, extensible routing architecture.
    1
    -
  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    A unified gateway and dashboard that aggregates multiple MCP servers into a single endpoint for streamlined management by AI clients. It features a centralized YAML configuration, a web-based monitoring dashboard, and hot-reload support for managing filesystem, GitHub, and database tools.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCPGate aggregates multiple MCP servers into a single unified endpoint, enabling centralized tool management with granular filtering, automatic namespacing, and observability. Features a real-time web dashboard and optional PostgreSQL-backed audit trails for monitoring and controlling AI tool access across local and remote deployments.
    5 npm
    Apache 2.0