Skip to main content

DecisionNode MCP server

DecisionNode is a decision engine: send it text, JSON or images with a question, and it answers with calibrated probabilities.

DecisionNode's judgments as tools for AI agents. An agent asks a narrow question about a piece of content (is this claim supported, which team should take this ticket, how urgent is it, how many line items does the invoice list, where in the photo is the damaged package) and gets a calibrated answer back in one tool call.

Every tool call is a DecisionNode API request made with your own API key. The server stores no key, state, question or answer.

Install

You need a DecisionNode API key and uv. The server runs on your machine and your MCP client starts it over stdio:

uvx bynn-decisionnode-mcp

Before the package's first release on PyPI, install it from this repository instead:

uvx --from git+https://github.com/Bynn-Intelligence/decision-node-mcp-server bynn-decisionnode-mcp

In the client setups below, the git form replaces bynn-decisionnode-mcp with --from git+https://github.com/Bynn-Intelligence/decision-node-mcp-server bynn-decisionnode-mcp.

Claude Code

claude mcp add decisionnode -e DECISIONNODE_API_KEY=<key> -- uvx bynn-decisionnode-mcp

Claude Desktop

Add the server to claude_desktop_config.json (Settings, Developer, Edit Config) and restart Claude Desktop:

{
  "mcpServers": {
    "decisionnode": {
      "command": "uvx",
      "args": ["bynn-decisionnode-mcp"],
      "env": { "DECISIONNODE_API_KEY": "<key>" }
    }
  }
}

Other MCP clients

Cursor, Windsurf and other clients configured by a JSON file take the same entry under mcpServers; VS Code takes it under servers. Any client that launches a server over stdio works: the command is uvx, the argument is bynn-decisionnode-mcp, and the key goes in the server's environment as DECISIONNODE_API_KEY. The server name (decisionnode above) is yours to choose.

Over HTTP

The same package serves Streamable HTTP, for a team that runs one server for several clients:

uvx bynn-decisionnode-mcp --transport http --host 0.0.0.0 --port 8000

The endpoint is the root path, stateless, with GET /health. Each client sends its own key on every request, Authorization: Bearer <key>, and the server forwards it to the API; it never uses a key of its own. Over HTTP a tool never reads a file path, and the base64 image data of one call is limited to 3 MiB (see Images below).

claude mcp add --transport http decisionnode http://127.0.0.1:8000/ \
  --header "Authorization: Bearer $DECISIONNODE_API_KEY"

Tools

All eleven are read-only and idempotent (readOnlyHint and idempotentHint true, destructiveHint false). Each declares an output schema and returns its result twice: as structured content, and as the same JSON in a text block.

Tool Use it to Returns Costs
guide Learn how to use the other tools well The guide, as text Nothing
truth Ask one yes-or-no question about a state {"truth": 0.94, "cost": {...}} A request
choice Pick one option from a set you define (1 to 255) {"choice", "confidence", "probabilities", "cost"} A request
score Place a state on an ordered scale (1 to 10 levels) {"score", "confidence", "legend", "probabilities", "cost"} A request
number Ask for a count or a quantity within a range {"number", "expected", "confidence", "probabilities", "cost"} A request
point Find one spot in an image {"x", "y", "present", "confidence", "image", "width", "height", "cost"} A request
box Draw a box around one thing in an image {"x1", "y1", "x2", "y2", "present", "confidence", "image", "width", "height", "cost"} A request
decide Ask several questions of any type about one state {"answers": {id: answer}, "model", "input_tokens", "cost"} One request
decide_many Ask the same questions about many states (1 to 50 items) {"results": {item id: {"answers", "cost"} or {"error"}}, "input_tokens"} One request per item
decide_video Ask questions of any type about videos sent as frames {"answers", "model", "input_tokens", "cost", "video_frames", "video_seconds"}, and warnings One request
models List the models the key may use, with their limits {"models": [...]} Nothing

Inputs:

