MSPbotsAIFramework

nable-passportal-mcp

Community MSPbotsAIFramework
Updated

nable-passportal-mcp

nable-passportal-mcp

A stateless HTTP MCP service for the N-able Passportal Documents API. It exposes Passportal API v2 operations as Model Context Protocol (MCP) tools consumable by Claude and other MCP clients.

MSPbots Connector

The MCP Gateway built for MSPs: visible, controlled, and your data stays where it belongs.

Get started at connect.mspbots.ai →

MSPbots Connector gives your AI clients one MCP URL to reach your entire MSP stack (RMM, PSA, documentation, security, finance), and gives you control over who can call which tool and a record of everything that was called.

Hosted service: connect.mspbots.ai · Free to use.

Why Connector

MSPbots Connector

Visible Every tool call is logged: who, which vendor, when. Usage dashboard, CSV export, SIEM streaming.
Controlled Role-based, per-tool allowlist. Deny by default.
Protected Credentials encrypted per record. AI clients never see your vendor passwords or tokens.
MSP-native Built for the MSP stack only: RMM, PSA, documentation, security, finance.

Quick start

  1. Sign up at connect.mspbots.ai.
  2. Connect your vendors. Pick from 150+ connectors and authorize each one on the vendor's own page, or bring your own API keys. No extra vendor accounts needed.
  3. Set access. Create roles and decide which tools each role may call. Nothing is allowed until you allow it.
  4. Add your MCP URL to your AI client. Copy the URL from your Connector dashboard into Claude, ChatGPT, Cursor, VS Code, Gemini, Codex, or any MCP-capable client.
  5. Ask your AI to do real work, and watch every call appear in the audit log.

Features

Unified gateway

  • One MCP URL for all your AI clients
  • 150+ connectors across the MSP stack
  • Custom MCP servers supported, free
  • Authorization happens on each vendor's own page; the AI never sees passwords or tokens
  • Bring your own credentials: use the vendor API keys you already have
  • Multiple accounts per app; connect once, reuse across AI clients
  • Tool search: finds the right action for the task
  • One sign-in; vendor credentials are injected behind the scenes and OAuth tokens refresh automatically

Visibility

  • Audit log for every tool call (who, which vendor, when)
  • Usage dashboard: call volume, top vendors, error rate, per-user activity
  • Export audit logs to CSV, or stream to Loki, Graylog, or LogScale (SIEM)
  • Optional recording of tool arguments and result summaries (off by default, enabled per organization)

Control

  • Per-role, per-tool allowlist, deny by default
  • owner / admin / member roles
  • SCIM provisioning with Entra ID, Okta, JumpCloud, and Google Workspace

Security

  • Credentials encrypted one record at a time (AES-256-GCM, per-record key)
  • AI clients authenticate with OAuth 2.1 + PKCE
  • Vendor responses are scanned for prompt-injection patterns and returned as structured data. This is one layer of defense, not a guarantee against every attack.
  • Static egress IP for customer firewall and API allowlisting

Pricing

Free.

Links: connect.mspbots.ai · mspbots.ai

Service overview

  • Stateless — No user state or session data is stored; requests are fully isolated from each other. Only the derived short-lived access token is cached in-process (see "Authentication" below).
  • Concurrent-safe — Per-request credentials and the instance base URL are isolated through Python contextvars, so concurrent requests never get mixed up.
  • Multi-tenant — Each request carries its own Passportal Access Key / Secret Access Key and the customer instance base URL (gateway mode), so a single service instance can serve multiple Passportal customers.
  • Authentication — Passportal uses an OAuth2 client-credentials, HMAC-signed authorization scheme: this service uses the long-lived Access Key / Secret Access Key pair to obtain a short-lived (about 55 minutes) access token from Passportal and caches it per tenant, so callers do not need to deal with HMAC computation or token renewal. Credentials are passed in the x-passportal-access-key / x-passportal-secret-key headers, and the customer instance address in x-passportal-base-url.

Upstream API references:

Endpoints

Method Path Description
POST /mcp MCP protocol entry point
GET /health Health check

Default port: 8080 (configured via MCP_HTTP_PORT).

