Skip to main content
Glama
ZRZRING

low-hallucination-vision

by ZRZRING

Low-Hallucination Vision Toolkit

A drop-in replacement for high-hallucination vision MCPs (like the default analyze_image), built on top of your own OpenAI-compatible multimodal model (mimo v2.5). Two pieces that work together:

vision-mcp/      ← MCP server (Python). The engine. Plug into any agent.
vision-skill/    ← Skill (SKILL.md). The cross-verification workflow. Plug into ZCode.

Why this is lower-hallucination than a generic VLM call

It's not magic — it's five boring disciplines, all in the MCP layer:

  1. Mode-routed prompts — UI / general / OCR / detect each get a tightly scoped system prompt instead of one "describe everything" prompt.

  2. Forced structured JSON — every claim is an object with confidence.

  3. Low temperature (0.2 default) — less creative completion.

  4. "Allowed to be ignorant" — prompts explicitly forbid common-sense completion of details not actually visible.

  5. Confidence gating — the MCP reflags any claim below threshold as "_flag": "存疑", so the agent can't accidentally report it as fact.

The Skill adds a sixth layer on top: cross-verification (run two independent modes and only trust claims both agree on).


Related MCP server: mcp-eyes

Setup (uv-managed environment)

This project uses uv for environment management. uv creates an isolated .venv per project and pins the Python version, so nothing pollutes your global Python. The .venv is what VSCode auto-detects.

1. Install dependencies & create the venv

cd C:\Users\zrzring\ZCodeProject\vision-mcp
uv sync

That single command:

  • reads .python-version (3.12) and auto-downloads that Python if missing,

  • creates vision-mcp\.venv,

  • installs everything in pyproject.toml (currently mcp[cli]).

To add a package later: uv add <pkg>. To rebuild after pulling the repo: just uv sync again. Never use raw pip here — it would install into the wrong place.

Verify it works:

uv run python -c "import main; print('OK', main.mcp.name)"
# → OK low-hallucination-vision

2. Configure API credentials

copy .env.example .env          # then edit .env
VISION_API_BASE=https://api.mimo.example.com/v1   # your OpenAI-compatible endpoint
VISION_API_KEY=sk-...
VISION_MODEL=mimo-vl-2.5
VISION_TEMPERATURE=0.2

3. Make VSCode detect the venv

VSCode's Python extension auto-detects .venv in the workspace. To be safe:

  1. Open the folder C:\Users\zrzring\ZCodeProject (not the single file) in VSCode.

  2. Install the Python extension (ms-python.python) if not already.

  3. Ctrl+Shift+PPython: Select Interpreter → pick the one shown as Python 3.12.13 ('.venv') under vision-mcp\.venv\Scripts\python.exe.

If it doesn't show up, force it with a workspace setting — create .vscode/settings.json in the project root:

{
  "python.defaultInterpreterForWorkspace": "vision-mcp\\.venv\\Scripts\\python.exe",
  "python.terminal.activateEnvironment": true
}

Now any terminal you open in VSCode auto-activates .venv, and you get autocomplete / type-checking for mcp and your code.

4. Register the MCP server with your agents

The server speaks stdio MCP. Use uv run to launch it — this guarantees the project's .venv is used regardless of the agent's working directory:

Claude Code~/.claude.json (or project .mcp.json):

{
  "mcpServers": {
    "low-hallucination-vision": {
      "command": "uv",
      "args": ["run", "--directory",
                "C:\\Users\\zrzring\\ZCodeProject\\vision-mcp",
                "python", "main.py"],
      "env": {
        "VISION_API_BASE": "https://api.mimo.example.com/v1",
        "VISION_API_KEY": "sk-...",
        "VISION_MODEL": "mimo-vl-2.5"
      }
    }
  }
}

OpenCodeopencode.json:

