MCP Gateway
Use any MCP server. We secure the boundary.
The Model Context Protocol (MCP) is the emerging standard for agent-to-tool communication. Triggerfish provides a secure MCP Gateway that lets you connect to any MCP-compatible server while enforcing classification controls, tool-level permissions, taint tracking, and full audit logging.
You bring the MCP servers. Triggerfish secures every request and response that crosses the boundary.
How It Works
The MCP Gateway sits between your agent and any MCP server. Every tool call passes through the policy enforcement layer before reaching the external server, and every response is classified before it enters the agent context.
Agent --> MCP Gateway --> Policy Layer --> MCP Server (any)
|
Classification
Taint tracking
Schema validation
Audit loggingThe gateway provides five core functions:
- Server authentication and classification -- MCP servers must be reviewed and classified before use
- Tool-level permission enforcement -- Individual tools can be permitted, restricted, or blocked
- Request/response taint tracking -- Session taint escalates based on server classification
- Schema validation -- All requests and responses validated against declared schemas
- Audit logging -- Every tool call, decision, and taint change is recorded
MCP Server States
All MCP servers default to UNTRUSTED. They must be explicitly classified before the agent can invoke them.
| State | Description | Agent Can Invoke? |
|---|---|---|
UNTRUSTED | Default for new servers. Pending review. | No |
CLASSIFIED | Reviewed and assigned a classification level with per-tool permissions. | Yes (within policy) |
BLOCKED | Explicitly prohibited by admin. | No |
UNTRUSTED --> CLASSIFIED (admin/user reviews and assigns level)
UNTRUSTED --> BLOCKED (admin determines server is not permitted)
CLASSIFIED --> BLOCKED (admin revokes access)SECURITY
An UNTRUSTED MCP server cannot be invoked by the agent under any circumstances. The LLM cannot request, convince, or trick the system into using an unclassified server. Classification is a code-level gate, not an LLM decision.
Configuration
MCP servers are configured in triggerfish.yaml with classification levels and per-tool permissions:
mcp_servers:
- uri: "mcp://salesforce.mcp.example.com"
name: "Salesforce MCP"
classification: CONFIDENTIAL
status: CLASSIFIED
tools:
- name: "query_opportunities"
permitted: true
requires_user_auth: true
- name: "delete_record"
permitted: false # Blocked by policy
- name: "export_all"
permitted: false
- uri: "mcp://weather-api.mcp.example.com"
name: "Weather API"
classification: PUBLIC
status: CLASSIFIED
tools:
- name: "*" # All tools permitted
permitted: true
- uri: "mcp://unknown-server.example.com"
status: UNTRUSTED # Pending reviewEach server entry specifies:
- uri -- The MCP server endpoint
- classification -- The data sensitivity level assigned to this server
- status -- The current server state (
CLASSIFIED,UNTRUSTED, orBLOCKED) - tools -- Per-tool permission configuration (use
"*"for all tools) - requires_user_auth -- Whether the tool requires user credential passthrough
Tool Call Flow
When the agent requests an MCP tool call, the gateway executes a deterministic sequence of checks before forwarding the request.
1. Pre-Flight Checks
All checks are deterministic -- no LLM calls, no randomness.
| Check | Failure Result |
|---|---|
Server status is CLASSIFIED? | Block: "Server not approved" |
| Tool is permitted for this server? | Block: "Tool not permitted" |
| User has required permissions? | Block: "Permission denied" |
| Session taint compatible with server classification? | Block: "Would violate write-down" |
| Schema validation passes? | Block: "Invalid parameters" |
INFO
If the session taint is higher than the server classification, the call is blocked to prevent write-down. A session tainted at CONFIDENTIAL cannot send data to a PUBLIC MCP server.
2. Execute
If all pre-flight checks pass, the gateway forwards the request to the MCP server.
3. Response Processing
When the MCP server returns a response:
- Validate the response against the declared schema
- Classify the response data at the server's classification level
- Update session taint:
taint = max(current_taint, server_classification) - Create a lineage record tracking the data origin
4. Audit
Every tool call is logged with: server identity, tool name, user identity, policy decision, taint change, and timestamp.
Response Taint Rules
MCP server responses inherit the server's classification level. Session taint can only escalate.
| Server Classification | Response Taint | Session Impact |
|---|---|---|
PUBLIC | PUBLIC | No taint change |
INTERNAL | INTERNAL | Taint escalates to at least INTERNAL |
CONFIDENTIAL | CONFIDENTIAL | Taint escalates to at least CONFIDENTIAL |
RESTRICTED | RESTRICTED | Taint escalates to RESTRICTED |
Once a session is tainted at a given level, it stays at that level or higher for the remainder of the session. A full session reset (which clears conversation history) is required to reduce taint.
User Authentication Passthrough
For MCP servers that support user-level authentication, the gateway passes through the user's delegated credentials rather than system credentials.
When a tool is configured with requires_user_auth: true:
- The gateway checks whether the user has connected this MCP server
- Retrieves the user's delegated credential from the secure credential store
- Adds user authentication to the MCP request headers
- The MCP server enforces user-level permissions
The result: the MCP server sees the user's identity, not a system identity. Permission inheritance works through the MCP boundary -- the agent can only access what the user can access.
TIP
User auth passthrough is the preferred pattern for any MCP server that manages access control. It means the agent inherits the user's permissions rather than having blanket system access.
Schema Validation
The gateway validates all MCP requests and responses against declared schemas before forwarding:
// Request validation (simplified)
function validateMcpRequest(
serverConfig: McpServerConfig,
toolName: string,
params: Record<string, unknown>,
): Result<void, McpError> {
const toolSchema = serverConfig.getToolSchema(toolName);
if (!toolSchema) {
return err(new McpError("Unknown tool"));
}
// Validate params against JSON schema
if (!validateJsonSchema(params, toolSchema.inputSchema)) {
return err(new McpError("Invalid parameters"));
}
// Check for injection patterns in string params
for (const [, value] of Object.entries(params)) {
if (typeof value === "string" && containsInjectionPattern(value)) {
return err(new McpError("Potential injection detected"));
}
}
return ok(undefined);
}Schema validation catches malformed requests before they reach the external server and flags potential injection patterns in string parameters.
Enterprise Controls
Enterprise deployments have additional controls for MCP server management:
- Admin-managed server registry -- Only admin-approved MCP servers can be classified
- Per-department tool permissions -- Different teams can have different tool access
- Compliance logging -- All MCP interactions available in compliance dashboards
- Rate limiting -- Per-server and per-tool rate limits
- Server health monitoring -- Gateway tracks server availability and response times