DEVELOPER DOCS

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:

  1. No LLM in the compression path. The decision is deterministic — nothing can hallucinate about what to compress.

  2. Default-OFF per model until a calibration battery proves that model reads imaged content accurately.

  3. Three content classes, each gated by its own measured fidelity:

    ClassExampleGate
    exactIDs, hashes, code to editNever imaged
    gistCode, logs, varied output read to comprehendImages when the model's gist score clears the floor
    lookupKeyed record-sets where you find a value by keyImages 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.

  4. 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

Shell
pip install opexia-trace     # ships pxcore, pxcore-mcp, and pxcore-proxy

Running the server

Shell
# 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

FlagTypeDefaultDescription
--httpflagoff (stdio)Serve JSON-RPC over HTTP POST instead of stdio
--hoststring127.0.0.1Bind host, with --http
--portinteger8765Bind port, with --http

Transports

TransportProtocolUse for
stdioNewline-delimited JSON-RPC on stdin/stdoutClaude Code and local MCP clients
HTTPSingle 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:

Shell
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.

ParameterTypeRequiredDescription
pathstring✅File path to read
JSON
{ "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.

ParameterTypeRequiredDefaultDescription
commandstring✅—Shell command to run
timeoutnumber➖120Timeout in seconds
JSON
{ "name": "pxcore_run", "arguments": { "command": "kubectl get pods -A", "timeout": 30 } }

pxcore_grep

Search files under a path and return matches token-efficiently.

ParameterTypeRequiredDefaultDescription
patternstring✅—Search pattern
pathstring➖.Directory to search
JSON
{ "name": "pxcore_grep", "arguments": { "pattern": "TODO", "path": "src/" } }

pxcore_view

Render a large block you already have into a token-efficient image.

ParameterTypeRequiredDefaultDescription
textstring✅—The block to render
exactboolean➖falseForce it to stay text — for content that must be reproduced verbatim
JSON
{ "name": "pxcore_view", "arguments": { "text": "<large block>", "exact": false } }

Client configuration

Claude Code

.mcp.json in your project root:

JSON
{
  "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:

JSON
{
  "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.

Shell
npm i @modelcontextprotocol/sdk
pxcore-mcp --http --port 8765     # in another terminal
TypeScript
// 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:

TypeScript
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.

Python
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

Python
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:

Python
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.

Shell
pxcore-proxy --help

Its only dependency is httpx, already required by opexia-trace.

MCP serverProxy
How it appliesYou call pxcore_* tools explicitlyTransparent, in the request path
Changes neededUse the tools instead of the built-insNone
ControlPer callGlobal
Best forSelective compression, other languagesBlanket savings in Claude Code