HEADER authorization parameters

In Gateway mode (default, production, SOP-compliant), every /mcp request must carry the following headers:

x-passportal-access-key

Item Description
Type string
Required Yes
Default None
Allowed values None
Description Passportal Access Key (corresponds to x-key in the authorization request), generated in the Passportal portal.
Example x-passportal-access-key: 11111111111111111111111111111111

x-passportal-secret-key

Item Description
Type string
Required Yes
Default None
Allowed values None
Description Passportal Secret Access Key. This service uses it in-process to HMAC-SHA256 sign each token exchange request (x-hash); it is never persisted and never forwarded anywhere other than Passportal.
Example x-passportal-secret-key: 22222222222222222222222222222222

x-passportal-base-url

Item Description
Type string
Required Yes
Default None
Allowed values None
Description Base URL of the customer's Passportal instance (the root of the dashboard address, without a trailing /). For example, if the dashboard is https://instance.passportalmsp.com//dashboard#/default, enter https://instance.passportalmsp.com here.
Example x-passportal-base-url: https://instance.passportalmsp.com

If any header is missing, the /mcp request returns 401, and required_headers in the response body lists the three required header names.

Internal authorization flow (automatic; callers do not need to care)

After receiving the three headers above, and before actually calling the Documents API, this service automatically:

  1. Generates a random plaintext content and computes an HMAC-SHA256 signature over it with the Secret Access Key to get x-hash (hex-encoded).
  2. POST {base_url}/api/v2/auth/client_token, with headers x-key (= Access Key) and x-hash, and body { "scope": "docs_api", "content": "<the same plaintext>" }, and gets back access_token and the expiry time expiry_time.
  3. Uses the obtained access_token as the x-access-token header to call the actual Documents API (e.g. GET /api/v2/documents).
  4. Caches the access_token in-process keyed by the fingerprint of (base_url, access_key, secret_key), and only repeats the exchange above when expiry_time is near (falling back to 55 minutes if none is returned), so that every tool call does not need to re-sign and re-exchange the token.

Callers only need to provide the three static credentials (Access Key / Secret Access Key / base URL); HMAC computation, token exchange and renewal are all handled by this service.

Tool List

passportal_list_documents

List documents from N-able Passportal —GET <base_url>/api/v2/documents. All parameters are optional.

Parameter Type Required Allowed values Description
resultsPerPage integer No — Number of results returned per page (positive integer).
pageNum integer No — Page number / index (positive integer).
orderBy string No label, id Sort field.
orderDir string No asc, desc Sort direction.
type string No asset, active_directory, application, backup, email, file_sharing, contact, location, internet, lan, printing, remote_access, vendor, virtualization, voice, wireless, licencing, custom, ssl Filter by template type.
templateUid string No — Filter by a specific template; accepts a UID or ID (e.g. tpl-101 or 101).
clientId integer No — Filter by customer identifier.
searchTxt string No — Full-text search based on document attributes.

The response is the raw Passportal JSON, with roughly the following structure:

{
  "success": true,
  "apiRequestUid": "string",
  "results": [
    {
      "id": 0,
      "organization_id": 0,
      "label": "string",
      "description": "string",
      "client_id": 0,
      "customId": "string",
      "templateId": 0,
      "templateName": "string",
      "type": "string"
    }
  ],
  "description": "string"
}

Configuration

Variable Required Default Description
AUTH_MODE No gateway gateway (per-request headers, SOP-compliant) or env (shared credentials, local development only).
PASSPORTAL_ACCESS_KEY_HEADER No x-passportal-access-key Header name carrying the Access Key in gateway mode.
PASSPORTAL_SECRET_KEY_HEADER No x-passportal-secret-key Header name carrying the Secret Access Key in gateway mode.
PASSPORTAL_BASE_URL_HEADER No x-passportal-base-url Header name carrying the instance base URL in gateway mode.
PASSPORTAL_TOKEN_SCOPE No docs_api scope of the token exchange request, fixed by the Passportal Documents API; usually no need to change.
PASSPORTAL_ACCESS_KEY env mode only — Passportal Access Key used in env mode.
PASSPORTAL_SECRET_KEY env mode only — Passportal Secret Access Key used in env mode.
PASSPORTAL_BASE_URL env mode only — Customer instance base URL in env mode, e.g. https://instance.passportalmsp.com.
MCP_TRANSPORT No http Transport: http or stdio.
MCP_HTTP_PORT No 8080 HTTP listen port.
MCP_HTTP_HOST No 0.0.0.0 HTTP listen address.