Tool Arguments
truth instructions, state, if_true, if_false, images, model
choice instructions, options (a list of names, or an object of name to description), state, images, model
score instructions, levels (lowest first), state, images, model
number instructions, min, max, step, state, images, model
point, box instructions, images (at least one), image, units, state, model
decide questions (id to {type, instructions, criteria}, {type, instructions, min, max, step} for a number, or {type, instructions, image, units} for a point or a box, as the API takes them), state, images, model
decide_many items (a list of {id, state, images}, images optional and each item's own), questions, model
decide_video questions, videos, state, images, model

cost, on every tool that asks a question, is what the call cost as the API booked it, in USD: usd, split into model_usd and boosters_usd, and free_tier. It is passed through as sent and appears when the API sends it.

state is a string or any JSON value and may be left out. model defaults to decisionnode-moe; decisionnode-flash is the faster, lower-cost tier. Both mean the current release; a result's model is the pinned id of the version that answered. The question types are truth, choice, score, number, point and box.

Values are passed through exactly as the API sent them. A result has a safety field only when the API's safety check flagged a category for the key.

Images

Up to 16 images a call, within the model's token limit, 10 MB each, JPEG, PNG or WebP. An image is {id, url}, {id, data, media_type} or, on your own machine, {id, path} for a file. A url must start with https://; any other scheme is refused before a request is made.

There are two ways to say which image a question is about:

  1. By id (recommended). Give each image a short, meaningful id and use it in the instructions, in backticks: "Does the total on receipt match the amount in the claim?"
  2. By number. Images are numbered from 1 in the order of images: "image 2", "the second image", "Picture 2" and "the last image" all work.

The model sees each image as Picture 1 (receipt):, Picture 2 (claim_photo):, so both ways point to the same image. Prefer ids: they stay right when images are added or reordered. Use names, not digits, as ids (front, not 2). Videos work the same way, by id or by number ("video 1"), numbered separately in the order of videos. The image of a point or box question takes the id.

Over HTTP one call's body is limited to 4 MiB by the MCP transport, so the base64 data of all images in a call (every item's, in decide_many) is limited to 3 MiB in total (3,145,728 characters, about 2.25 MiB of image bytes). A call with more is refused with an invalid_request_error tool result before any request is made, and a body over 4 MiB is answered 413. Send larger images by https url; the API fetches them itself, up to the model's own limit (10 MB an image).

Number questions

A number question asks for a count or a quantity within a range: how many people are in the photo, how many line items the invoice lists, the year a contract was signed, a rating in halves. min and max bound the answer (0 and 255 when left out) and step sets the grid of possible answers (1 when left out; 0.5 for halves). The grid holds at most 4,096 values; keep the range as narrow as the question allows.

{"type": "number", "instructions": "How many cars are visible?", "min": 0, "max": 50}

The answer:

{"number": 7, "expected": 7.3, "confidence": 0.62, "probabilities": {"6": 0.21, "7": 0.62, "8": 0.14}}

number is the most probable value on the grid and confidence its probability. expected is the probability-weighted mean, a fractional estimate even on a grid of whole numbers. probabilities lists the values above 0.001, keyed by the value as a string, so they can sum to less than 1. Number questions work on text, images and video frames, alone with the number tool or beside other questions in decide, decide_many and decide_video.

Points and boxes

A point or box question asks where something is in an image: point gives one spot, box a rectangle around the thing. The instructions say what to find, as a phrase ("the yellow package"), a description with conditions ("the person standing nearest the door") or a question ("Where is the crack?"), and can refer to the state and to the other images ("the part that differs from the reference image").

{"type": "box", "instructions": "Draw a box around the damaged package.", "image": "belt"}
Field
instructions What to find.
image The id of the image to look in (a string). Needed with two or more images; with one, that one is used. A reference by number ("Picture 2") goes in the instructions.
units pixels (the default): pixels of the image as sent. normalized: fractions of the width and the height, from 0 to 1.

A point or box question needs at least one image in the call. The point and box tools require images and check image before any request is made.

The answers:

{"x": 812, "y": 455, "present": 0.97, "confidence": 0.91, "image": "belt", "width": 1920, "height": 1080}
{"x1": 300, "y1": 120, "x2": 520, "y2": 410, "present": 0.95, "confidence": 0.88, "image": "belt", "width": 1920, "height": 1080}
Field
x, y The point, from the image's top-left corner, x to the right and y down: whole pixels, or fractions with normalized units.
x1, y1, x2, y2 The box: its top-left corner (x1, y1) and bottom-right corner (x2, y2), in the same units.
present The probability that what the instructions describe is in the image at all. Under a low present the place is only a best guess for something probably not there.
confidence The probability that the place is right if the thing is there: for a point, that it lies on the thing; for a box, that it overlaps the true box by at least half (an intersection over union of 0.5 or more).
image, width, height The image looked in and its size in pixels, to draw or convert the answer without another lookup.

Every field is always there, so the shape never changes. Act on an answer when both present and confidence are high, and hand the image to a person when either is low. The thresholds are yours. When several things match ("the yellow package" with three on the belt), the answer is the best match; the instructions can say which one ("the leftmost yellow package"). Point and box questions mix with the other types in decide, and in decide_many each item can carry its own images, such as one photo per item.

Video (frames)

Only frames are sent: no video file, video URL or sound ever reaches the API. A video is the frames a camera or a script took, each with its time, and the model reads them as one video, in order and with their times:

{
  "id": "dock",
  "fps": 2,
  "frames": [
    {"t": 30.0, "media_type": "image/jpeg", "data": "<base64>"},
    {"t": 30.5, "media_type": "image/jpeg", "data": "<base64>"}
  ]
}
Field
id Unique within the call, across images and videos. The model sees the video as "Video " (its place in videos, from 1) with this id beside it, so questions can refer to it by either.
frames The frames in time order, all of one size: t in seconds, larger than the frame before; media_type image/jpeg, image/png or image/webp; data the image as base64.
fps A cap on the frames read a second: 2 when left out, at most 4.
start, end A window in seconds on the frames' own times; every frame when left out.

