MCP Servers
Overview
Model Context Protocol (MCP) is an open standard that allows AI models to invoke external tools and access external resources through a standardised JSON-RPC interface. TRCAA integrates MCP as a first-class feature, enabling the AI triage assistant to call tools exposed by any compliant MCP server — file search, database queries, monitoring APIs, runbook automation, and more.
MCP support extends the AI's capabilities beyond conversation: during incident triage, the model can autonomously invoke registered tools to gather diagnostic data, check system status, or execute remediation steps — all within the app's security and audit framework.
Architecture
┌──────────────────────────────────────────────┐
│ TRCAA App │
│ │
│ ┌────────┐ ┌──────────┐ ┌───────────┐ │
│ │Frontend│──▶│ Commands │──▶│ Store │ │
│ │ React │ │(IPC/Tauri)│ │ (SQLite) │ │
│ └────────┘ └────┬─────┘ └───────────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Discovery │ │
│ └─────┬─────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ │ │ │ │
│ ┌────▼────┐ ┌────▼────┐ ┌───▼────┐ │
│ │ stdio │ │ HTTP │ │Adapter │ │
│ │Transport│ │Transport│ │(AI glue)│ │
│ └────┬────┘ └────┬────┘ └────────┘ │
└───────┼─────────────┼────────────────────────┘
│ │
▼ ▼
Local process Remote HTTP
(e.g. npx) MCP endpoint
Module layout (src-tauri/src/mcp/):
| File | Responsibility |
|---|---|
models.rs |
Struct definitions: McpServer, McpTool, McpResource, request types |
store.rs |
CRUD operations against SQLite (encrypted at rest) |
transport/stdio.rs |
Stdio process spawn via rmcp (absolute path enforced) |
transport/http.rs |
Streamable HTTP transport via rmcp |
client.rs |
Connection lifecycle, tool listing, tool invocation |
adapter.rs |
Name sanitisation, McpTool → AI Tool conversion |
discovery.rs |
Per-server and bulk startup discovery orchestration |
commands.rs |
8 Tauri IPC command handlers |
Database Schema
Three tables are created by Migration 018 (018_mcp_servers). Migration 023 adds the env_config column.
mcp_servers
| Column | Type | Constraints |
|---|---|---|
id |
TEXT | PRIMARY KEY |
name |
TEXT | NOT NULL |
url |
TEXT | NOT NULL |
transport_type |
TEXT | NOT NULL, CHECK IN ('stdio', 'http') |
transport_config |
TEXT | NOT NULL DEFAULT '{}' (JSON) |
auth_type |
TEXT | NOT NULL, CHECK IN ('none', 'api_key', 'bearer', 'oauth2') |
auth_value |
TEXT | Nullable — AES-256-GCM encrypted |
env_config |
TEXT | Nullable — AES-256-GCM encrypted JSON object of env vars |
enabled |
INTEGER | NOT NULL DEFAULT 1 |
last_discovered_at |
TEXT | Nullable UTC timestamp |
discovery_status |
TEXT | NOT NULL DEFAULT 'pending', CHECK IN ('pending', 'connected', 'unreachable', 'error') |
discovery_error |
TEXT | Nullable |
created_at |
TEXT | NOT NULL DEFAULT datetime('now') |
updated_at |
TEXT | NOT NULL DEFAULT datetime('now') |
mcp_tools
| Column | Type | Constraints |
|---|---|---|
id |
TEXT | PRIMARY KEY |
server_id |
TEXT | NOT NULL, FK → mcp_servers(id) ON DELETE CASCADE |
name |
TEXT | NOT NULL (original tool name from server) |
tool_key |
TEXT | NOT NULL (sanitised key used by AI) |
description |
TEXT | Nullable |
parameters |
TEXT | NOT NULL DEFAULT '{}' (JSON Schema) |
mcp_resources
| Column | Type | Constraints |
|---|---|---|
id |
TEXT | PRIMARY KEY |
server_id |
TEXT | NOT NULL, FK → mcp_servers(id) ON DELETE CASCADE |
uri |
TEXT | NOT NULL |
name |
TEXT | Nullable |
description |
TEXT | Nullable |
Cascade deletes ensure that removing a server automatically cleans up its tools and resources.
Transport Types
stdio
The app spawns a local process and communicates over its stdin/stdout using the MCP JSON-RPC protocol.
Configuration (transport_config JSON):
{
"command": "/usr/local/bin/my-mcp-server",
"args": ["--port", "0", "--mode", "stdio"],
"env": {
"DEBUG": "1",
"LOG_LEVEL": "info"
}
}
command— must be an absolute path. Relative paths are rejected to prevent path traversal attacks.args— optional array of command-line arguments.env— optional object of plaintext environment variables for non-sensitive values.
Sensitive environment variables (API keys, tokens) are stored separately in the env_config column (AES-256-GCM encrypted) and merged with plaintext env vars at discovery time. Encrypted values take precedence over plaintext for duplicate keys.
The process is spawned via Tokio and wrapped with rmcp::transport::TokioChildProcess.
Important: PATH for npx/node-based servers
When TRCAA spawns a stdio process from a macOS .app bundle, it runs in a stripped environment — the system PATH is not inherited. Any server that relies on node, npx, python, or other tools found via PATH must have it explicitly set.
In the Environment Variables (Plaintext) field, add:
PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
Adjust the paths to match where your runtime is installed (which node will show the correct directory).
Example: GitHub MCP server
| Field | Value |
|---|---|
| Transport | stdio |
| Command | /opt/homebrew/bin/npx |
| Arguments | -y @modelcontextprotocol/server-github |
| Auth Type | none |
| Environment Variables (Plaintext) | PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin |
| Secure Environment Variables (Encrypted) | GITHUB_PERSONAL_ACCESS_TOKEN=ghp_yourtoken |
http (Streamable HTTP)
The app connects to a remote MCP server over HTTP(S) using the Streamable HTTP transport from rmcp.
Configuration:
urlfield on the server record — the HTTP endpoint (e.g.,https://mcp.example.com/v1).- If
auth_typeisbearerorapi_key, the decrypted auth value is attached as anAuthorizationheader.
{
"url": "https://mcp.example.com/v1",
"transport_type": "http",
"auth_type": "bearer"
}
The transport_config field for HTTP servers is typically {} — connection details come from url and auth_value.
Authentication Types
| Type | Description | Storage |
|---|---|---|
none |
No authentication required | — |
api_key |
API key sent as Authorization header | Encrypted in auth_value |
bearer |
Bearer token sent as Authorization header | Encrypted in auth_value |
oauth2 |
OAuth2 PKCE flow via WebView | Token encrypted in auth_value after exchange |
All auth values are encrypted with AES-256-GCM before storage (same encryption system as integration credentials). The plaintext is never returned to the frontend — list_mcp_servers strips auth_value from responses.
OAuth2 Flow
For servers requiring OAuth2:
transport_configmust includeauth_endpoint,token_endpoint,client_id, and optionallyscope.- Call
initiate_mcp_oauth(server_id)— opens a WebView window at the authorization URL. - User authenticates with the MCP provider.
- On redirect, the code is exchanged for an access token.
- Token is encrypted and stored in
auth_value.
Configuration Guide
Adding an MCP Server (UI)
Navigate to Settings > MCP Servers (/settings/mcp) to manage servers.
- Click Add Server.
- Fill in:
- Name — Human-readable label (e.g., "Weather API", "Filesystem Tools").
- URL — For HTTP: the server endpoint. For stdio: leave blank.
- Transport —
stdioorhttp. - Command (stdio only) — Absolute path to the executable (e.g.,
/opt/homebrew/bin/npx). - Arguments (stdio only) — Space-separated arguments (e.g.,
-y @modelcontextprotocol/server-github). - Auth Type —
none,api_key,bearer, oroauth2. - Auth Value — The token/key (will be encrypted on save). Leave blank for
none. - Environment Variables (Plaintext) (stdio only) — Space-separated
KEY=valuepairs for non-sensitive values. Always includePATH=...fornpx/node/python-based servers — the app bundle does not inherit the system PATH. - Secure Environment Variables (Encrypted) (stdio only) — Space-separated
KEY=valuepairs for sensitive values (API keys, tokens). Stored AES-256-GCM encrypted. Leave blank when editing to preserve existing values. - Custom Headers (HTTP only) — Not yet supported by the backend transport (currently ignored); do not use for secrets yet.
- Enabled — Toggle on/off.
- Click Save. The server record is persisted.
- Click Discover to connect and enumerate available tools and resources.
Discovery
Discovery connects to the server, queries its tool and resource manifests, and persists them locally. Status transitions:
pending → connected (success)
pending → error (connection/protocol failure)
pending → unreachable (startup failure, non-fatal)
After successful discovery, tools from the server appear in AI conversations automatically.
Tool Naming Convention
When tools are discovered, each gets a tool key used by the AI model:
mcp_{server_name}_{tool_name}
Both parts are sanitised:
- Lowercased
- Non-alphanumeric characters replaced with
_ - Consecutive underscores collapsed
- Leading/trailing underscores trimmed
Examples:
| Server Name | Tool Name | Tool Key |
|---|---|---|
| My Weather API | get_forecast | mcp_my_weather_api_get_forecast |
| Filesystem | search files | mcp_filesystem_search_files |
| simple | ping | mcp_simple_ping |
The AI model calls tools by their tool_key. The adapter layer resolves this back to the original server and tool name for execution.
Startup Discovery
On application launch, init_all_servers() iterates all enabled servers and attempts discovery for each:
- Successful connections are stored in
AppState.mcp_connections(aHashMap<String, Arc<TokioMutex<McpConnection>>>>). - Failed connections are marked as
unreachablein the database with the error message. A warning is logged, but startup continues. - This is a best-effort, non-blocking operation — the app launches regardless of MCP server availability.
AI Integration
Enabled MCP tools are automatically injected into AI conversations:
get_enabled_mcp_tools()queries tools from servers that are bothenabled = 1anddiscovery_status = 'connected'.- Each
McpToolis converted to an AITooldefinition (name, description, JSON Schema parameters). - When the AI responds with a tool call matching an
mcp_*key, the adapter routes it tocall_tool()on the appropriate live connection. - The tool result is fed back to the AI as a tool response message.
IPC Commands
| Command | Parameters | Returns |
|---|---|---|
list_mcp_servers |
— | McpServer[] (auth_value always null) |
create_mcp_server |
CreateMcpServerRequest |
McpServer |
update_mcp_server |
id, UpdateMcpServerRequest |
McpServer |
delete_mcp_server |
id |
void |
toggle_mcp_server |
id, enabled |
void |
discover_mcp_server |
id |
McpServerStatus |
get_mcp_server_status |
id |
McpServerStatus |
initiate_mcp_oauth |
id |
void (opens WebView) |
See IPC Commands for full type signatures.
Security
- Encrypted auth values — AES-256-GCM, same key derivation as integration credentials (
TRCAA_ENCRYPTION_KEY(or legacyTRCAA_ENCRYPTION_KEY)) - Server-side scrubbing —
auth_valueset toNonebefore any response to the frontend - Audit logging —
write_audit_eventcalled before every MCP tool execution - PII scan — Tool call arguments are scanned for PII patterns (non-blocking warning to user)
- Absolute path enforcement — stdio transport rejects relative paths to prevent traversal attacks
- Encrypted env vars — sensitive environment variables stored AES-256-GCM encrypted in
env_config; never returned to the frontend - Dangerous env var blocking —
LD_PRELOAD,LD_LIBRARY_PATH,DYLD_INSERT_LIBRARIES, and related privilege-escalation variables are rejected at the transport layer - Cascade deletes — Removing a server removes all associated tools and resources
- TLS — HTTP transport uses
reqwestwith certificate verification for HTTPS endpoints
See Security Model for the full threat analysis.