npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@teamnetwork-nz/mailstore-spe-mcp

v0.1.0

Published

MCP server providing a curated, safety-gated administrator interface over the MailStore Service Provider Edition (SPE) Management API. Multi-instance aware, read-only by default, with access modes, confirmation gating, capability discovery, and bounded st

Readme

MailStore SPE MCP Server

A Model Context Protocol (MCP) server that provides a curated, safety-gated administrator interface over the MailStore Service Provider Edition (SPE) 26.3 Management API.

It is deliberately opinionated: rather than exposing every raw API function, it offers a concise set of high-level tools suitable for reliable LLM use — multi-instance aware, read-only by default, with graduated access modes, exact confirmation strings for state changes, capability discovery against live metadata, and bounded, structured, secret-free output.

Verified against a live MailStore SPE 26.3.1.24182 installation.


Contents


Architecture

RooCode / Cline
      │  SSE
      ▼
   Caddy  (TLS, access control)
      │
      ▼
 Supergateway  (SSE ⇄ stdio)
      │  stdio
      ▼
 mailstore-spe-mcp   ← this project
      │  HTTPS + Basic auth
      ▼
 MailStore SPE Management Server (:8474)

Internally the server is layered so the MailStore client is independent of the MCP SDK:

src/
  config/       env parsing & validation (Zod)
  mailstore/    client, encoder, response-parser, operation-poller,
                metadata, capability-registry, instance-resolver, errors
  policy/       access-mode, tool-policy (risk classes), confirmations, redaction
  output/       tool-result, truncation, normalizers
  tools/        platform, instances, users, profiles, jobs, stores, smtp,
                compliance, maintenance, raw-api, register-tools
  resources/    health + read-only resources
  server.ts     wires everything together
  index.ts      stdio bootstrap

Prerequisites

  • Node.js 22 LTS (for local runs) or Docker
  • Network reachability to the MailStore SPE Management API over HTTPS (default TCP 8474)
  • A dedicated MailStore SPE system administrator account (see below)

MailStore account setup

Use a dedicated SPE system administrator account for the MCP — not a personal admin login.

  • The Management API uses HTTP Basic authentication over HTTPS.
  • Where MFA is enabled for the system administrator, you must use the administrator's API password rather than the interactive password. The MailStore API exposes CreateSystemAdministratorAPIPassword to generate one.
  • Grant the account only the privileges the deployment needs. Read-only monitoring needs far less than administrator mode.

Configuration

All configuration comes from environment variables (or Docker secrets). Copy .env.example to .env and fill it in. MAILSTORE_BASE_URL must not include /api.

Required

| Variable | Description | |----------|-------------| | MAILSTORE_BASE_URL | e.g. https://mailstore.example.com:8474 (HTTPS, no /api) | | MAILSTORE_USERNAME | SPE administrator / API account username | | MAILSTORE_PASSWORD | Password or API password (never logged) |

Recommended

| Variable | Default | Description | |----------|---------|-------------| | MAILSTORE_VERIFY_TLS | true | Verify the server certificate. Disable only in a lab. | | MAILSTORE_CA_FILE | — | Path to a custom CA bundle (PEM). | | MAILSTORE_REQUEST_TIMEOUT_MS | 30000 | Per-request timeout. | | MAILSTORE_LONG_POLL_TIMEOUT_MS | 25000 | Long-poll window for async operations. | | MAILSTORE_OPERATION_TIMEOUT_MS | 1800000 | Overall timeout for long-running operations. | | MAILSTORE_METADATA_CACHE_TTL_SECONDS | 3600 | Metadata cache TTL. | | MAILSTORE_INSTANCE_CACHE_TTL_SECONDS | 60 | Instance-list cache TTL. | | MCP_ACCESS_MODE | read-only | read-only | operator | administrator. | | MCP_ENABLE_RAW_API | false | Enable the generic escape-hatch tool. | | MCP_ALLOW_DESTRUCTIVE | false | Permit destructive tools. | | MCP_ALLOW_BULK_INSTANCE_ACTIONS | false | Reserved; first release keeps single-target only. | | MCP_MAX_RESULT_ITEMS | 200 | Cap on list results before truncation. | | LOG_LEVEL | info | debug | info | warn | error. | | LOG_FORMAT | json | json | pretty. |


Access modes

Tools are registered — and therefore visible to the model — only when the current mode permits them. Read-only mode exposes no mutating tools at all.

| Mode | Adds | |------|------| | read-only | Retrieval, reporting, health checks. | | operator | Run profile/job, cancel job, test SMTP, dry-run directory sync, verify a store, refresh statistics, start/stop/restart a single instance. | | administrator | Create/update/delete users, set passwords, apply directory sync, change retention policies. |

