Refract
by LoudiliMed
README.md
<p align="center">
<img src="assets/logo.png" alt="Refract" width="360">
</p>
# Refract
[](https://github.com/LoudiliMed/Refract/actions/workflows/ci.yml)
[](https://glama.ai/mcp/servers/LoudiliMed/Refract)
> Cuts up to 98% of the tokens your AI agents spend using MCP tools — without losing anything.
---
## What it actually changes
| Server | Tools | Before | After | Reduction |
|---|---|---|---|---|
| filesystem (Anthropic) | 14 | 1,892 tok | 236 tok | **−88%** |
| sequential-thinking | 1 | 926 tok | 20 tok | **−98%** |
| Google Calendar | 5 | 5,010 tok | 660 tok | **−87%** |
| Enterprise (Cal + Gmail + Drive) | 12 | 8,649 tok | 882 tok | **−90%** |
| sample_app.js (JavaScript) | — | 799 tok | 284 tok | **−64.5%** |
| sample_app.ts (TypeScript) | — | 378 tok | 266 tok | **−29.6%** |
| ast_extractor.py (Python) | — | 3,633 tok | 890 tok | **−75.5%** |
Fewer tokens sent = lower API bills, faster responses. And nothing is lost. Every check confirmed tools stay 100% usable after compression.
Reproduce these numbers yourself — every input is a static fixture in the repo, tokens counted with tiktoken cl100k_base:
```bash
python benchmarks/run_benchmark.py # the table above
python benchmarks/run_benchmark.py --json # machine-readable
python benchmarks/run_benchmark.py --fixture path/to/your_schemas.json
```
---
## Install
One-liner (macOS / Linux) — installs the package and configures Claude Desktop:
```bash
curl -sSL https://raw.githubusercontent.com/LoudiliMed/Refract/main/install-refract.sh | sh
```
> Piping a script from the internet into your shell deserves a quick look first: [inspect install-refract.sh on GitHub](https://github.com/LoudiliMed/Refract/blob/main/install-refract.sh). It never uses sudo.
Or with pip directly:
```bash
pip install refract-mcp
```
fastembed and tree-sitter are installed by default.
---
## Two modes
### Mode 1 — MCP Proxy
Sits between your agent and any MCP server. Compresses tool schemas on the fly so your agent does not load the full catalogue on every request.
**Local subprocess (stdio):**
```bash
refract-proxy --target "npx @modelcontextprotocol/server-filesystem /tmp" --verbose
```
**Remote HTTP/SSE server:**
```bash
# --url implies SSE transport (explicit, recommended for remote endpoints)
refract-proxy --url https://my-mcp-server.com/sse
# or with --transport flag (auto-detection can be overridden)
refract-proxy --target https://my-mcp-server.com/sse --transport sse
```
**Proxy flags:**
| Flag | Default | Description |
|---|---|---|
| `--target URL` | required | MCP target: stdio command, HTTP URL, or JSON file |
| `--stdio-cmd CMD` | — | Alias for `--target` for stdio commands |
| `--url URL` | — | Remote SSE/HTTP endpoint — implies `--transport sse` |
| `--transport {stdio,sse,http}` | auto | Force transport to the target: `stdio`, `sse` (legacy), or `http` (Streamable HTTP) |
| `--sse-timeout SECONDS` | 30 | Connection timeout for SSE targets (retries 3×) |
| `--mode {stdio,http}` | stdio | How the proxy serves your agent |
| `--port PORT` | 8080 | Proxy listen port in `--mode http` |
| `--verbose` | off | Print token counts per request |
| `--log-level` | WARNING | DEBUG / INFO / WARNING / ERROR |
Add it to Claude Desktop:
```json
{
"mcpServers": {
"my-server-via-refract": {
"command": "/path/to/refract-proxy",
"args": [
"--target",
"npx @modelcontextprotocol/server-filesystem /path/to/folder",
"--verbose"
]
}
}
}
```
For a remote MCP server (SSE):
```json
{
"mcpServers": {
"remote-via-refract": {
"command": "/path/to/refract-proxy",
"args": ["--url", "https://my-mcp-server.com/sse"]
}
}
}
```
#### refract-wrap-all — wrap every server at once
Instead of editing entries one by one (or running `refract-install` per server), `refract-wrap-all` rewrites **all** stdio servers in `claude_desktop_config.json` to go through `refract-proxy` in a single command:
```bash
# Preview what would change — writes nothing
refract-wrap-all --dry-run
# Wrap every stdio server not already going through refract
refract-wrap-all
# Restore the original commands
refract-wrap-all --unwrap
```
Example: this entry
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["@modelcontextprotocol/server-filesystem", "/tmp"],
"env": {"MY_VAR": "1"}
}
}
}
```
becomes
```json
{
"mcpServers": {
"filesystem": {
"command": "/path/to/refract-proxy",
"args": ["--stdio-cmd", "npx @modelcontextprotocol/server-filesystem /tmp"],
"env": {"MY_VAR": "1"}
}
}
}
```
Guarantees:
- A backup of the config is taken **before every write** (`claude_desktop_config.json.bak`, then `.bak2`, `.bak3`… — an existing backup is never overwritten).
- `env`, `cwd` and any other server fields are preserved.
- Servers already going through `refract-proxy` or `refract-server` are skipped (`already wrapped`).
- Remote SSE/HTTP servers (`url` entries) are skipped — only stdio servers are wrapped.
- `--unwrap` is an exact round-trip: wrap then unwrap restores every original command, args and fields.
#### Transports supported by refract-proxy
| Flag | Value | Description |
|---|---|---|
| `--transport http` | Streamable HTTP | **Current standard** (MCP spec 2025-03-26). Use with remote MCP servers. |
| `--transport sse` | SSE | Legacy transport, kept for compatibility. Use if the server does not support Streamable HTTP. |
| `--transport stdio` | stdio subprocess | Local command (default when `--target` is a command). |
| *(omit)* | auto-detect | Inferred from `--target`: HTTP URL → SSE, command → stdio. |
Both `sse` and `http` require an HTTP(S) URL in `--target`.
```bash
# Connect to a remote MCP server via Streamable HTTP (recommended)
refract-proxy --target "https://my-mcp-server.com/mcp" --transport http
# Connect via SSE (legacy)
refract-proxy --target "https://my-mcp-server.com/sse" --transport sse
# Local subprocess (auto-detected, --transport stdio optional)
refract-proxy --target "npx @modelcontextprotocol/server-filesystem /tmp"
```
### Mode 2 — MCP Server
Exposes your codebase as an MCP server. Your agent can index a repo, get compressed file context, expand specific functions, analyze impact, detect breaking changes, and map security risks.
```bash
refract-server --root /path/to/your/repo
```
Add it to Claude Desktop:
```json
{
"mcpServers": {
"refract-code": {
"command": "/path/to/refract-server",
"args": ["--root", "/path/to/your/repo"]
}
}
}
```
---
## How it works, no jargon
Imagine a library with 50 books.
Without Refract: your agent gets a detailed summary of all 50 books on every question, even if the answer only needs one of them.
With Refract: your agent first gets a list of titles (the index). Once it knows which book it needs, it only receives that book's content.
Technically:
The index (always sent): just tool names and a short description of each.
The detail (sent only when needed): the full description of the tool actually used, everything required to use it correctly, nothing more.
The verification: after every compression, Refract automatically checks that nothing important was removed. If there is any doubt, it sends the full version instead of taking a risk.
No AI model is involved in this process. It is fully automatic, fast, and deterministic.
---
## MCP Proxy tools
| Tool | What it does |
|---|---|
| Compression | Compresses tool schemas on the fly, up to 98% reduction |
| Signal check | Verifies callable contract after every compression |
| Semantic routing | Identifies the right tool using embeddings (opt-in) |
| Prompt caching | Injects Anthropic cache_control for repeated requests |
## MCP Server tools
| Tool | Input | Output |
|---|---|---|
| index_repo | repo path | aggregated index of all Python, JS, TS files |
| get_compressed | file path | compressed structure + token stats |
| expand | file path + function names | verbatim source + dependency context |
| blast_radius | file path + function name | all functions that break if target changes |
| semantic_diff | file path + old source + new source | breaking changes vs body-only changes |
| semantic_diff_branches | repo path + file + function + base/head git refs | semantic_diff of one function between two branches/commits |
| security_surface | repo path | map of dangerous calls (subprocess, eval, pickle, requests) |
---
## Repository health check
```bash
refract-status --root /path/to/repo
refract-status --root /path/to/repo --json
```
| Flag | Description |
|---|---|
| `--root PATH` | Path to analyse (default: current directory) |
| `--json` | Machine-readable output |
Shows: files per language, raw vs compressed tokens, functions/classes indexed, dangerous calls by category, languages without tree-sitter support.
---
## blast_radius
Ask Claude which functions break if you change a target function.
Example result:
```json
{
"target": "authenticate",
"direct_callers": ["login_user"],
"all_impacted": ["login_user", "verify_session", "admin_access"],
"impacted_count": 3,
"risk_level": "MEDIUM"
}
```
Risk levels: LOW (0 to 2 impacted), MEDIUM (3 to 5), HIGH (6 or more).
---
## semantic_diff
Detects breaking API changes by comparing function interfaces, not bodies. Use it as a CI gate.
Example result:
```json
{
"breaking": ["authenticate"],
"body_only": ["logout"],
"added": ["new_function"],
"removed": [],
"unchanged": ["hash_password"],
"is_breaking": true
}
```
If is_breaking is true, the PR changes the public API and must be reviewed.
---
## security_surface
Maps every function that calls dangerous primitives across your repo.
HIGH risk: subprocess, os.system, eval, exec, pickle, ctypes
MEDIUM risk: open (write mode), socket, requests, httpx, urllib
Example result:
```json
{
"high_risk": [
{
"file": "src/refract_server.py",
"function": "_git_show",
"calls": ["subprocess.run"],
"line_hint": "line 801"
}
],
"medium_risk": [
{
"file": "src/compression_cache.py",
"function": "store_cached",
"calls": ["open"],
"line_hint": "line 90"
},
{
"file": "src/refract_proxy.py",
"function": "_check_url_reachable",
"calls": ["urllib.request.urlopen"],
"line_hint": "line 430"
}
],
"summary": {
"high_risk_count": 1,
"medium_risk_count": 2,
"total_functions_scanned": 789,
"total_files_scanned": 41,
"clean_files": 37
}
}
```
---
## Languages supported
Python (via ast module), JavaScript, TypeScript, JSX, TSX (via tree-sitter). fastembed and tree-sitter are installed by default.
Language is auto-detected from file extension.
---
## Built-in Anthropic caching
Refract integrates with Anthropic prompt caching. `as_anthropic_tools()` returns compressed tools in Anthropic API format with `cache_control` pre-injected on the last tool, so the Anthropic API caches the full tool list from the second call onward (price: $0.30/M vs $3.00/M for cache hits).
```python
from refract_proxy import RefractProxy
proxy = RefractProxy(target_url="https://my-mcp-server.com/mcp", use_cache=True)
await proxy.connect()
# Pass directly to the Anthropic client:
response = anthropic_client.messages.create(
model="claude-sonnet-4-6",
tools=proxy.as_anthropic_tools(), # cache_control injected automatically
messages=[{"role": "user", "content": "..."}],
)
```
---
## Troubleshooting
**"Failed to spawn process: No such file or directory" in Claude Desktop**
Claude Desktop cannot find refract-proxy in its PATH. Find the absolute path and use it directly:
```bash
which refract-proxy
```
Then use the full path in claude_desktop_config.json:
```json
{
"mcpServers": {
"my-tool-via-refract": {
"command": "/full/path/to/refract-proxy",
"args": [
"--target",
"npx @modelcontextprotocol/server-filesystem /path/to/folder"
]
}
}
}
```
---
## Works with
Claude Desktop, Cursor, any client that follows the MCP standard, any existing MCP server.
---
## License
MIT — free to use, including commercially.
TDQS
A3.8/5.0
Scored across 5 tools
Disambiguation5/5
Each tool has a distinct purpose: impact analysis, source retrieval, file compression, repo indexing, and security scanning. No two tools overlap in functionality.
Naming Consistency4/5
All tools use snake_case, but 'expand' is a lone verb while others follow a verb_noun pattern (e.g., get_compressed, index_repo). Minor inconsistency but still clear.
Tool Count5/5
5 tools is a well-scoped set for a static analysis toolkit. Neither too few nor too many, each tool serves a clear need.
Completeness4/5
Covers core static analysis needs (impact, source, compression, indexing, security). Missing a dedicated diff or test analysis tool, but the surface is reasonably complete for the domain.
Maintenance
ActivityMaintained
ResponsivenessNo issues