Skip to main content
Glama

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


Related MCP server: paperless-mcp

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.

Related MCP Connectors

Related MCP Servers