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.

服务介绍

  • Stateless — 不保存任何用户状态或会话数据,请求之间完全隔离;仅在进程内缓存派生出的短期 access token(见下文"认证")。

  • Concurrent-safe — 每请求的凭据与实例 base URL 通过 Python contextvars 隔离,并发请求之间绝不串号。

  • 多租户 — 每个请求自带 Passportal Access Key / Secret Access Key 与客户实例 base URL(gateway 模式),单个服务实例即可服务多个 Passportal 客户。

  • 认证 — Passportal 用的是 OAuth2 client-credentials、HMAC 签名的授权方式:本服务用长期的 Access Key / Secret Access Key 对,自己向 Passportal 换取短期(约 55 分钟)access token 并按租户缓存,调用方无需关心 HMAC 计算或 token 续期。凭据通过 x-passportal-access-key / x-passportal-secret-key 两个 Header 传入,x-passportal-base-url 传入客户实例地址。

上游 API 参考:

Related MCP server: paperless-mcp

Endpoints

Method

Path

Description

POST

/mcp

MCP protocol entry point

GET

/health

Health check

默认端口:8080(通过 MCP_HTTP_PORT 配置)。

HEADER 授权参数说明

Gateway 模式(默认、生产、SOP 合规)下,每个 /mcp 请求必须携带以下 Header:

x-passportal-access-key

项目

说明

类型

string

是否必填

必填

默认值

枚举值

字段描述

Passportal Access Key(对应授权请求里的 x-key),在 Passportal 门户生成。

Example

x-passportal-access-key: 11111111111111111111111111111111

x-passportal-secret-key

项目

说明

类型

string

是否必填

必填

默认值

枚举值

字段描述

Passportal Secret Access Key。本服务在进程内用它对每次 token 交换请求做 HMAC-SHA256 签名(x-hash),从不持久化、不转发给 Passportal 之外的任何地方。

Example

x-passportal-secret-key: 22222222222222222222222222222222

x-passportal-base-url

项目

说明

类型

string

是否必填

必填

默认值

枚举值

字段描述

客户 Passportal 实例的 Base URL(dashboard 地址的根,不含尾部 /)。例如 dashboard 为 https://instance.passportalmsp.com//dashboard#/default,则此处填 https://instance.passportalmsp.com

Example

x-passportal-base-url: https://instance.passportalmsp.com

缺少任一 Header 时,/mcp 请求返回 401,响应体的 required_headers 会列出所需的三个 Header 名。

内部授权流程(自动完成,调用方无需关心)

本服务收到上述三个 Header 后,在真正调用 Documents API 之前,会自动:

  1. 生成一段随机明文 content,用 Secret Access Key 对其计算 HMAC-SHA256 签名得到 x-hash(hex 编码)。

  2. POST {base_url}/api/v2/auth/client_token,Header 带 x-key(=Access Key)、x-hash,body 带 { "scope": "docs_api", "content": "<同一段明文>" },换回 access_token 与过期时间 expiry_time

  3. 用换到的 access_token 作为 x-access-token Header 调用真正的 Documents API(如 GET /api/v2/documents)。

  4. (base_url, access_key, secret_key) 的指纹在进程内缓存该 access_token,直到临近 expiry_time(默认无返回时按 55 分钟兜底)才重新走一次上述交换——避免每次工具调用都重新签名换 token。

调用方全程只需要提供 Access Key / Secret Access Key / base URL 这三项静态凭据,HMAC 计算、token 交换与续期均由本服务完成。

Tool List

passportal_list_documents

List documents from N-able Passportal —GET <base_url>/api/v2/documents。全部参数均为可选。

参数

类型

必填

枚举值

说明

resultsPerPage

integer

每页返回的结果数(正整数)。

pageNum

integer

页码 / 索引(正整数)。

orderBy

string

label, id

排序字段。

orderDir

string

asc, desc

排序方向。

type

string