{
  "mcp": {
    "low-hallucination-vision": {
      "type": "local",
      "command": ["uv", "run", "--directory",
                   "C:\\Users\\zrzring\\ZCodeProject\\vision-mcp",
                   "python", "main.py"],
      "environment": {
        "VISION_API_BASE": "https://api.mimo.example.com/v1",
        "VISION_API_KEY": "sk-...",
        "VISION_MODEL": "mimo-vl-2.5"
      }
    }
  }
}

ZCode — same mcpServers shape as Claude Code.

Why uv run --directory instead of a bare python? Because the agent may launch the server from any working directory; uv run --directory always activates the right .venv. Environment variables can live in the config (as above) OR in vision-mcp/.env — either works.


Alternative: build a standalone vision-mcp.exe

If you'd rather not depend on uv/Python at runtime, package the server into a single executable with PyInstaller. The exe is self-contained (~24 MB), needs no Python installed, and works on any machine when shipped with its .env. It runs in two modes: a stdio MCP server (default) and a command-line image tool.

Build it

pyinstaller is already in pyproject.toml, so after uv sync:

cd C:\Users\zrzring\ZCodeProject\vision-mcp
uv run pyinstaller --onefile --name vision-mcp --collect-all mcp --clean --noconfirm main.py

Output lands in dist\vision-mcp.exe. The vision-mcp.spec file is auto-generated; you can re-run pyinstaller vision-mcp.spec --noconfirm after that for identical builds.

Put it on PATH and configure

  1. Copy the exe and your .env to a directory already on PATH (e.g. C:\Users\<you>\.local\bin):

    copy dist\vision-mcp.exe  C:\Users\<you>\.local\bin\
    copy .env                 C:\Users\<you>\.local\bin\
  2. The exe reads .env from its own directory first, then the source dir, then the working dir. So keep .env next to the exe — change key/endpoint there, no rebuild needed.

  3. Verify from anywhere:

    vision-mcp --help
    vision-mcp analyze C:\path\to\pic.png --mode general --prompt "describe it"

Register the exe with agents

