LLMxRay-MCP
Connects to a local Ollama daemon to observe and diagnose its behavior: token-by-token chat streaming with confidence coloring, prompt X-ray showing how each turn's prompt is composed and cached, GPU/VRAM usage mapping of loaded models, cache diagnostics and measured prompt-cache fixes, model comparison and benchmarking against curated suites, and per-turn metrics such as prefill/generation speed, time to first token and context truncation.
Speaks Ollama's OpenAI-compatible /v1/chat/completions protocol, letting the same prompt be run in parallel against the native and OpenAI-compatible endpoints with side-by-side streaming, per-protocol metrics and an envelope diff of finish reasons, token counts and errors.
Quick Start
You need Ollama running with at least one model pulled (ollama pull llama3.2). Then:
npx llmxrayOr with Docker:
docker run -p 5174:5174 djovaneli/llmxrayOpen http://localhost:5174. Pick a model, send a message, and watch what happens. That's it.
Related MCP server: agent-vitals
What LLMxRay shows you
You run a local model. You chat with it. LLMxRay answers the questions that come next: how fast was each token, what did the prompt cost, did the cache help, which setting was actually better, and what are your other tools sending to the same model.
Every page below is one of those answers.
Prompt X-ray: the prompt itself, drawn to scale
Each turn your tool sent, as a bar. Colour is what each part of the prompt was: system prompt, tool schemas, earlier turns, the new message. Brightness is what happened to it: dim was already in the model's memory and cost nothing, bright had to be read again, striped was cut by the daemon and never seen. Stack the turns of a conversation and you watch the cache grow, see the turn where a timestamp in the system prompt emptied it, and the turn where the prompt outgrew the context and Ollama silently dropped the start, system prompt included, and answered anyway. Click a part and the request opens at that place in the text.
Shared box: why Ollama is slow right now, and which tool did it
One line per tool, sorted by what it cost the others, in seconds: the one that sends keep_alive: 0 and unloads the model after every run, the one that asks for a 128K context on 4K prompts and drops the daemon to one request at a time, the one that waited 22 seconds behind them. Each with the setting to change. A tool that cost nothing is listed too, so you can see what good looks like.
GPU map: what is in video memory, and what else would fit
One bar the width of your card: each loaded model as a block split into its weights and what its context costs on top, then the free space. Under it, every pulled model with one of three verdicts: fits now, fits only if what is loaded unloads first, larger than the card.
Tool calls: can this model drive an agent?
Thirteen request shapes agents send all day, scored on what the daemon returned: the right tool, the right arguments, the right number of calls, no call when none is needed. Each cell is one sentence: "the path argument is missing", "wrote the call into the answer text", "called search_web when no tool was needed". Click it for what the model returned.
Chat, token by token
Every token is drawn as it arrives, coloured by confidence. You see where the model hesitated and where it was sure. Markdown, multi-turn, file and image attachments, slash commands, and a thinking budget for reasoning models (off, model's choice, or low / medium / high / max).

Each response is also checked as it lands. A badge appears only when something is wrong: repetition, a refusal, gibberish, an empty answer, or a reply cut off at the token limit.
Session deep dive
Open any turn to see it as a timeline: time to first token, inter-token gaps, the reasoning block if there was one, tool calls, and the exact prompt that was sent.

Live: what your other tools send
LLMxRay opens a second port, 11435, that behaves exactly like Ollama and forwards everything to it. Point VS Code Copilot, Open WebUI, Continue, n8n or your own script at http://localhost:11435 and every turn they send appears here: client, model, prompt size, how much came from the cache, prefill and generation speed, tool calls.
VS Code Copilot ─┐
Open WebUI ──────┤ ┌─ Live page: every turn,
Continue / n8n ──┼─► http://localhost:11435 ─► Ollama ┤ cache hits, prefill speed,
your scripts ────┘ (LLMxRay) └─ where the cache broke
Select a turn to see what the prompt is made of and the exact point where it stopped matching the previous one, which is where the cache broke. Findings are plain sentences, each linked to the turn that proves it: a client re-reading its whole prompt every turn, a prompt the daemon silently cut to fit the context (Ollama keeps the first few tokens and the end, drops the rest, and says nothing), a model running partly on CPU, tool schemas taking 40% of every prompt. Only counts and timings are kept, in memory. Prompt text is an opt-in that writes to a local file. Nothing leaves your machine.
Both ports answer only this machine by default, because the Live log holds whatever your tools sent. Start with npx llmxray --host 0.0.0.0 to let other machines on your network reach them, for a Live page on a second screen or a shared GPU box.
Cache Lab
A local model reuses its prompt cache only while the prompt matches from the very first token. One timestamp near the top forfeits everything below it. Cache Lab finds the values that change between turns, shows where reuse dies, and then measures against your own daemon what moving them to the end saves.

Measured on a real 324-token prompt: 4 tokens reused and 64.6 ms of prefill with the timestamp at the front, 290 reused and 18.6 ms with it at the back. 3.5x faster, same words.
Compare
The same prompt against up to four slots, each with its own model, temperature and system prompt, streaming side by side. One-click presets: Temperature Sweep, Deterministic Pair, Language Compare. A word-level diff shows exactly what changed between two answers.

Surgical Benchmark
Score models on curated question suites (MMLU-Pro, ARC-Challenge, HellaSwag, GSM8K, TruthfulQA) using the model's real token logprobs, not whether the answer happened to look right. Confidence versus accuracy per category, so you see where a model is confidently wrong. Import your own suites as JSON.

Decision Lab
Decision models (nimble, tev1, clef) answer typed questions with probabilities instead of prose. Give the lab a situation and ask for a choice among candidates, a yes/no probability, or a score on a scale. Every answer comes back as the model's own distribution, drawn as bars.

Protocol Observatory
The same prompt through Ollama's three serving protocols in parallel: native /api/chat, OpenAI-compatible /v1/chat/completions, and Anthropic-compatible /v1/messages. Side-by-side streaming, per-protocol metrics, and an envelope diff that shows how each one frames finish reasons, token counts and errors.

Knowledge Base and Embeddings
Drop in PDF, DOCX, Markdown or CSV files. They are chunked, embedded and searchable, so you see what retrieval actually returns before a model ever sees it. The Embeddings page lets you compare any two texts by cosine similarity, visualise the vectors, and see what Matryoshka truncation costs.


Everything stays in your browser's IndexedDB.
Code Completion
Fill-in-the-middle for Qwen-Coder, CodeLlama, Codestral, DeepSeek-Coder and StarCoder: a prefix, a suffix, and the model fills the gap. The stitched preview shows the result as your editor would.

Tool Workshop
A node canvas for building tool definitions, with the TypeScript kept in sync both ways: edit the nodes or edit the code. Probe an API, generate the schema, and test the tool with a live call.

Analytics and Costs
Latency percentiles (P50 / P95 / P99) for requests and first tokens, quality over turns, errors by model, a usage heatmap, and temperature against tokens per second. The cost page prices your local usage at cloud rates, so you see what running locally saves.


My System and Models
Hardware, runtime and inference overview on one page: CPU, memory, GPU, which models are loaded and where. The Models tab lists every installed model with its parameters, template and runner, and pulls new ones from the catalog.


Also in the box
AI Training Pipeline. Curate pairs from your conversations, tag and review them, export JSONL for fine-tuning.
Local history database. Every chat, comparison and benchmark is archived in IndexedDB with filters, trends, exports and retention rules.
Educators Kit. Nine lesson modules on the docs site, each built around an LLMxRay page.
Five languages. English, French, Serbian (Latin and Cyrillic), Chinese and Arabic, with RTL layout. Scaffolds ready for Hebrew and Japanese.
For agents
If you are an agent running on a local model, LLMxRay can tell you what went wrong with your own calls. Two steps.
Send your Ollama calls to port 11435 instead of 11434. It behaves exactly like Ollama and forwards everything; LLMxRay only records what passes.
Add the LLMxRay MCP server to your tools:
{ "mcpServers": { "llmxray": { "command": "npx", "args": ["-y", "-p", "llmxray", "llmxray-mcp"] } } }Three tools, all read-only, nothing leaves the machine:
Tool | Answers |
| What stands out in your recent turns, as sentences with the fix: a prompt rejected for exceeding the loaded context, the prompt cache lost on every turn or on one turn, a model running partly on CPU, tool schemas crowding the prompt. |
| Your last turn in numbers: prompt tokens and cached share, prefill time and speed, generated tokens and speed, why generation stopped, what the prompt was made of, whether the model fit in video memory. |
| Which models are pulled, their size and quantisation, which are loaded now and with what context, and whether each fits in video memory. |
LLMxRay itself must be running (npx llmxray). The MCP server reads from it over localhost.
Name yourself so your turns are yours: send the header X-LLMxRay-Client: my-agent, or use http://localhost:11435/?client=my-agent as the base URL, and pass my-agent as client to the tools. Where to set the base URL: Ollama SDKs and CLI OLLAMA_HOST=127.0.0.1:11435; OpenAI-compatible clients base_url=http://localhost:11435/v1; Claude Code ANTHROPIC_BASE_URL=http://localhost:11435; Continue apiBase; Open WebUI OLLAMA_BASE_URL.
Who is this for
You are... | LLMxRay helps you... |
Developer | Debug prompts, profile latency, compare models, inspect tool calls, see what your editor sends |
Researcher | Run controlled experiments with the same settings across models and temperatures |
Student / Educator | Watch model behaviour instead of reading about it, with the nine-module Educators Kit |
AI team lead | Give every developer the same local setup, and collect the benchmark results and training pairs they export |
Install
npx (recommended)
npx llmxray
npx llmxray --port 3000
npx llmxray --ollama-url http://192.168.1.50:11434
npx llmxray --observe-port 11436 # the Live port, 11435 by defaultDocker
docker run -p 5174:5174 -p 11435:11435 djovaneli/llmxray
docker run -p 5174:5174 -p 11435:11435 -e OLLAMA_URL=http://host.docker.internal:11434 djovaneli/llmxrayFrom source
git clone https://github.com/LogneBudo/llmxray.git
cd llmxray
npm install
npm run dev # http://localhost:5173Ollama compatibility
Tested against Ollama 0.40.x (verified on 0.40.4, October 2026). Works with 0.20 and newer; older versions chat but lack think and JSON-schema format. Recommended: 0.33.3 or newer, which reports prompt-cache reuse, so prefill speed is measured over the tokens actually evaluated.
Endpoint | Used for |
| Streaming chat (NDJSON, with |
| Generation and Fill-in-the-Middle via |
| Model list, capabilities, context length, parameters, template |
| Vector embeddings for the Knowledge Base, with optional |
| Model management and status |
| OpenAI-compatible path, used by Surgical Benchmark for real logprobs |
| Anthropic-compatible path, used by Protocol Observatory |
| Decision models, used by Decision Lab |
Under the hood
Vue 3.5, TypeScript 5.9 (strict), Vite 7, Tailwind CSS 4, Pinia stores per concern, Chart.js and D3 for charts, Vue Flow for the tool canvas, CodeMirror 6 for code. Storage is the browser's IndexedDB. The backend is Ollama, local.
Streaming reads Ollama's NDJSON through fetch() and a ReadableStream, and tokens update the UI through Pinia. Chat confidence is approximated from inter-token latency and labelled as such; benchmarks use real logprobs. Hardware detection is a small Vite plugin that asks the OS directly. The Live port is a transparent proxy that keeps counts and timings in memory.
Command | What it does |
| Dev server (port 5173) |
| Type-check and production build |
| Unit tests (Vitest) |
| End-to-end (Playwright) |
Contributing
Contributions welcome. See CONTRIBUTING.md for setup and guidelines. Community translations are especially welcome: scaffold files are ready for Hebrew and Japanese.
License
Trademark
LLMxRay is a trademark of Ivan Stankovic (LogneBudo). See TRADEMARK.md.
Available Tools
3 toolsdiagnose_my_turnsDiagnose my turnsA
What went wrong, if anything, with the calls your Ollama client sent through LLMxRay (port 11435): prompts rejected for exceeding the loaded context, prompt-cache lost on every turn or on one turn, a model running partly on CPU, tool schemas crowding the prompt. Each finding is a plain sentence with the fix. Call it after a few turns; optionally narrow to your client label and a time window.
| Name | Required | Description | Default |
|---|---|---|---|
| client | No | Part of the client label or id as LLMxRay shows it (for example "VS Code Copilot", "python-requests"). Omit for all clients. | |
| since_minutes | No | Only turns from the last N minutes. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose meaningful behavior: the tool needs a few accumulated turns to be useful, and output is 'a plain sentence with the fix' per finding, which sets the shape and tone of results. It stops short of stating that the operation is read-only, whether it has any side effects, or how expensive/slow it is.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core question ('What went wrong, if anything'), then lists the concrete failure modes, then closes with usage timing and optional filters. Dense and mostly waste-free, though the four-item enumeration is long relative to a two-parameter tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must convey the return shape, and it does ('Each finding is a plain sentence with the fix'), plus the detection categories, timing advice, and optional filters. It omits any note on what happens when nothing is wrong (empty result) or on permissions, which would complete the picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters ('client' with example labels, 'since_minutes') are already fully documented in the schema, and the description only restates them as 'your client label and a time window'. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('diagnose... the calls your Ollama client sent through LLMxRay (port 11435)') and enumerates the exact failure classes it detects, so the agent knows this is a fault-finding tool rather than a metrics reader. It never names the siblings last_turn_metrics or local_models, so the differentiation is inferential rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear triggering context ('Call it after a few turns') and states the optional narrowing ('optionally narrow to your client label and a time window'), which tells the agent the tool works unfiltered too. No alternative tool is named and no when-not-to-use condition is given, so it stops short of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
last_turn_metricsLast turn metricsA
The most recent turn seen through LLMxRay, in numbers: prompt tokens and how many came from cache, prefill time and speed, generated tokens and speed, why generation stopped, what the prompt was made of, whether the model fit in video memory. Use it to budget your next call or to confirm a change helped.
| Name | Required | Description | Default |
|---|---|---|---|
| client | No | Part of the client label or id. Omit for the latest turn from any client. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations and no output schema, the description carries the full burden, and it does disclose the shape of the returned metrics in useful detail. It is silent on the read-only nature (only implied), on what happens when no turn has been recorded yet, and on whether a running proxy/client is a prerequisite. Those operational gaps keep it at an adequate 3.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The metric list is front-loaded and each enumerated item maps to a real return field, so nothing is filler. The single long sentence is dense but readable; a slight trim of the field list would make it tighter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, enumerating the returned metrics is exactly the right compensation, and the agent knows what it will get back. Only the empty/no-data behavior and any prerequisite for having captured a turn are unaddressed for an otherwise simple one-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one optional 'client' parameter and schema description coverage is 100%, so the schema already explains the label/id matching and the 'omit for latest' default. The description never references the parameter, adding nothing beyond the schema, which is the expected baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource — the most recent turn — and enumerates exactly what 'in numbers' means (prompt tokens, cache hits, prefill time/speed, generated tokens/speed, stop reason, prompt composition, VRAM fit). That is far more concrete than a restatement of the title. It does not explicitly contrast itself with diagnose_my_turns, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives two concrete use cases — 'budget your next call' and 'confirm a change helped' — which tells the agent when this tool is the right pick. However, it offers no exclusions or explicit routing away from diagnose_my_turns, which is the obvious sibling for deeper analysis, so it is clear context without alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
local_modelsLocal modelsA
Which models Ollama has on this machine, their size, parameters and quantisation, which are loaded now and with what context, and whether each fits in video memory. Use it before choosing a model or a context length.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full burden, and it does well by disclosing the returned facets including live state ('which are loaded now and with what context') and capacity checking ('whether each fits in video memory'). What it omits is the safety profile (read-only/never mutates) and any auth or refresh-cost notes, which a no-annotation tool would ideally state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The resource and its returned facets are front-loaded in a single sentence, followed by one short usage sentence; there is no filler. The facet enumeration is dense but each item earns its place by telling the agent what it will get back.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, no annotations, and no parameters, the description is the only source of return-shape information, and it supplies a usable field list. It does not describe the structure or ordering of the result, but for a zero-argument inventory call this is close to sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, which sets the baseline at 4. Nothing in the schema needs explaining, and the description cannot add parameter meaning because there are no parameters to describe.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (Ollama models on this machine) and enumerates the exact facets returned: size, parameters, quantisation, load state, context, and VRAM fit. That is far more than a restatement of the name 'local_models', and the unrelated siblings (diagnose_my_turns, last_turn_metrics) pose no ambiguity risk.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit trigger: 'Use it before choosing a model or a context length,' which tells the agent exactly when to reach for this tool. It stops short of naming when-not to use it or an alternative, but the sibling tools cover entirely different domains, so no exclusion is realistically needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.8.0- First observed
diagnose_my_turns - First observed
last_turn_metrics - First observed
local_models
Related MCP Connectors
Find your AI agent's likely failure mode, get runtime settings, and clarify ambiguous prompts.
Watches your live app, explains every problem in plain language and writes the fix prompt.
Diagnose why an AI agent failed and get the verified fix instantly. Free, no token.
Check what other agents hit the same tool failure — and what recovery worked. Ask before retrying.
Related MCP Servers
- AlicenseCqualityCmaintenanceProfessional local context management and system diagnostic tools for AI IDEs (Cursor, Trae, Antigravity, Windsurf).3684 npm1MIT
- AlicenseNot gradedqualityBmaintenanceLocal-first observability for AI agent stacks. Provides MCP tools for agents to check health, shadow configs, and burnout metrics proactively.1GPL 3.0
- AlicenseNot gradedqualityDmaintenanceEnables LLM clients to inspect local dev environments—Docker container health, pnpm workspace integrity, and stuck process detection—without manual terminal copy-pasting.MIT
- AlicenseNot gradedqualityFmaintenanceProvides AI agents with real-time cognitive health monitoring, detecting context rot through token utilization, retrieval accuracy, and session fatigue analysis.22 npm13MIT