Gavriel MCP
πͺ½ Gavriel MCP
Local MCP server (TypeScript) that exposes the Gavriel API β alarm monitoring system β as tools for AI agents (OpenCode, Claude Desktop).
Documentation
Document | Purpose |
Minimum | |
Optimization ledger and context metrics. | |
Inventoried and unimplemented endpoints (backlog). |
Requirements
Node.js 20+ (tested with Node 22/24)
Gavriel user credentials (
app.gavriel.com.ar)
Installation
cd ~/proyectos/gavriel-mcp
pnpm install # package manager: pnpm (see packageManager in package.json)
pnpm build
cp .env.example .env # fill in GAVRIEL_EMAIL and GAVRIEL_PASSWORDConfiguration
src/config.ts reads these variables (from .env or the environment):
Variable | Required | Default |
| yes | β |
| no* | β (see secret resolution) |
| no | β (dev fallback; normally in keyring) |
| no |
|
| no |
|
| no |
|
| no |
|
| no |
|
Server Roles (GAVRIEL_MCP_ROLE)
full(default): all tools, including write tools (withconfirm).lite: read access + core writes (tickets, interventions, conversations).readonly: read-only; write tools are not registered (they do not exist for the agent). Includesgetandaudit_logs, which are GETs.
Without the variable β full (current behavior). confirm remains in effect in
all roles: role = availability, confirm = approval. The actual security role is
the Gavriel user the server logs in with.
Service Role Configuration
The service role is defined in docs/PROPUESTA_ROL_SERVICIO.md. The
recommended configuration is to use the MCP Service role (read-only) as the
default.
Note: currently the MCP logs in with an
Adminaccount (full CRUD). This is the current undesired state that the role proposal aims to replace, not a supported usage mode. Configuring theAdminaccount only makes sense as an interim step until theMCP Servicerole is created.
The JWT is cached in memory (never on disk) and renewed ~5 minutes before
expiration or after a 401. The API renews the token through the x-new-token
header, which the client automatically respects.
Secret Resolution
The server resolves password and trusted_device_token at startup, in this
order (see src/secrets.ts):
System keyring (
secret-tool,libsecret-toolspackage): most secure, and the recommended method.Environment variables
GAVRIEL_PASSWORD/GAVRIEL_TRUSTED_DEVICE_TOKEN(useful for local development outside OpenCode).Legacy files (
~/.secrets/gavriel-passwordand~/.local/share/gavriel-mcp/trusted-device.json): last resort only, with an explicit warning on stderr.
The JWT is cached in memory (never on disk) and renewed ~5 minutes before
expiration or after a 401. The API renews the token through the x-new-token
header, which the client automatically respects. The trusted_device_token (valid
for ~20 days and bypasses 2FA on subsequent logins) is also stored in the keyring.
Registering it in OpenCode
Install libsecret-tools (if not already installed) and store both secrets once,
interactively (the value is requested through stdin and is not included on the
command line):
sudo apt install libsecret-tools # if needed (daemon: gnome-keyring)
secret-tool store --label="Gavriel MCP - password" service gavriel-mcp account password
secret-tool store --label="Gavriel MCP - trusted device token" service gavriel-mcp account trusted_device_tokenThe server reads them only from the keyring; the OpenCode config no longer needs the secret:
{
"mcp": {
"gavriel": {
"type": "local",
"command": ["node", "/path/to/project/gavriel-mcp/dist/index.js"],
"environment": {
"GAVRIEL_EMAIL": "user@example.com"
}
},
"enabled": true
}
}Interim (until migration): if
secret-toolis not installed, the server falls back to~/.secrets/gavriel-password(chmod 600) with a warning. In that case the OpenCode config can still use{file:~/.secrets/gavriel-password}as it does today.
Tools
MCP names do not use a prefix. When using them from an OpenCode session,
OpenCode prepends the server name: create_ticket is exposed as
gavriel_create_ticket.
Read Operations (do not require confirm)
Tool | What it does |
| Lists tickets (filters: status, priority, accountId, categoryId, assignedUserId, search). Max. pagination 200. |
| Ticket + activities (comments) by ID. |
| Ticket + account + activities in ONE call. |
| Global ticket statistics. |
| Number of open technical tickets (by accountId). |
| Lists events/alarms (accountId, port, eventCode, dateFrom, dateTo, pendingβ¦). |
| Accounts with pending events (for bulk intervention). |
| 24-hour event chart (per connection or global). |
| Event by ID with its relationships. |
| Event + account + connection in ONE call. |
| Full account (zones, contacts, users, interventions). |
| Account + devices + interventions + pending events in ONE call. |
| Accounts with pending events and their details (bulk processing). |
| Search accounts by name/code. |
| Devices, partitions, and zones of an account. |
| Users and contacts of an account. |
| Useful contacts (by jurisdiction). |
| Interventions for an account ( |
| Activities for a ticket / global statistics. |
| Helpdesk conversations, their messages, and stats. |
| Connections and status report per connection. |
| Logs and disk space for a bridge. |
| Service panel, technician agenda, and locations. |
| Companies and their technicians. |
| Users, roles, and own profile. |
| System audit logs. |
| Connection and bridge health logs. |
| Quick search with reduced fields (for resolving IDs). |
| Audit of event type/code mapping. |
| Free GET over a whitelist of read-only endpoints. |
Write Operations β all require confirm: true
The gate is Phase 0, rule 2: if confirm is missing or false, the tool
does not execute anything and returns a preview (method + path + body). If
confirm: true, it executes and logs the operation in writes.log.
Tool | Action |
| Create an in-progress intervention on an account. |
| Process pending events in bulk (reason + accounts). |
| Close an intervention (creates/closes a ticket and marks events as processed). |
| Put an intervention under observation with a comment. |
| Create a ticket. |
| Change the status/priority/assignee/fields of a ticket. |
| Close a ticket with a resolution. |
| Add a comment/activity to a ticket. |
| Mark one or more events as processed. |
| Mark multiple events as processed in bulk. |
| Mark events to a state by filter (account required; preview of IDs before confirmation). |
| Close multiple tickets in bulk with the same resolution. |
| Add the same note to up to 100 accounts (ID deduplication). |
| Update account fields. |
| Account log/notes. |
| Send a message in a helpdesk conversation. |
| Conversation management. |
| Mark as read/unread and edit an activity. |
| Add and edit account contacts. |
| Set the final order of all contacts (spacing Γ10 for future insertions). |
| Schedule and edit services. |
| Technician and company non-working days. |
| CRUD for the event type and code catalog. |
| CRUD for the brand/model and device catalog. |
Important: always test first with confirm omitted/false and review the
preview. Perform the first real execution of each tool in the presence of the
operator β these are real production customer data.
Resources (semi-static catalogs, 1 h cache)
gavriel://catalog/... for event-types, event-codes, event-formats,
protocols, intervention-categories, device-brands (and active ones), device-models,
device-connection-types (and active ones), device-taxonomies, states, cities,
jurisdictions, zones, ticket status/priority options, ticket-categories,
activity type-options, event-types/gavriel-intervention, and
company/type/technical.
Unimplemented Endpoints (Tier 3)
Write endpoints that exceed the approved risk profile (deletions,
user/role management, monitoring activation, billing, catalogs,
files) are inventoried in TIER3_PENDIENTE.md and are not implemented
without explicit instruction.
Write Log
Every executed write operation is logged in
~/.local/share/gavriel-mcp/writes.log (JSONL): timestamp, tool, parameters,
JWT user email, and API response (status + summarized body).
This is in addition to Gavriel's own audit log (/audit/logs).
Deployment
It is not deployed: it is local, using stdio transport. It does not require Docker or the Hyper-V host.
Verification
pnpm typecheck # types
pnpm build # compiles to dist/
pnpm selfcheck # quick offline core invariants suite (no network)
pnpm regression # compares tool vs endpoint against the real backend (requires .env and network)Security
Secrets (
passwordandtrusted_device_token) live in the system keyring (recommended); the legacy~/.secrets/gavriel-password(chmod 600) remains only as an interim fallback with a warning. The.envfile in the repository (gitignored) is a local runtime fallback.The JWT is never persisted to disk.
The
confirmgate prevents accidental executions; control over when writes are used remains at the agent's skill/prompt level rather than being blocked in code (project owner's decision).Unparseable responses: occasionally the backend may return HTTP 200 with a truncated or invalid body. This tool detects it (
writeStatus: "applied_response_unparseable"), logs the raw body, and re-reads the resource to verify the actual state. Do not assume success or failure for this status: check the returnedverifiedStateor re-query the resource.