asset, active_directory, application, backup, email, file_sharing, contact, location, internet, lan, printing, remote_access, vendor, virtualization, voice, wireless, licencing, custom, ssl

模板类型过滤。

templateUid

string

按具体模板过滤,接受 UID 或 ID(如 tpl-101101)。

clientId

integer

客户标识过滤。

searchTxt

string

基于文档属性的全文搜索。

响应为 Passportal 原始 JSON,结构大致为:

{
  "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(每请求 Header,SOP 合规)或 env(共享凭据,仅本地开发)。

PASSPORTAL_ACCESS_KEY_HEADER

No

x-passportal-access-key

gateway 模式下携带 Access Key 的 Header 名。

PASSPORTAL_SECRET_KEY_HEADER

No

x-passportal-secret-key

gateway 模式下携带 Secret Access Key 的 Header 名。

PASSPORTAL_BASE_URL_HEADER

No

x-passportal-base-url

gateway 模式下携带实例 base URL 的 Header 名。

PASSPORTAL_TOKEN_SCOPE

No

docs_api

token 交换请求的 scope,由 Passportal Documents API 固定,一般无需修改。

PASSPORTAL_ACCESS_KEY

env mode only

env 模式下使用的 Passportal Access Key。

PASSPORTAL_SECRET_KEY

env mode only

env 模式下使用的 Passportal Secret Access Key。

PASSPORTAL_BASE_URL

env mode only

env 模式下的客户实例 base URL,如 https://instance.passportalmsp.com

MCP_TRANSPORT

No

http

传输方式:httpstdio

MCP_HTTP_PORT

No

8080

HTTP 监听端口。

MCP_HTTP_HOST

No

0.0.0.0

HTTP 监听地址。

env 模式(仅本地开发,非生产 SOP 合规):设置 AUTH_MODE=envPASSPORTAL_ACCESS_KEYPASSPORTAL_SECRET_KEYPASSPORTAL_BASE_URL,所有请求共享同一凭据,切勿用于生产 / 多租户。

Quick Start

HTTP server (gateway mode — 默认,SOP 合规)

uv sync
uv run nable-passportal-mcp
# 每请求通过 x-passportal-access-key + x-passportal-secret-key + x-passportal-base-url
# Header 传入凭据与实例地址;本服务内部自动完成 HMAC 签名与 token 交换/续期

HTTP server (env mode — 仅本地开发)

cp .env.example .env
# 编辑 .env:AUTH_MODE=env、PASSPORTAL_ACCESS_KEY=...、PASSPORTAL_SECRET_KEY=...、
#           PASSPORTAL_BASE_URL=https://<instance>.passportalmsp.com
uv sync
uv run nable-passportal-mcp
# 服务启动于 http://0.0.0.0:8080

Docker

docker compose up --build

Test Examples

Health check

curl http://localhost:8080/health

预期响应:

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

Initialize(MCP 握手)

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"
      }
    }
  }'

第一次调用会先触发一次内部 HMAC token 交换(略增延迟),后续约 55 分钟内的调用复用缓存的 access token。

Security

  • 每请求的 Access Key / Secret Access Key / base URL 存放于 contextvars.ContextVar,请求结束后立即 reset,绝不跨租户串号。

  • 换来的短期 access token(约 55 分钟有效期)按 (base_url, access_key, secret_key) 指纹在进程内缓存,纯为避免每次工具调用都重新做一次 HMAC 签名 + 网络往返;缓存只存派生出的短期 token,不存 Secret Access Key 本身,也不落盘、不跨进程持久化。

  • Secret Access Key 只在进程内用于计算 x-hashauth.py::compute_x_hash),从不被记录到日志,也不会转发给 Passportal 之外的任何地方。

  • 容器以非 root 用户运行。

  • 切勿提交真实 Access Key / Secret Access Key —— .gitignore 已排除 .env

Related MCP Connectors

Related MCP Servers