MCP Response Redaction
Overview
When you connect sqry to a cloud-hosted AI assistant, MCP tool responses may contain absolute file paths, source code snippets, documentation strings, and workspace layout details. The sqry-mcp-redaction library lets you filter these before they reach the model.
The library ships as a standalone crate and can be used client-side or integrated into the MCP server pipeline. It uses a whitelist-first security model: every field in a JSON response is redacted unless it appears on an explicit allow list. This inverts the usual “block known-bad” approach — unknown fields are redacted by default, so new tool outputs are safe without configuration changes.
Status: The redaction library is fully implemented and tested but not yet wired into the MCP server by default. Configure it via environment variables when launching
sqry-mcp.
Presets
Four presets cover common deployment scenarios. Set the preset with SQRY_REDACTION_PRESET:
| Preset | Paths | Code | Docs | Filenames | Use case |
|---|---|---|---|---|---|
none | — | — | — | — | Trusted local tools (Claude Code, local Codex) |
minimal | redacted | kept | kept | kept | Cloud LLMs that need code context |
standard | redacted | redacted | kept | kept | Cloud LLMs, code is confidential (default) |
strict | redacted | redacted | redacted | hashed | Untrusted external services |
nonedisables all filtering (passthrough mode).minimalstrips absolute paths and URIs but preserves source code and documentation, giving cloud models enough context to reason about your code.standardadditionally strips source code blocks, replacing them with a line-count placeholder ([REDACTED: 3 lines of code]). The model still sees symbol names, kinds, positions, and relationships.strictalso strips documentation and replaces filenames with salted SHA-256 hashes, leaving only structural graph data.
What gets redacted
Path data (P0)
Absolute paths, file URIs, workspace root paths, Windows paths, and UNC network paths are all detected and redacted. The engine also scans arbitrary string fields for embedded paths using pattern matching:
/home/user/project/src/main.rs → src/main.rs
file:///home/user/project/src/lib.rs → src/lib.rs
C:\Users\dev\project\src\app.ts → src/app.ts
\\server\share\project\README.md → README.md
When SQRY_REDACT_WORKSPACE is set, the workspace root itself (e.g., /srv/repos/internal/acme/backend) is stripped from all responses.
Security hardening: The path canonicalizer rejects null bytes, control characters, paths longer than 4,096 characters, Windows device paths (\\.\COM1), and UNC escape attempts.
Source code (P1)
Code context blocks — function bodies, snippets, and source excerpts — are replaced with a line-count placeholder:
fn main() { → [REDACTED: 3 lines of code]
println!("Hello");
}
The detector recognizes common language patterns (fn, func, def, class, import, var, let, etc.) to distinguish code from plain text.
Documentation
Doc comments, docstrings, and inline documentation are replaced with [REDACTED: documentation]. The detector matches ///, //!, /**, @param, @returns, Python docstrings, and similar patterns.
Unknown fields
In whitelist mode (the default for all presets except none), any JSON field not on the whitelist is redacted. This means new tool outputs or unexpected fields are safe by default.
Whitelists
Each preset defines which response fields pass through unmodified:
Always preserved (all presets):
- Semantic info:
name,kind,language,qualified_name - Position info:
line,column,range,start,end - Graph structure:
edges,nodes,relation_type,score
Minimal adds: code, code_context, snippet, source_code, documentation, doc, docstring, comment, results, items, data, symbols, from, to
Standard adds documentation fields but not code context fields.
Strict allows only minimal semantic, position, and structural fields.
You can extend any preset with SQRY_WHITELIST_FIELDS:
export SQRY_WHITELIST_FIELDS="my_custom_field,another_field"
Configuration
All settings are controlled via environment variables. Set them when launching sqry-mcp:
# Use the standard preset (default)
SQRY_REDACTION_PRESET=standard sqry-mcp
# Override individual toggles
SQRY_REDACTION_PRESET=minimal \
SQRY_REDACT_CODE=1 \
sqry-mcp
Environment variables
| Variable | Values | Default | Description |
|---|---|---|---|
SQRY_REDACTION_PRESET | none, minimal, standard, strict | standard | Base preset |
SQRY_REDACT_PATHS | 0 / 1 | preset | Strip absolute paths |
SQRY_REDACT_WORKSPACE | 0 / 1 | preset | Strip workspace root from all strings |
SQRY_REDACT_URIS | 0 / 1 | preset | Strip file:// URIs |
SQRY_REDACT_CODE | 0 / 1 | preset | Replace code blocks with line-count placeholder |
SQRY_REDACT_DOCS | 0 / 1 | preset | Replace documentation strings |
SQRY_REDACT_PATTERNS | 0 / 1 | preset | Detect and redact paths embedded in strings |
SQRY_HASH_FILENAMES | 0 / 1 | 0 | Replace filenames with SHA-256 hashes |
SQRY_HASH_SALT | string | random | Salt for filename hashing (set for deterministic output) |
SQRY_WORKSPACE_ROOT | path | auto | Workspace root for relative-path conversion |
SQRY_WHITELIST_FIELDS | CSV | preset | Additional fields to preserve |
SQRY_PRESERVE_PATHS | CSV | — | JSONPath expressions for fields to never redact |
Individual toggles override the preset. For example, SQRY_REDACTION_PRESET=minimal SQRY_REDACT_CODE=1 uses the minimal preset but also redacts code.
JSONPath rules
For surgical control, use JSONPath expressions via SQRY_PRESERVE_PATHS to exempt specific fields from redaction, regardless of other rules:
# Always preserve metadata, even in strict mode
export SQRY_PRESERVE_PATHS="$.result.metadata,$..summary"
Supported syntax:
| Pattern | Meaning |
|---|---|
$.field | Root-level field |
$.a.b.c | Nested path |
$..field | Recursive descent (any depth) |
$[0] | Array index |
$[*] | All array elements |
$[0,1,2] | Multiple indices |
Example: Claude Desktop with redaction
{
"mcpServers": {
"sqry": {
"command": "/usr/local/bin/sqry-mcp",
"env": {
"SQRY_MCP_WORKSPACE_ROOT": "/home/dev/project",
"SQRY_REDACTION_PRESET": "standard",
"SQRY_REDACT_WORKSPACE": "1"
}
}
}
}
This configuration gives Claude access to all 33 MCP tools while stripping absolute paths, workspace root, and source code from every response. Symbol names, kinds, positions, relationships, and documentation pass through — enough for the model to reason about code structure without seeing the code itself.
Redaction statistics
Every redacted response includes a statistics summary (logged at debug level):
{
"paths_redacted": 12,
"uris_redacted": 3,
"code_contexts_redacted": 5,
"docs_redacted": 2,
"pattern_paths_redacted": 1,
"unknown_fields_redacted": 0,
"workspace_path_redacted": true
}
Use this to audit what’s being filtered and tune your preset.
Programmatic API
For custom integrations, use the Rust API directly:
use sqry_mcp_redaction::{Redactor, RedactionConfig};
// From environment variables
let redactor = Redactor::from_env()?;
// Or from a preset
let redactor = Redactor::new(RedactionConfig::standard())?;
// Redact in-place
let stats = redactor.redact(&mut json_value);
// Redact a clone (original preserved)
let (redacted, stats) = redactor.redact_clone(&json_value);
// Dry-run preview
let preview = redactor.preview(&json_value);
// Stream processing for large responses
let stats = redactor.redact_stream(reader, writer)?;