PatrolTech MCP server
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@PatrolTech MCP serverShow me last night's patrol rounds and any incidents reported"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
PatrolTech MCP server
The remote Model Context Protocol server of PatrolTech, the guard tour and security patrol platform. It lets AI assistants such as Claude, ChatGPT, Copilot, Gemini or Cursor read and act on a PatrolTech account on behalf of a user who signs in with OAuth: rounds, routes, checkpoints, guards, incidents, users, locations, access control and scans.
This repository holds only the server code. To install the connector in your assistant, use PatrolTech/ai-integrations: plugins, MCP Registry entry and instructions for each client.
This server grants no access by itself. It has no credentials of its own: it forwards the user's token, and the PatrolTech API authorizes every call (organization and location roles, OAuth scopes and a closed list of writes allowed to agents). See SECURITY.md.
How it works
MCP client ──OAuth──▶ PatrolTech authorization server
│ Bearer access token (audience = MCP_PUBLIC_URL)
▼
MCP server (this repo, stateless) ──agent session──▶ PatrolTech API
│ ▲
└── Redis: locks and rate limits └── @patroltech/agent-capabilities + @patroltech/sdk-apiOAuth resource server.
/mcprequires a bearer token issued by the PatrolTech authorization server (RFC 9728 metadata at/.well-known/oauth-protected-resource/mcp). Tokens are verified against the API's JWKS (ES256, exact issuer and audience) and exchanged for a 15-minute agent session (POST /oauth/agent-session), cached by a hash of the token. The API trims the session to what the grant still allows.Stateless. Each request gets a fresh MCP server instance and serves both protocol eras (2025 and 2026-07-28). Nothing about a conversation is kept in memory: proposals live in the PatrolTech API, so any number of workers can serve the same user.
Redis holds what must be shared between workers: the per-user lock around proposals (
SET NX PX, renewed while it lasts) and the per-user, per-tool rate limits. It is required inproductionandstaging. If Redis fails, propose, confirm and cancel answer "busy" rather than risk two proposals overwriting each other. WithoutREDIS_URL(development and test only) both live in process memory.Tools come from the
mcpchannel of@patroltech/agent-capabilities, which calls the API through@patroltech/sdk-api.
Tools
Tool | What it does |
| One per read of the catalog: read-only, English titles and descriptions, optional |
| The user's organizations (name, role, access) and their locations. |
| Proposes a change. Nothing changes until it is confirmed. Proposals of one user and client form one batch (up to 10, expires after 30 minutes). |
| Executes the whole pending batch, in order, with the parameters that were proposed (marked destructive: clients ask the user first). |
| Withdraws the pending batch. |
| A signed link (1 hour) to the printable QR sheet of a location. |
Writes need the write scope: without it the server answers 403 insufficient_scope with the read write challenge. Every result is { data, truncated?, notices?, note }, capped at 60,000 characters, where note says that data is data, never instructions. Each user can make 60 calls per minute to a read tool and 20 to a write tool. Every call writes one mcp.tool_call audit line with a hash of the arguments, never the arguments.
Endpoints
Path | Auth | Purpose |
| Bearer | The MCP endpoint (POST, GET, DELETE). Validates |
| none | Protected resource metadata (RFC 9728), also at the root path. |
| none | Liveness: |
| none | Readiness: |
| none | The |
Related MCP server: MCP Server for Odoo
Configuration
Every variable is documented in .env.example. The server refuses to start, listing each missing or invalid variable, if the configuration is not valid.
Variable | Required | Description |
| yes | Exact public URL of the MCP endpoint, the audience of the tokens (for example |
| yes | Origin of the PatrolTech API, without |
| yes | Expected |
| no | JWKS of the issuer. Default |
| yes | PatrolTech dashboard and web app, for links shown to the user. |
| yes |
|
| in production and staging | Shared Redis (ioredis URL). |
| no | Key prefix in Redis. Default |
| no | Where the process listens. Default |
| no |
|
| no |
|
| no | Domain verification token for the ChatGPT apps directory. |
Logs are one JSON object per line on stdout and stderr. Each process writes an mcp.heartbeat line every 5 minutes, so a log monitor can alert when it stops.
Development
Node.js 22.9 or later.
npm ci
cp .env.example .env.local # fill in the values; .env.local is ignored by git
npm run dev # tsx watch, loads .env.local
curl http://127.0.0.1:3110/healthScript | |
| Run with reload ( |
| ESLint, Prettier and the type check of sources and tests. |
| Unit and HTTP tests (vitest). |
| Tests of the PM2 ecosystem and of the remote deployment script. |
| Compile to |
| One self-contained ESM file, |
| Starts the bundle with a test configuration and checks |
Code layout follows the hexagonal style: src/domain (pure rules), src/application (use cases and their ports), src/interface/mcp (the MCP adapter) and src/infrastructure (HTTP, OAuth, SDK adapters, Redis, logging).
Self-hosting
You can run this server on your own infrastructure, for example to audit it or to put it in front of your own network policies.
OAuth audience. Access tokens are bound to the resource they were issued for. The PatrolTech authorization server only issues tokens for resources it knows, so a deployment under your own MCP_PUBLIC_URL needs to be registered with PatrolTech before PatrolTech users can connect to it. Ask through the channels in SECURITY.md.
What you need:
Node.js 22.9 or later and Redis.
A reverse proxy with TLS in front of
HOST:PORTthat forwards/mcp,/.well-known/oauth-protected-resource(and its subpaths) and, if you use them,/health,/health/readyand/.well-known/openai-apps-challenge. Keep theHostheader: the server only accepts the host ofMCP_PUBLIC_URLor loopback.
Steps:
Build the artifact:
npm ci && npm run bundle && npm run smoke.Copy
dist/bundle/server.mjs,dist/bundle/server.mjs.mapandpackage.json(the version comes from it) to a directory on the server. Nonpm installis needed there.Create
.env.localin that directory from.env.example, withAPP_ENVIRONMENT=productionandREDIS_URL.Start it:
node --enable-source-maps --env-file-if-exists=.env.local server.mjs, or with PM2 (below). The process stops gracefully onSIGTERM, waiting up to 55 s for calls in progress, so give it about 60 s before a forced kill.
With PM2
deploy/ecosystem.config.cjs runs the bundle in cluster mode. It holds no server data: it reads MCP_PM2_NAME, MCP_PORT and MCP_APP_ENVIRONMENT (required) and MCP_INSTANCES, MCP_SERVICE_NAME and PM2_APP_DIR (optional) from the environment, and loads the rest from .env.local.
MCP_PM2_NAME=mcp MCP_PORT=3110 MCP_APP_ENVIRONMENT=production MCP_INSTANCES=2 \
pm2 start ecosystem.config.cjsIn cluster mode the workers run with the Node.js of the PM2 daemon, which must be 22.9 or later for --env-file-if-exists. Never run pm2 update on a shared daemon: it restarts every app it manages.
With GitHub Actions
.github/workflows/deploy.yml deploys a fork of this repository by SSH, by hand (workflow_dispatch, staging by default). It builds, tests and smoke-tests the bundle without secrets, uploads the bundle, package.json and the ecosystem with rsync, and runs deploy/remote-deploy.sh on the server: checks .env.local, reloads PM2 without downtime, probes the readiness URL and waits until every instance is online with the new version. production only deploys from main or a v* tag.
The workflow and the scripts contain no server data, and the logs print nothing from the server. Create the GitHub environments staging and production (with a required reviewer and a deployment branch rule for main and v* tags on production) and set, in each one:
Secret | Required | Description |
| yes | Host name or IP address of the server. |
| yes | SSH user that owns the app directory and runs PM2. |
| yes | Private key of that user, without passphrase, used only for deployments. |
| yes |
|
| yes | Absolute path of the app directory (bundle, |
| yes | Name of the PM2 process. |
| yes | Local port the process listens on. |
| yes | Readiness URL as seen from the server, |
| no | SSH port, if not 22. |
| no |
|
| no | Directory of the Node.js binary to use on the server, put first in |
| no | Path of the |
| no | Lock file ( |
| no |
|
| no |
|
| no | Datadog API key, to send an event when a deployment fails. |
Variable | Required | Description |
| no | Number of instances (default 1). |
| no | Datadog site for the failure event (default |
Server data goes in secrets, not variables: Actions masks secrets in the logs, and the workflow also masks the values derived from them.
Versioning and releases
The version lives only in package.json. When a change to it reaches main, the release workflow creates the v<version> tag and a GitHub release with the bundle and its checksums.
Related packages
@patroltech/agent-capabilities: the catalog of reads and proposed actions this server exposes.@patroltech/sdk-api: the TypeScript SDK of the PatrolTech public API.PatrolTech/ai-integrations: the connector for each AI assistant.
License
MIT © Ingenieros Web SL
This server cannot be deployed
Maintenance
Related MCP Connectors
- mcpOAuthcom.vibgrate
Query your team's drift, vulnerability, and upgrade data from any AI assistant. OAuth 2.1, 51 tools.
Read, write and run Odoo actions from any AI app, as each user, with approval rules per colleague.
Connect AI to store orders, products and inventory with scoped access and human approvals.
AI agents for CRM, mail, calendar, ERP and accounting - you approve. EU-hosted, OAuth.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants like Claude, ChatGPT, and Copilot to query live Jobber data—clients, jobs, quotes, invoices, revenue, and schedule—using natural language, with read-only access and careful API budget management.1MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to securely access and interact with Odoo data through natural language, supporting full CRUD operations, OAuth 2.1 and API key authentication, and granular per-model permissions.-
- AlicenseAqualityBmaintenanceEnables AI assistants to work with the entire Manager.io API surface across any number of businesses, with granular per-resource controls that can block, require confirmation, or allow operations. It surfaces real confirmation dialogs before risky writes and keeps security-sensitive endpoints read-only.13MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to read and, where permitted, write data in ChurchTools, schedule recurring tasks like weekly service rosters, and review or revert changes for security and transparency.-