env mode (local development only, not production SOP-compliant): set AUTH_MODE=env, PASSPORTAL_ACCESS_KEY, PASSPORTAL_SECRET_KEY and PASSPORTAL_BASE_URL; all requests share the same credentials, so never use it in production / multi-tenant setups.

Quick Start

HTTP server (gateway mode — default, SOP-compliant)

uv sync
uv run nable-passportal-mcp
# Credentials and the instance address are passed per request via the x-passportal-access-key + x-passportal-secret-key + x-passportal-base-url
# headers; this service handles HMAC signing and token exchange/renewal internally

HTTP server (env mode — local development only)

cp .env.example .env
# Edit .env: AUTH_MODE=env, PASSPORTAL_ACCESS_KEY=..., PASSPORTAL_SECRET_KEY=...,
#           PASSPORTAL_BASE_URL=https://<instance>.passportalmsp.com
uv sync
uv run nable-passportal-mcp
# Service starts at http://0.0.0.0:8080

Docker

docker compose up --build

Test Examples

Health check

curl http://localhost:8080/health

Expected response:

{"status": "ok", "transport": "http", "auth_mode": "gateway"}

Initialize (MCP handshake)

curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "x-passportal-access-key: your_access_key" \
  -H "x-passportal-secret-key: your_secret_access_key" \
  -H "x-passportal-base-url: https://instance.passportalmsp.com" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "capabilities": {},
      "clientInfo": {"name": "curl", "version": "1.0"}
    }
  }'

List tools

curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "x-passportal-access-key: your_access_key" \
  -H "x-passportal-secret-key: your_secret_access_key" \
  -H "x-passportal-base-url: https://instance.passportalmsp.com" \
  -d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}'

Call passportal_list_documents

curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "x-passportal-access-key: your_access_key" \
  -H "x-passportal-secret-key: your_secret_access_key" \
  -H "x-passportal-base-url: https://instance.passportalmsp.com" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "passportal_list_documents",
      "arguments": {
        "resultsPerPage": 20,
        "pageNum": 1,
        "orderBy": "label",
        "orderDir": "asc",
        "type": "asset"
      }
    }
  }'

The first call triggers an internal HMAC token exchange (slightly more latency); subsequent calls within about 55 minutes reuse the cached access token.

Security

  • Each request's Access Key / Secret Access Key / base URL is stored in a contextvars.ContextVar and reset immediately after the request ends, so it never leaks across tenants.
  • The obtained short-lived access token (valid for about 55 minutes) is cached in-process keyed by the (base_url, access_key, secret_key) fingerprint, purely to avoid redoing an HMAC signature + network round trip for every tool call; the cache holds only the derived short-lived token, not the Secret Access Key itself, and it is never written to disk or persisted across processes.
  • The Secret Access Key is only used in-process to compute x-hash (auth.py::compute_x_hash); it is never logged and never forwarded anywhere other than Passportal.
  • The container runs as a non-root user.
  • Never commit real Access Key / Secret Access Key values — .gitignore already excludes .env.

MCP Server · Populars

MCP Server · New

    bex-co

    Beancount.io Backend

    💰 Double-entry bookkeeping made easy — plain-text accounting for humans and AI agents. Polished iOS & Android app built with React Native + Expo.

    Community bex-co
    nkapila6

    mcpsurfr

    Local web search MCP server, formerly mcp-local-rag. Multi-engine deep research with on-device re-ranking. ✨ no API keys ✨

    Community nkapila6
    convex

    mcp.ts

    The open-source reactive database for app developers

    Community convex
    convex

    convex-backend

    The open-source reactive database for app developers

    Community convex
    Tripo-Developer

    Tripo MCP Server

    Official MCP server for Tripo

    Community Tripo-Developer