On your own machine a video can also be a file, {"id": "dock", "path": "~/clips/dock.mp4", "fps": 2, "start": 30, "end": 45}. The server samples it into JPEG frames on that machine with ffmpeg, at fps within start and end (seconds from the video's first frame), at most max_frames of them (32 when left out, up to 128). A window that holds more frames at that rate is cut there, and the result's warnings say so. The frames are then sent as above; the file itself and its sound stay on the machine. ffmpeg and ffprobe must be on the PATH the client starts the server with (set PATH in the server's env if they are not); without them a path video is refused with an error that says so, and frames still work. Over HTTP the server never reads a path.

Send as few frames as the question needs: one or two for one item on a sorting line, about one a second for an incident such as a fall or smoke, about two a second for counting what passes. The API publishes its video limits with the models (models). Over HTTP the base64 data of the images and the frames of one call share the 3 MiB above.

A decide_video result carries answers, model and input_tokens as decide does, plus video_frames and video_seconds (what the API read), and warnings when the API read a video at a lower rate or a smaller size than sent, or a file's window was cut.

Errors

A failed call is a tool result with isError true and the error as structured content:

{
  "error_type": "invalid_request_error",
  "message": "Too many score levels. Must have at most 10 levels.",
  "reason": "question 'score': a score takes up to 10 levels, got 11",
  "status": 400,
  "request_id": "req_..."
}

reason is the API's explanation in words, so the agent can correct the call. A request refused under the usage policy has error_type refusal_error and its category. A 422 adds entries; a 429 or 529 adds retry_after in seconds. Temporary failures (408, 429, 5xx, timeouts, dropped connections) are retried twice before an error is reported; 400, 401, 402, 403, 404 and 422 are never retried.

Configuration

Variable Default
DECISIONNODE_API_KEY none The API key, on stdio. Over HTTP each caller's own key is used and never this one.
DECISIONNODE_BASE_URL https://api.decisionnode.com The API the tools call. Must be https://; plain http:// is accepted only for a loopback address (localhost, 127.0.0.1, ::1), and any other is refused at startup.
DECISIONNODE_MODEL decisionnode-moe The default model.
DECISIONNODE_MCP_RATE_LIMIT 120 over HTTP, 0 (off) on stdio Requests a minute per key on each server process; 0 turns it off. A negative or non-numeric value is refused at startup. Several processes each count on their own. At most 10,000 keys are tracked per process; when the table is full, a new key replaces one whose minute has passed, and if every tracked key has called within the minute the new key's call is refused with the rate-limit error.
MCP_TRANSPORT stdio Or http; the --transport flag wins.
MCP_HOST, MCP_PORT, MCP_PATH 127.0.0.1, 8000, / HTTP only; the --host, --port and --path flags win.

Over HTTP the server accepts any well-formed bearer value and refuses a request without one (401). The API decides whether the key is valid. A key the API has just answered 401 for is refused for the next 60 seconds with the same error result, and no request is made; the server holds only the key's SHA-256 digest, in memory. The key is never written to a log.

Development

Requires Python 3.10 or later and uv.

git clone https://github.com/Bynn-Intelligence/decision-node-mcp-server
cd decision-node-mcp-server
uv sync
uv run bynn-decisionnode-mcp                      # stdio
uv run bynn-decisionnode-mcp --transport http     # http://127.0.0.1:8000/

The tests run against the mock API server of the DecisionNode SDK conformance suite and never call a real endpoint. Clone the suite beside this repository, or point DECISIONNODE_CONFORMANCE_DIR at it:

git clone https://github.com/Bynn-Intelligence/decision-node-conformance ../decision-node-conformance
uv run pytest

The video file tests need ffmpeg and ffprobe and are skipped without them. After a deliberate change to a tool's schema or result, regenerate the golden files with UPDATE_GOLDEN=1 uv run pytest tests/test_golden.py.

License

MIT. See LICENSE.

Metadata

Release files for bynn-decisionnode-mcp 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bynn-decisionnode-mcp 0.1.2
File Size Uploaded
bynn_decisionnode_mcp-0.1.2.tar.gz 35.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bynn-decisionnode-mcp 0.1.2
File Interpreter ABI Platform
bynn_decisionnode_mcp-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 79.2 kB

Release files / bynn_decisionnode_mcp-0.1.2.tar.gz

Download URL bynn_decisionnode_mcp-0.1.2.tar.gz
Size 35.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b8d09c0521284778ca4715f5e30d57ebd7b0eafc593e45c4ce052f705d0cf959
BLAKE2b-256 checksum
How to use checksums
c63160ab66b8da3ce721d2784934f25488e2bae40c2774e52ba3ff3bc28dd2dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / bynn_decisionnode_mcp-0.1.2-py3-none-any.whl

Download URL bynn_decisionnode_mcp-0.1.2-py3-none-any.whl
Size 44.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
293330db07da42c305edc048bb2ed672422c3e2740be379e25a1ca6037b7ad8a
BLAKE2b-256 checksum
How to use checksums
343df6000ac60551e3777ef32f6a3270d63fbe9b46d0efcc2de9631fd25ca531
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page