Because the exe defaults to MCP-server mode, agent config is minimal — no uv run, no args, no env block (creds come from the exe's .env):

Claude Code~/.claude.json (or project .mcp.json):

{
  "mcpServers": {
    "low-hallucination-vision": {
      "command": "vision-mcp"
    }
  }
}

OpenCodeopencode.json:

{
  "mcp": {
    "low-hallucination-vision": {
      "type": "local",
      "command": ["vision-mcp"]
    }
  }
}

If vision-mcp isn't on PATH for the agent, use the full path instead: "command": "C:\\Users\\<you>\\.local\\bin\\vision-mcp.exe".

CLI mode (use it directly, no agent)

The same exe doubles as a terminal image tool:

vision-mcp                                    # = MCP server (default)
vision-mcp mcp                                #   "    (explicit)
vision-mcp analyze <image> [--mode general|ui_screenshot|ocr|detect] [--prompt "..."]
vision-mcp ocr      <image> [--prompt "..."]
vision-mcp detect   <image> [--prompt "..."]

<image> is a local path or an http(s) URL. Output is the same JSON the MCP tools return (with bbox normalization + confidence flagging applied).

Source vs exe — which to use? Source (uv run) is best while developing (edit main.py, reload instantly). The exe is best for daily use and sharing to other machines — no Python toolchain needed.

3. (Optional) Register the Skill with ZCode

Copy or symlink vision-skill/ into your skills directory so the cross-verification workflow is auto-loaded:

<skills-dir>/low-hallucination-vision/SKILL.md

The Skill is agent-agnostic in content but only ZCode auto-discovers Skills. For Claude Code / OpenCode, the MCP tools alone still work — just keep the Skill's workflow in mind (or paste the relevant section into your own prompt).


Tools provided

Tool

What it does

When to use

analyze_image(image_source, mode, prompt, temperature)

Structured analysis; mode = general / ui_screenshot / ocr / detect

Default entry point

ocr_extract(image_source, prompt, temperature)

Text-only extraction

When you only need words

detect_elements(image_source, prompt, temperature)

Object detection with mandatory bbox

When you need locations

All three return JSON. Claims below VISION_CONFIDENCE_THRESHOLD (default 0.6) are tagged "_flag": "存疑".

image_source accepts either a local file path or an http(s) URL.


File map

ZCodeProject/
├── vision-mcp/                ← uv project (this README lives here)
│   ├── main.py                ← the MCP server + CLI (engine + anti-hallucination)
│   ├── pyproject.toml         ← deps: mcp[cli], pyinstaller
│   ├── uv.lock                ← pinned versions (auto-generated)
│   ├── .python-version        ← 3.12 (uv auto-downloads it)
│   ├── .env.example           ← copy to .env and fill in
│   ├── vision-mcp.spec        ← auto-generated by PyInstaller (for rebuilds)
│   ├── .venv/                 ← created by `uv sync` (gitignored)
│   ├── build/                 ← PyInstaller intermediates (gitignored)
│   └── dist/
│       └── vision-mcp.exe     ← the standalone exe (built, gitignored)
└── .agents/                   ← skill(s) discovered by ZCode
    └── skills/vision-skill/
        └── SKILL.md           ← cross-verification workflow for the agent

Tuning

  • Still too much hallucination? Lower VISION_TEMPERATURE to 0.1 and raise VISION_CONFIDENCE_THRESHOLD to 0.7.

  • Missing real things (over-conservative)? Lower the threshold to 0.5 and raise temperature slightly to 0.3.

  • Model keeps breaking JSON? Some VLMs ignore schema instructions; in that case the tool returns "_parse_error": true with the raw text so you can post-process. Consider switching to a model with stronger JSON support.

Available Tools

3 tools
analyze_imageA

Analyze an image with anti-hallucination safeguards.

Args:
    image_source: Local file path or http(s) URL of the image.
    mode: One of "general" | "ui_screenshot" | "ocr" | "detect".
        - general       structured subject/background/style description
        - ui_screenshot UI element inventory with bbox + confidence
        - ocr           text-only extraction (see ocr_extract for the dedicated tool)
        - detect        object detection with mandatory bbox
    prompt: Optional extra instructions (e.g. "focus on the top-right card").
    temperature: Sampling temperature, default 0.2 (low = less hallucination).

Returns:
    JSON string. Low-confidence claims are tagged with "_flag": "存疑".
ParametersJSON Schema
NameRequiredDescriptionDefault
modeNogeneral
promptNo
temperatureNo
image_sourceYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries full burden. It discloses anti-hallucination safeguards, a confidence flag ("存疑"), mandatory bbox behavior, and temperature's effect on hallucination. Rich behavioral disclosure beyond basic operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with Args/Returns sections, but slightly verbose with the mode definitions. Still, every line adds value, so minor deduction only for length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

All parameters, return format, and behavioral traits are covered, including the custom flag. The description is self-contained for a 4-param tool with no schema annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has zero descriptions; the description fully compensates by defining image_source as path/URL, enumerating mode values with their outputs, and explaining prompt/temperature semantics beyond defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Starts with a clear verb+object ('Analyze an image') and immediately differentiates from siblings by explicitly pointing to ocr_extract for OCR and describing distinct modes (general, ui_screenshot, ocr, detect). This leaves no ambiguity about the tool's scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Includes a mode list that explains which analysis to run, explicitly defers OCR to the dedicated ocr_extract tool, and notes mandatory bbox for detect mode. This gives the agent clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

detect_elementsA

Detect objects in an image with mandatory bounding boxes.

Conservative by design: prefers false negatives over false positives.

Args:
    image_source: Local file path or http(s) URL of the image.
    prompt: Optional extra instructions (e.g. "only people and vehicles").
    temperature: Sampling temperature, default 0.2.

Returns:
    JSON: {"objects":[{"label","bbox","confidence"}], "overall_confidence"}.
ParametersJSON Schema
NameRequiredDescriptionDefault
promptNo
temperatureNo
image_sourceYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavioral traits: it explicitly notes the precision/recall tradeoff ('prefers false negatives over false positives') and the mandatory bounding box output. This provides meaningful insight beyond the basic input/output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a one-sentence summary, a key behavioral note, and clearly labeled Args and Returns sections. Every sentence provides useful information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, the description provides a concrete example of the return JSON, and covers input, output, and behavioral policy. For a tool with 3 parameters and moderate complexity, this is complete and sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, but the description fully compensates by explaining all three parameters: image_source as a local path or URL, prompt as optional instructions with an example, and temperature with a default. This adds significant semantic meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Detect objects in an image with mandatory bounding boxes,' providing a specific verb and resource. However, it does not explicitly differentiate from sibling tools like analyze_image or ocr_extract, so the purpose is clear but lacks sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for object detection with a 'conservative by design' behavior, giving clear context on when to use the tool. It does not explicitly state exclusions or alternative tools, so it falls short of the highest rating.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ocr_extractA

Extract visible text from an image (OCR only, no scene description).

Args:
    image_source: Local file path or http(s) URL of the image.
    prompt: Optional extra instructions.
    temperature: Sampling temperature, default 0.2.

Returns:
    JSON: {"texts":[{"text","bbox","confidence"}], "overall_confidence"}.
    Unclear characters are dropped, never guessed.
ParametersJSON Schema
NameRequiredDescriptionDefault
promptNo
temperatureNo
image_sourceYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It reveals key behaviors: it returns a specific JSON structure, and unclear characters are dropped rather than guessed. This adds meaningful context beyond a bare description, though it does not cover potential rate limits or authentication requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured. The first line states the core purpose, followed by an 'Args' section and a 'Returns' section. Every sentence adds value—no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with three parameters and an output schema, the description is remarkably complete. It includes parameter semantics, return format, a behavioral caveat about OCR accuracy, and the scope limitation. This allows an agent to select and invoke the tool correctly without additional context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only parameter names and defaults, but the description explains each parameter's semantics: image_source can be a local path or HTTP(s) URL, prompt is optional instructions, and temperature is sampling temperature with a default of 0.2. This compensates well for the 0% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool extracts visible text from images, with the explicit constraint 'OCR only, no scene description'. This distinguishes it from sibling tools like analyze_image and detect_elements, making its purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear use context: it is for OCR text extraction, not scene understanding. It explicitly excludes scene description, which helps the agent avoid using this tool for image analysis tasks. However, it does not name sibling alternatives directly, so a 4 is appropriate.

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. Dates show when Glama detected each change.

  1. 3 tool updatesv0.1.0
    • First observedanalyze_image
    • First observeddetect_elements
    • First observedocr_extract

TDQS

A4.4/5.0
Disambiguation3/5

The analyze_image tool includes modes for OCR and detection, directly overlapping with ocr_extract and detect_elements. While descriptions reference the dedicated tools, the redundancy creates potential confusion about which tool to choose. The general-purpose nature of analyze_image vs. the specialized tools provides some clarity, but boundaries are not crisp.

Naming Consistency4/5

Two tools follow the verb_noun pattern (analyze_image, detect_elements), while ocr_extract inverts the order. All are snake_case and descriptive, so the inconsistency is minor and does not impede readability.

Tool Count5/5

Three tools is a well-scoped count for a focused vision server, each targeting a distinct primary task: general analysis, OCR, and object detection. This falls squarely within the ideal 3-15 range.

Completeness4/5

The set covers core vision workflows: general scene description, text extraction, and object detection. Minor gaps exist (e.g., no dedicated UI screenshot tool despite analyze_image's mode), but the surface is functional and sufficient for typical use cases.

Maintenance

ActivityStale
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ZRZRING/vision-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server