Destructive tools (mailstore_delete_user, mailstore_verify_all_stores, mailstore_set_retention_policies) additionally require MCP_ALLOW_DESTRUCTIVE=true, and are not registered otherwise.


Running locally (stdio)

npm install
npm run build
MAILSTORE_BASE_URL=https://mailstore.example.com:8474 \
MAILSTORE_USERNAME=mcp-api \
MAILSTORE_PASSWORD=... \
MCP_ACCESS_MODE=read-only \
npm start

Or in watch mode during development: npm run dev.

The process communicates over stdio: stdout carries only MCP protocol messages; all logs go to stderr.


Docker deployment

Multi-stage build, runs as the non-root node user, no credentials baked in:

docker build -t teamnetwork/mailstore-spe-mcp:latest .

See docker-compose.example.yml for a full stack. Provide secrets via environment or Docker secrets.


Supergateway + Caddy

RooCode requires SSE. Supergateway converts the stdio server to SSE; Caddy terminates TLS and restricts access. Suggested hostname:

https://mcp-mailstore.ai.example.net.nz/sse

Minimal Caddyfile:

mcp-mailstore.ai.example.net.nz {
    # import your standard auth / IP allowlist snippet here
    encode gzip
    reverse_proxy mailstore-mcp:8115 {
        # SSE needs unbuffered, HTTP/1.1 proxying
        flush_interval -1
        transport http {
            versions 1.1
        }
    }
}

Supergateway command (see compose file):

--stdio "node dist/index.js" --port 8115 --cors --healthEndpoint /healthz

The MCP server must not assume it is directly exposed to the Internet — always front it with Caddy.


RooCode / Cline configuration

RooCode (SSE):

{
  "mcpServers": {
    "mailstore-spe": {
      "type": "sse",
      "url": "https://mcp-mailstore.ai.example.net.nz/sse",
      "timeout": 60
    }
  }
}

Cline (stdio, running the built server directly):

{
  "mcpServers": {
    "mailstore-spe": {
      "command": "node",
      "args": ["/app/dist/index.js"],
      "env": {
        "MAILSTORE_BASE_URL": "https://mailstore.example.com:8474",
        "MAILSTORE_USERNAME": "mcp-api",
        "MAILSTORE_PASSWORD": "...",
        "MCP_ACCESS_MODE": "read-only"
      }
    }
  }
}

Adjust key names to your client's current schema.


Tool catalogue

Every instance-scoped tool takes an instance selector (exact instanceID, alias, or display name — resolved to exactly one instance; ambiguous names are rejected). Tools requiring confirmation take a confirmation string (see below).

| Tool | Mode | Notes | |------|------|-------| | mailstore_ping | read-only | Connectivity + auth check. | | mailstore_get_environment | read-only | Version / environment. | | mailstore_get_service_status | read-only | SPE service status. | | mailstore_get_platform_summary | read-only | Composed platform overview. | | mailstore_list_instances | read-only | Instances with state filter/search. | | mailstore_get_instance | read-only | Config + optional stats/stores (sizes off by default). | | mailstore_get_instance_statistics | read-only | Archive statistics. | | mailstore_list_users | read-only | | | mailstore_get_user | read-only | | | mailstore_list_profiles | read-only | | | mailstore_get_profile_results | read-only | Worker results (handles timeZoneID spelling). | | mailstore_list_jobs | read-only | | | mailstore_get_job_results | read-only | | | mailstore_list_stores | read-only | includeSize off by default (slow). | | mailstore_get_smtp_settings | read-only | Secrets redacted. | | mailstore_get_compliance | read-only | Compliance + retention + policy hash. | | mailstore_start_instance | operator | Single instance; confirm START <id>. | | mailstore_stop_instance | operator | Single instance; confirm STOP <id>. | | mailstore_restart_instance | operator | Single instance; confirm RESTART <id>. | | mailstore_run_profile | operator | Confirm RUN PROFILE <id> IN <instance>. | | mailstore_run_job | operator | Confirm RUN JOB <id> IN <instance>. | | mailstore_cancel_job | operator | Confirm CANCEL JOB <id> IN <instance>. | | mailstore_verify_store | operator | Confirm VERIFY STORE <id> IN <instance>. | | mailstore_refresh_store_statistics | operator | Confirm REFRESH STORE STATISTICS IN <instance>. | | mailstore_test_smtp | operator | Confirm TEST SMTP IN <instance>. | | mailstore_sync_directory_users | operator (dry-run) / administrator (apply) | Dry run by default. | | mailstore_create_user | administrator | Confirm CREATE USER <userName> IN <instance>. | | mailstore_update_user | administrator | Only changes the fields you pass. | | mailstore_set_user_password | administrator | Password never returned. | | mailstore_delete_user | administrator + destructive | Confirm DELETE USER <userName> FROM <instance>. | | mailstore_verify_all_stores | administrator + destructive | Expensive; confirm VERIFY ALL STORES IN <instance>. | | mailstore_set_retention_policies | administrator + destructive | Optimistic-concurrency hash guard. | | mailstore_refresh_capabilities | administrator | Reload API metadata. | | mailstore_invoke_api | administrator + MCP_ENABLE_RAW_API | Allow-listed generic invoke; denylist enforced. |

