MCP & Plugin
Part 1 — The pxcore MCP Server
On this page
What it does
pxcore renders dense reference content — logs, large JSON, files you are
reading but not editing — as PNG images the model reads with native vision,
instead of as text tokens. Exact content you must reproduce verbatim (IDs, paths,
hashes, code you are about to edit) is always kept as text.
Measured reduction on the imaged subset is roughly 64% on code and logs.
The safety model
Compression is worthless if the model misreads what it was given, so pxcore is conservative by construction:
-
No LLM in the compression path. The decision is deterministic — nothing can hallucinate about what to compress.
-
Default-OFF per model until a calibration battery proves that model reads imaged content accurately.
-
Three content classes, each gated by its own measured fidelity:
Class Example Gate exactIDs, hashes, code to edit Never imaged gistCode, logs, varied output read to comprehend Images when the model's gist score clears the floor lookupKeyed record-sets where you find a value by key Images only at a much higher bar This split matters: live calibration showed a model's imaged-reading fidelity is not one number. Models read gist content reliably (arithmetic 100%, hex 87–100%) yet fail lookup (finding a value by key in a large keyed record-set — as low as 0/10). A single class would gate everything by the weakest mode and disable compression where it is genuinely safe.
-
Net-loss guard. If the rendered image would cost more tokens than the text it replaces, the text is kept. Prose is usually more expensive as an image.
Installation
pip install opexia-trace # ships pxcore, pxcore-mcp, and pxcore-proxy
Running the server
# stdio — the default; what Claude Code and local clients use
pxcore-mcp
# HTTP — for Next.js / serverless callers
pxcore-mcp --http
pxcore-mcp --http --host 127.0.0.1 --port 8765
CLI options
| Flag | Type | Default | Description |
|---|---|---|---|
--http | flag | off (stdio) | Serve JSON-RPC over HTTP POST instead of stdio |
--host | string | 127.0.0.1 | Bind host, with --http |
--port | integer | 8765 | Bind port, with --http |
Transports
| Transport | Protocol | Use for |
|---|---|---|
| stdio | Newline-delimited JSON-RPC on stdin/stdout | Claude Code and local MCP clients |
| HTTP | Single JSON-RPC-over-POST endpoint (the non-streaming Streamable HTTP subset) | Next.js, serverless, any language with an MCP client |
Pure standard library — no server framework, no extra dependency.
PXCORE_MODEL
MCP does not surface which model is calling, so the active model is supplied out-of-band:
export PXCORE_MODEL=claude-fable-5
pxcore-mcp
This selects the calibration profile that gates compression. An unknown or uncalibrated model leaves compression off — pxcore returns plain text rather than risk a misread.
MCP tools
Four tools, exactly as advertised over tools/list.
pxcore_read
Read a file and return it token-efficiently. Large dense files come back as an image (read via native vision) with exact identifiers listed as text; small or exact-heavy files come back as plain text. Use for reference reads you will not edit verbatim.
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | ✅ | File path to read |
{ "name": "pxcore_read", "arguments": { "path": "logs/app.log" } }
pxcore_run
Run a shell command and return its output token-efficiently — large dense output as an image, exact IDs as text.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
command | string | ✅ | — | Shell command to run |
timeout | number | ➖ | 120 | Timeout in seconds |
{ "name": "pxcore_run", "arguments": { "command": "kubectl get pods -A", "timeout": 30 } }
pxcore_grep
Search files under a path and return matches token-efficiently.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
pattern | string | ✅ | — | Search pattern |
path | string | ➖ | . | Directory to search |
{ "name": "pxcore_grep", "arguments": { "pattern": "TODO", "path": "src/" } }
pxcore_view
Render a large block you already have into a token-efficient image.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
text | string | ✅ | — | The block to render |
exact | boolean | ➖ | false | Force it to stay text — for content that must be reproduced verbatim |
{ "name": "pxcore_view", "arguments": { "text": "<large block>", "exact": false } }
Client configuration
Claude Code
.mcp.json in your project root:
{
"mcpServers": {
"pxcore": {
"command": "pxcore-mcp",
"env": { "PXCORE_MODEL": "claude-fable-5" }
}
}
}
The bundled plugin uses a vendored copy instead, so it needs no pip install:
{
"mcpServers": {
"pxcore": {
"command": "python",
"args": ["-m", "pxcore_mcp"],
"env": {
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/vendor",
"PXCORE_MODEL": "claude-fable-5"
}
}
}
}
TypeScript / Node
Use the HTTP transport with the official MCP SDK.
npm i @modelcontextprotocol/sdk
pxcore-mcp --http --port 8765 # in another terminal
// pxcore-client.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "my-app", version: "1.0.0" });
await client.connect(
new StreamableHTTPClientTransport(new URL("http://127.0.0.1:8765")),
);
// Discover what the server offers.
const { tools } = await client.listTools();
console.log(tools.map(t => t.name));
// → ["pxcore_read", "pxcore_run", "pxcore_grep", "pxcore_view"]
// Read a large log token-efficiently.
const result = await client.callTool({
name: "pxcore_read",
arguments: { path: "logs/app.log" },
});
console.log(result.content); // image blocks + exact identifiers as text
Raw JSON-RPC, with no SDK:
async function callPxcore(name: string, args: Record<string, unknown>) {
const res = await fetch("http://127.0.0.1:8765", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0", id: 1,
method: "tools/call",
params: { name, arguments: args },
}),
});
return (await res.json()).result;
}
console.log(await callPxcore("pxcore_grep", { pattern: "TODO", path: "src/" }));
Python
Call the same functions in-process — no server, no MCP round trip.
import pxcore.agent_tools as tools
# Each returns MCP-shaped content blocks.
print(tools.read("logs/app.log"))
print(tools.run("kubectl get pods -A", timeout=30))
print(tools.grep("TODO", "src/"))
print(tools.view(large_block, exact=False))
# as_text=True forces plain text, bypassing imaging entirely.
print(tools.read("config.yaml", as_text=True))
Using pxcore as a library
import pxcore
# Decide whether one block should be imaged, given a model profile.
decision = pxcore.decide(block_text, profile)
# Split an oversized block into page-images (capped at DEFAULT_MAX_PAGES = 16).
pages = pxcore.decide_paged(huge_block, profile)
# Classify content without acting on it.
label = pxcore.classify(block_text)
Public API: decide, decide_paged, classify, render, Meter,
DriftMonitor, BlockHint, BlockLabel, Decision, Geometry,
ImageWithFactsheet, KeepText, ModelProfile, Rendered, plus the in-code
integration helpers to_anthropic, to_openai, compress_anthropic.
DEFAULT_MAX_PAGES = 16 is a blast-radius guard, not an economic one: it stops a
pathological megablock exploding into hundreds of images. Each page under the cap
still images only if that page alone wins.
In-code integration
Compress the messages you send to a provider directly:
from pxcore import compress_anthropic
compressed = compress_anthropic(messages, profile)
response = anthropic_client.messages.create(model="claude-opus-4-6",
messages=compressed, max_tokens=1024)
pxcore-proxy
An in-path token-compression proxy for Claude Code — the same compression applied transparently, with no tool calls to change.
pxcore-proxy --help
Its only dependency is httpx, already required by opexia-trace.
| MCP server | Proxy | |
|---|---|---|
| How it applies | You call pxcore_* tools explicitly | Transparent, in the request path |
| Changes needed | Use the tools instead of the built-ins | None |
| Control | Per call | Global |
| Best for | Selective compression, other languages | Blanket savings in Claude Code |