Phase-two tools (instance/store/credential/profile/job lifecycle, store transfer/merge/repair/recovery) are intentionally not in the first release. See the specification.


Confirmation model

State-changing tools require an exact confirmation string, generated from the resolved instance and target. Generic words (yes, confirm, proceed) are rejected. Examples:

  • STOP customer-a
  • DELETE USER jsmith FROM customer-a
  • CHANGE RETENTION POLICIES IN customer-a

If you omit or mismatch it, the tool returns CONFIRMATION_REQUIRED / CONFIRMATION_MISMATCH with the exact string required — nothing is executed. Retry with that string.

mailstore_set_retention_policies additionally requires expectedCurrentHash (from mailstore_get_compliance); if the live policies changed since you read them, the change is refused with CONCURRENT_MODIFICATION.


Resources

Read-only MCP resources (no credentials exposed):

  • mailstore://health — reachability, auth, TLS, version, access mode
  • mailstore://environment
  • mailstore://service-status
  • mailstore://instances
  • mailstore://capabilities

Error model

Errors are structured with a stable code, a concise message, and safe details — never secrets, auth headers, or stack traces:

{ "code": "AMBIGUOUS_INSTANCE", "message": "The instance name matched multiple MailStore instances.", "details": { "matches": [ ... ] } }

Codes: CONFIGURATION_ERROR, AUTHENTICATION_FAILED, AUTHORIZATION_FAILED, TLS_ERROR, MAILSTORE_UNAVAILABLE, MAILSTORE_API_ERROR, MAILSTORE_OPERATION_FAILED, MAILSTORE_OPERATION_TIMEOUT, UNSUPPORTED_FUNCTION, INVALID_ARGUMENT, INSTANCE_NOT_FOUND, AMBIGUOUS_INSTANCE, OBJECT_NOT_FOUND, CONFIRMATION_REQUIRED, CONFIRMATION_MISMATCH, ACCESS_MODE_DENIED, DESTRUCTIVE_ACTION_DISABLED, CONCURRENT_MODIFICATION, RESULT_TOO_LARGE.


Development & testing

npm install
npm run build         # tsc
npm run typecheck     # tsc --noEmit
npm run lint          # eslint
npm test              # vitest (unit + mock server + in-process MCP)

Unit tests cover the safety boundaries (form encoding, BOM handling, envelope/error parsing, long-operation polling and timeout, retry policy, metadata & argument validation, instance resolution & ambiguity, confirmations, access-mode gating, secret redaction, output truncation, time-zone parameter spelling). A mock MailStore server exercises the client end-to-end, and an in-process MCP client verifies that read-only mode registers no mutating tools and that confirmations are enforced.

Live integration tests (opt-in, read-only)

tests/integration/live-readonly.test.ts runs strictly read-only checks against a real server when MAILSTORE_BASE_URL is configured (via .env). It never mutates. Run with:

npm run test:integration

Mutating integration tests are intentionally not included; if you add any, gate them behind MAILSTORE_MUTATION_TESTS=true and a dedicated MAILSTORE_TEST_INSTANCE — never a production customer instance.

Note on live metadata vs. published reference: the live SPE metadata is the source of truth. This server was aligned to it — e.g. GetProfiles requires a raw argument, GetWorkerResults uses timeZoneID/profileID (capitalised) while GetJobResults uses timeZoneId/jobId, SetRetentionPolicies takes a single config JSON argument, and user privilege/email/POP3 lists are comma-separated strings, not JSON arrays.


Troubleshooting

| Symptom | Likely cause | |---------|--------------| | CONFIGURATION_ERROR at startup | Missing/invalid env var, or MAILSTORE_BASE_URL includes /api. | | AUTHENTICATION_FAILED | Wrong username/password, or MFA account needs an API password. | | TLS_ERROR | Untrusted certificate — set MAILSTORE_CA_FILE, or MAILSTORE_VERIFY_TLS=false for a lab only. | | Startup aborts: missing essential functions | The account/server lacks core API functions; check API access. | | A tool is missing | It requires a higher access mode, the destructive flag, or an API function unavailable on this server. | | AMBIGUOUS_INSTANCE | The name matches multiple instances — pass the exact instanceID. | | SSE drops / hangs behind Caddy | Ensure unbuffered HTTP/1.1 proxying (flush_interval -1). |


License

MIT