Skip to main content
Glama
SDNick484
by SDNick484

mcp-server-onkyo

CI

An MCP server for Onkyo AV receivers, so Claude Code, Claude Desktop, the Claude mobile app (through a connector) or any other MCP client can turn zones on, set volumes, pick inputs and listening modes, and play network audio. It talks eISCP (the Integra Serial Control Protocol over Ethernet, TCP/UDP 60128) directly: no cloud, no pairing.

It's one of four sibling servers with the same conventions (multi-device by name, dry run, doctor, Streamable HTTP behind Cloudflare Access): mcp-server-harmony, mcp-server-sofabaton and mcp-server-shieldtv.

Status. The core protocol (power, volume, inputs, Zone 2, network services, stations, folders) was used against a TX-NR6050 and a TX-NR7100 in 2026-10. The features added since (several receivers by name, per-zone caps, resources and prompts, dry run, doctor, HTTP, the Alpine service) are verified against the simulator only. Verification status lists every protocol assumption and whether hardware has confirmed it; HARDWARE_VALIDATION.md is the checklist that will. This is also a learning project for MCP, so the code is commented for that.

Tools

Tool

Read-only

What it does

get_status

yes

Every receiver and zone: power, volume (0-100), the zone's volume cap, mute, input; the main zone's listening mode; which zones are on the network player

set_power

Turn a zone on, or put it in standby

set_volume

Set a zone's volume (0.5 steps on newer models), lowered to the zone's cap if higher

set_mute

Mute or unmute a zone

set_input

A zone's input: bd-dvd, game, cbl-sat, strm-box, pc, aux, tv, phono, cd, fm, am, net, bluetooth; zones 2/3 also same-as-main

set_listening_mode

The main zone's mode: stereo, direct, pure-audio, all-ch-stereo, full-mono, theater-dimensional, dolby-surround, dts-neural-x, game-rpg, game-action, game-rock, game-sports

select_net_service

Switch the network player to pandora, spotify, deezer, tidal, amazon-music, airplay, tunein or music-server

list_net_services

yes

The services this receiver lists itself, and which of them the tools can select

get_now_playing

yes

The network player's service, station, play state, title, artist, album, position

list_stations

A service's menu: what can be played, and folders (refuses to open a different service, which would stop the music, unless interrupt=true)

play_station

Play a station or track by (part of its) name, optionally inside folder

control_playback

Play, pause, stop, next, previous

discover_receivers

yes

UDP broadcast: each receiver's address, model, port and MAC

Arguments shared by the tools. receiver is a configured name (case, spaces and punctuation ignored: family-room = Family Room) or an address. With one receiver configured it can be left out. With several, a setter without it is refused, never guessed: the error names the receivers so the model can ask you. get_status without it covers them all. zone is main (the default), zone2 or zone3.

Results. Read-only tools return typed JSON (each tool's outputSchema). Every setter returns the same ActionResult shape as the sibling servers:

{"receiver": "Family Room", "zone": "zone2", "outcome": "done",
 "detail": "Zone 2: Volume is now 50.0", "sent": ["ZVL64"],
 "warnings": ["Requested 90, capped at 50 (the owner's limit for this zone)."]}

outcome is done or dry_run; sent is the eISCP commands that change something. Failures are MCP errors (isError: true) with a sentence that says what to do: Zone 2 of Theater (192.168.1.245) is in standby. Turn it on with set_power with zone='zone2' first.

Annotations. Read-only tools are marked readOnlyHint. Setters are non-destructive and idempotent (volume 30 twice is volume 30), so clients may retry them; control_playback isn't idempotent ("next" twice skips two tracks). discover_receivers is the one open-world tool, since it lists whatever answers a broadcast. list_stations is marked as a setter, not read-only: browsing moves the receiver's on-screen menu.

Zones

The server asks each receiver which zones it has (NRIQSTN, once, then cached), so a missing zone or one without volume control gets an immediate answer instead of a timeout. Zones are independent: Zone 2 can play while the main zone is in standby.

Model

Zones

Multi-zone outputs

TX-RZ71, TX-RZ70

3

Main, powered Zone 2 / line out, Zone 3 line out; HDMI Zone 2

TX-RZ61, TX-RZ51, TX-RZ50

3

Main, powered Zone 2 / line out, Zone 3 line out

TX-NR7200

3

Main, powered Zone 2, Zone 3 line out

TX-NR7100

3

Main, powered Zone 2 / line out, Zone 3 line out; HDMI Zone 2

TX-RZ31, TX-RZ30

2

Main, powered Zone 2 / line out

TX-NR6200, TX-NR6100, TX-NR6050, TX-NR5100

2

Main, powered Zone 2 / line out

What's usable also depends on the speaker setup. A powered Zone 2's amplifier channels can drive other speakers instead (height channels in a 5.2.4 layout, as on the TX-NR7100 here), and then that zone has no volume control. Zone 3 codes (PW3/VL3/MT3/SL3) come from the onkyo-eiscp tables and haven't been tried: neither receiver here has a working Zone 3.

The shared network player

A receiver has one network player, heard in every zone whose input is net. The commands that drive it (NSV, NLS, NTC) don't name a zone, so Zone 2 can't play Pandora while the main zone plays TuneIn. The tools say so: set_input source=net warns when another zone is already on net, and select_net_service warns when nobody will hear it or several zones will.

Folders: list_stations and play_station take a folder path, e.g. TuneIn's ["My Presets"] or a music server's ["MiniDLNA", "Music", "Album", "21"] (part of each name is enough). Long menus are read 100 items at a time. A signed-out service opens a sign-in popup instead of its menu; the tools quote it ("TIDAL Login") and say to sign in with the Onkyo Controller app.

Service

What happens (TX-NR6050)

Pandora

Stations listed and played by name

TuneIn, Music Server

Browsed through folders; tracks and stations played by name

TIDAL, Amazon Music, Deezer

Menu if signed in (and subscribed); otherwise a clear "isn't ready"

Spotify, AirPlay

Selected; playback starts from a phone (Spotify Connect, AirPlay)

Related MCP server: sony-bravia-mcp

Resources and prompts

Resources are context a client attaches (in Claude Code: @onkyo:onkyo://receivers). Reading one sends nothing but NRIQSTN, once per receiver.

Resource

What it holds

onkyo://receivers

Every configured receiver: model, zones (volume control, cap), network services

onkyo://receivers/{receiver}

One of them, by name or address (onkyo://receivers/Family%20Room)

onkyo://catalog

The inputs, listening modes, services and zones the tools accept, with each eISCP code and the assumption it rests on

Prompts are workflows you pick (in Claude Code: /mcp__onkyo__play_music patio pandora). Each walks the model through this server's tools in order and names the traps.

Prompt

Arguments

Does

play_music

room, service, station, volume

Finds the receiver and zone for the room (asks if unclear), turns it on, net, service, station

movie_night

receiver, source, listening_mode, volume

The receiver's part: main zone on, the video input (asks rather than guess the wiring), mode, volume

all_off

receiver

Every zone that's on into standby, then confirms

Movie night across servers

The servers don't know about each other. That's deliberate: each one works alone, and a client with several connected composes them. With all four connected, "movie night in the theater" can be one request:

Movie night in the theater: start the Harmony activity "Watch Shield", open Plex on the Shield, put Theater on strm-box in Dolby Surround at 45, and turn off Zone 2 of the Family Room.

The model then calls, in order (tool names as of these versions):

harmony.start_activity   activity="Watch Shield"            # TV and receiver on, inputs switched
shieldtv.launch_app      app="plex"
onkyo.get_status         receiver="Theater"                  # confirm Harmony left it on strm-box
onkyo.set_input          receiver="Theater" source="strm-box"   # only if it didn't
onkyo.set_listening_mode receiver="Theater" mode="dolby-surround"
onkyo.set_volume         receiver="Theater" level=45         # capped server-side if above the cap
onkyo.set_power          receiver="Family Room" zone="zone2" state="off"

Two things make this safe to hand to a model: every server refuses to guess a device when there are several (so "the receiver" can't become the wrong room), and limits like the volume cap are enforced by the server, not by the prompt. If a Harmony activity already sets the receiver's input, let it: the Onkyo calls then only confirm and adjust.

Install

pip install git+https://github.com/SDNick484/mcp-server-onkyo

Python 3.11+. Dependencies: the official mcp SDK, pyjwt[crypto] and uvicorn (only used by the HTTP transport), typing_extensions (typed results on Python 3.11). Every compiled dependency ships musllinux wheels, so it installs on Alpine without a compiler.

The receiver needs Network Standby on (Setup → Hardware → Power Management) to be turned on over the network.

First contact

mcp-server-onkyo discover                 # who answers a broadcast
mcp-server-onkyo doctor --host 192.168.1.147
Receiver 192.168.1.147: TX-NR6050
   ok tcp       connected in 4 ms
   ok eiscp     main zone on; answered in 98 ms
   ok describe  TX-NR6050; zones: main, zone2; 8 network services
   ok zones     main on, zone2 standby

doctor checks each layer in turn (TCP, eISCP framing, self-description, each zone) and stops at the first failure with what it means and which HARDWARE_VALIDATION.md step covers it. It only sends queries. --json for a machine-readable report, --dump DIR to save each receiver's raw replies (redacted) for an issue or to compare with the simulator.

Configuration

Receivers go in config.json, in ONKYO_CONFIG_DIR (default ~/.config/mcp-server-onkyo):

{
  "receivers": [
    {"host": "192.168.1.147", "name": "Family Room"},
    {"host": "192.168.1.245", "name": "Theater"}
  ],
  "max_volume": {"main": 75, "zone2": 50}
}

name is optional (a receiver without one is known by its address). port and volume_steps can be set per receiver. max_volume is a number for every zone, or an object per zone. With no receivers configured, the server uses the one receiver that answers discovery, and refuses if several do. A typo never stops the server: each problem is logged at startup and shown by doctor, and only the bad entry is skipped.

Variable

Default

Meaning

ONKYO_CONFIG_DIR

~/.config/mcp-server-onkyo

Where config.json lives

ONKYO_HOSTS

(from config.json)

Comma-separated host, host:port or Name=host; replaces the file's list (keeping its names)

ONKYO_HOST

none

One receiver (the older form of ONKYO_HOSTS)

ONKYO_PORT

60128

Default eISCP port

ONKYO_MAX_VOLUME

75

Volume cap for every zone, on the 0-100 display scale. Enforced by the server

ONKYO_MAX_VOLUME_ZONE2, _ZONE3

as above

Per-zone caps; override the file

ONKYO_VOLUME_STEPS

2

Raw steps per display unit: 2 for 0.5-step models (TX-NR6050, TX-NR7100), 1 for older ones

ONKYO_TIMEOUT

5

Seconds to wait for a reply (power gets 3x; a TX-NR7100 takes ~10 s to confirm standby)

ONKYO_DISCOVERY_ADDR

255.255.255.255

Where the discovery broadcast goes

ONKYO_DRY_RUN

off

Read the receivers, send nothing that changes anything (serve --dry-run)

ONKYO_DEBUG

off

Log MCP and eISCP traffic to stderr (--debug)

ONKYO_LOG_UNREDACTED

off

Show LAN addresses and MACs in logs (--no-redact); secrets stay hidden

Use it with an MCP client

Local (stdio): the client starts the server.

claude mcp add onkyo -- mcp-server-onkyo
{ "mcpServers": { "onkyo": { "command": "mcp-server-onkyo" } } }

(the second for Claude Desktop's claude_desktop_config.json). Then: "turn on Zone 2 and play my Pearl Jam station".

HTTP and Cloudflare Access

To use one server from Claude Code, Claude Desktop and the mobile app, run it as a service and reach it through a Cloudflare Tunnel with Access in front:

CF_ACCESS_TEAM_DOMAIN=<team>.cloudflareaccess.com CF_ACCESS_AUD=<aud tag> \
  mcp-server-onkyo serve --http --public-host mcp.example.com      # 127.0.0.1:8711/onkyo/mcp

Flag

Variable

Default

--bind

MCP_HTTP_BIND

127.0.0.1

--port

MCP_HTTP_PORT

8711 (Shield 8712, Harmony 8713)

--path

MCP_HTTP_PATH

/onkyo/mcp

--public-host

MCP_PUBLIC_HOSTS

none: only loopback Host headers pass

CF_ACCESS_TEAM_DOMAIN, CF_ACCESS_AUD

none: no Access checks

MCP_ALLOWED_EMAILS

anyone Access lets in

With Access configured, every request needs a valid Cf-Access-Jwt-Assertion: signature (the team's published keys), audience, issuer, expiry, and the email allow-list if set. Anything else gets a plain 403. The server refuses to start on a non-loopback address without Access, unless --insecure-no-auth (trusted LAN testing only). Host and Origin are checked too (DNS-rebinding protection), including on --bind 0.0.0.0. GET /healthz answers without auth, for monitoring. Details are in src/onkyo_mcp/remote.py, which is identical in all four servers.

As a service on Alpine (Proxmox LXC)

sh deploy/alpine/install.sh            # as root; or: install.sh /path/to/checkout
vi /etc/mcp-server-onkyo/config.json   # the receivers
vi /etc/mcp-server-onkyo/env           # HTTP and Access settings
rc-update add mcp-server-onkyo default && rc-service mcp-server-onkyo start

Path

Owner, mode

Holds

/opt/mcp-server-onkyo/venv

root, 0755

The code

/etc/mcp-server-onkyo/

root:mcp-onkyo, 0750 (files 0640)

config.json, env

/var/lib/mcp-server-onkyo/

mcp-onkyo, 0750

State (none yet)

/var/log/mcp-server-onkyo/server.log

mcp-onkyo, 0750

Logs, redacted

/etc/init.d/mcp-server-onkyo

root, 0755

OpenRC script (supervise-daemon, restarts on exit)

It runs as the unprivileged mcp-onkyo user, which can read its config but not change it. /opt/mcp-server-onkyo/run.sh is exactly what the service runs. Run cloudflared in the same LXC and keep the default 127.0.0.1 bind. deploy/alpine/smoke-test.sh does the whole install in a python:3.12-alpine container against the simulator (CI runs it on every push).

A session against the simulator

mcp-server-onkyo simulate --write-config DIR starts a fake TX-NR6050 ("Family Room") and TX-NR7100 ("Theater") and writes a config.json naming them; call runs one tool the way the model would. This is real output:

$ export ONKYO_CONFIG_DIR=/tmp/sim
$ mcp-server-onkyo call set_power state=on
Error executing tool set_power: Several receivers are configured: Family Room (127.0.0.1:35405),
Theater (127.0.0.1:35339). Pass the one you mean as `receiver` (its name or address); call
get_status without one to see them all.

$ mcp-server-onkyo call set_power state=on receiver=family-room zone=zone2
{ "receiver": "Family Room", "zone": "zone2", "outcome": "done",
  "detail": "Zone 2: Power is now on", "sent": ["ZPW01"],
  "warnings": ["Some receivers need about 15 seconds to start up before they accept other commands."] }

$ mcp-server-onkyo call set_input source=net receiver=family-room zone=zone2
{ ..., "detail": "Zone 2: Input is now net", "sent": ["SLZ2B"], "warnings": [] }

$ mcp-server-onkyo call play_station station=pearl receiver=family-room
{ ..., "detail": "Playing Pearl Jam Radio on pandora", "sent": ["NSV040", "NLSI00003"] }

$ mcp-server-onkyo call set_volume level=90 receiver=family-room zone=zone2
{ ..., "detail": "Zone 2: Volume is now 75.0", "sent": ["ZVL96"],
  "warnings": ["Requested 90, capped at 75 (the owner's limit for this zone)."] }

$ mcp-server-onkyo call set_input source=net receiver=family-room
{ ..., "detail": "Input is now net", "sent": ["SLI2B"],
  "warnings": ["It now plays the same network audio as Zone 2: a receiver has one network
  player, so changing the service or station changes it in every zone on \"net\"."] }

$ mcp-server-onkyo call set_volume level=30 receiver=theater zone=zone2
Error executing tool set_volume: Zone 2 of Theater (127.0.0.1) has no volume control
(fixed-level output, or its outputs are used for other speakers).

$ mcp-server-onkyo call --dry-run set_volume level=40 receiver=theater
{ "receiver": "Theater", "zone": "main", "outcome": "dry_run",
  "detail": "DRY RUN, nothing sent: would set Main zone volume to 40.0", "sent": ["MVL50"] }

(Lines wrapped and some fields elided with ....)

Safety design

  • Never guess a receiver. Several configured and no receiver means an error that lists them. A bare word that isn't a configured name is an error too, never a DNS lookup.

  • Limits live in the server. Volume is capped per zone (default 75) whatever the model asks, and the reply says it was capped.

  • One exchange at a time per receiver. A tool call holds the receiver's lock and one TCP connection for its whole exchange, so parallel calls or two HTTP clients queue instead of mixing replies or opening many connections.

  • Only queries are retried. A query dropped mid-exchange is asked again on a fresh connection; a setter never is (it may have been applied).

  • Not stopping the music by accident. list_stations won't open a different service (which stops what's playing) unless interrupt=true, and the description tells the model to ask.

  • Dry run reads everything and sends nothing that changes anything; results say "outcome": "dry_run" and list what would have been sent.

  • Logs are redacted and on stderr (stdout is the stdio transport): LAN addresses and MACs are masked (x.x.x.147); Access JWTs, bearer tokens and keys are always removed.

Troubleshooting

When discovery finds nothing

Discovery broadcasts one UDP query (!xECNQSTN) to port 60128, and every receiver that hears it replies with its model and MAC. Broadcasts only reach the local subnet, and switches, access points and mesh systems often filter them. Then discover returns nothing even though the receivers are fine. You don't need discovery: configure the receivers by address.

  • mcp-server-onkyo discover --debug shows whether any reply arrives.

  • A unicast query, ONKYO_DISCOVERY_ADDR=192.168.1.147 mcp-server-onkyo discover, tells you if only the broadcast is blocked.

  • Try the subnet's broadcast address (ONKYO_DISCOVERY_ADDR=192.168.1.255) on a machine with several network adapters.

  • WSL2: NAT networking keeps broadcasts off the LAN. Set networkingMode=mirrored in %UserProfile%\.wslconfig and wsl --shutdown.

  • Finding the IP otherwise: the router's DHCP leases, the receiver's Setup → Network screen, or the ARP table (Onkyo MACs start 00:09:B0): ip neigh | grep -i 00:09:b0.

Other problems

  • Power-on does nothing: turn on Network Standby.

  • "didn't reply in time" right after power-on: some models ignore commands for ~15 s after power-on. Wait and retry.

  • Volume numbers don't match the front panel: set ONKYO_VOLUME_STEPS (or volume_steps for that receiver).

  • Anything else: doctor, then --debug (both redacted, safe to paste).

Development

No receiver needed. Each test runs its own fake receivers on free ports.

pip install -e '.[dev]'
pytest -q                     # ~250 tests, ~20 s
ruff check . && ruff format --check . && mypy

Command

What it's for

mcp-server-onkyo simulate [--write-config DIR]

Fake receivers on localhost, to point Claude or the Inspector at

mcp-server-onkyo call <tool> key=value ...

One tool call through the real MCP layer (call tools lists them)

mcp-server-onkyo serve --debug

Log every MCP message and eISCP packet to stderr

npx @modelcontextprotocol/inspector mcp-server-onkyo

Browse tools, resources and prompts by hand

python -m onkyo_mcp.sim.transcript LOG

Turn a call --debug log into a contract-test fixture

Tests

Cover

test_transport.py, test_protocol.py

eISCP framing, reply matching, discovery

test_tools.py, test_multi_receiver.py

The MCP contract: schemas, annotations, results, errors, never guessing

test_resources.py

Resources and prompts (prompts may only name tools that exist)

test_faults.py

Failure injection: silence, delays, drops mid-exchange, garbled packets, connection limits, push storms

test_contract.py

Byte-exact replays of transcripts in tests/fixtures/eiscp/

test_http_tools.py, test_remote.py

Streamable HTTP end to end, Access JWTs (valid, expired, wrong audience, missing) with locally generated keys

test_config.py, test_cli.py, test_logsafe.py

Config parsing, doctor/simulate/call, redaction

test_assumptions.py

Every assumption is cited by code, and listed here and in HARDWARE_VALIDATION.md

The fake (src/onkyo_mcp/sim/fake_receiver.py) has two profiles from the owner's receivers: the TX-NR6050 (Zone 2; in standby it changes inputs and answers N/A to volume) and the TX-NR7100 (Zone 2 driving height speakers, so no Zone 2 volume; silent in standby). Faults makes either misbehave on purpose. CI runs the checks on Python 3.11-3.14 and the Alpine smoke test.

CLAUDE.md holds the project's conventions and what was seen on hardware.

How it works

Each eISCP message is a 16-byte header (ISCP, header size, data size, version) and a command like !1MVL3C\r (main volume to raw 0x3C, 30.0 on a 0.5-step model). Receivers also push status nobody asked for, so replies are matched by their 3-letter prefix and, for setters, by the echoed value. eiscp.py speaks the protocol, receivers.py decides which receiver a call means and serializes access to it, server.py holds the tools: each @mcp.tool() function's docstring becomes the description the model reads and its type hints the JSON Schema.

Verification status

Hardware-verified means seen on the owner's TX-NR6050 and/or TX-NR7100 (what was seen is in each assumption's note in src/onkyo_mcp/assumptions.py). Simulator-only means the simulator implements it and nothing has confirmed it.

Assumption

Confidence

Status

O-FRAMING

high

hardware-verified

O-PUSHES

high

hardware-verified

O-STANDBY-SILENT

high

hardware-verified

O-MULTI-COMMAND

high

simulator-only

O-CONNECTIONS

low

simulator-only

O-DISCOVERY

high

hardware-verified

O-VOLUME-STEPS

high

hardware-verified

O-ZONE2-CODES

high

hardware-verified

O-ZONE3-CODES

medium

simulator-only

O-NRI-ZONES

high

hardware-verified

O-NRI-SERVICES

medium

simulator-only

O-NSV-CODES

high

hardware-verified

O-NET-SHARED

high

simulator-only

O-PLAY-STATE

high

hardware-verified

O-MENU-LISTS

high

hardware-verified

O-SOURCE-CODES

medium

simulator-only

O-LMD-CODES

medium

simulator-only

O-MULTI-COMMAND is the one the restructure depends on most: tool calls used to open one connection per command, and now share one. doctor exercises it first (step 2). test_assumptions.py fails if this table and assumptions.py disagree.

Roadmap

  • Zone 2 / Zone 3, inputs, listening modes, network services, stations, folders

  • Several receivers by name; typed results; resources and prompts

  • Streamable HTTP behind Cloudflare Access; OpenRC service on Alpine

  • Hardware validation of the above (HARDWARE_VALIDATION.md)

  • A persistent connection per receiver, with pushes as MCP resource updates (once the Claude apps support subscriptions)

  • Publish to PyPI and the MCP registry

Acknowledgements

Command tables come from miracle2k/onkyo-eiscp, with corrections from the receivers themselves (their NRI lists TIDAL as 1B and AirPlay as 44).

License

MIT

Available Tools

7 tools
discover_receiversA

Find Onkyo/Integra/Pioneer receivers on the local network. Returns each receiver's IP address, model, eISCP port and MAC address.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It discloses the return fields (IP, model, eISCP port, MAC), which is useful, but says nothing about scan duration/latency, network-access requirements, or that it is a safe read-only operation. Adequate but with real gaps for a zero-annotation tool.

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?

Two sentences, zero waste, and the core action (finding receivers on the local network) is front-loaded ahead of the return-value detail.

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

Completeness4/5

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

For a parameterless discovery tool with an output schema, the description covers purpose and return shape sufficiently; the return-value sentence is mildly redundant given the output schema. The main omission is behavioral context (scan time, permissions) that annotations would otherwise supply.

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 tool takes no parameters, so per the baseline this dimension starts at 4. There is no syntax or argument meaning the description could add, and it does not attempt to.

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?

States a specific verb (Find) and resource (Onkyo/Integra/Pioneer receivers on the local network), plus the identifying fields returned. It is clearly a discovery tool rather than a control tool, so it is distinguishable from the get_status/set_* siblings, but it never explicitly contrasts itself with them.

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

Usage Guidelines3/5

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

Usage is only implied: an agent can infer you discover receivers before configuring them, but the description names no conditions, prerequisites, or alternatives. No explicit when-to-use or when-not-to-use guidance is present.

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

get_statusA

Get a receiver's current power state, master volume (0-100), mute state, selected input and listening mode. If there are several receivers on the network, call discover_receivers first and pass the one you want.

ParametersJSON Schema
NameRequiredDescriptionDefault
receiverNoIP address of the receiver, as returned by discover_receivers. Omit to use the default receiver.

TDQS

A4.3/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 behavioral burden, and it does disclose the return payload (all five state fields) plus the multi-receiver prerequisite workflow. It is silent on permissions, error cases, or whether the call can fail for an unreachable receiver, which keeps it below 5.

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?

Two sentences, front-loaded with the returned data and followed by the one conditional prerequisite. No filler, no restating the tool name.

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?

There is no output schema, so the description must carry the return contract — and it enumerates every field returned, including the volume range. Combined with the receiver-selection prerequisite, an agent has everything needed to call this correctly.

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

Parameters3/5

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

Schema description coverage is 100% and the single 'receiver' param is fully documented in the schema, including the 'as returned by discover_receivers' and 'omit to use the default receiver' semantics. The description's 'pass the one you want' merely restates that, so baseline 3 is appropriate.

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?

States a specific verb ('Get') and enumerates exactly which state fields are returned (power state, master volume with its 0-100 range, mute state, selected input, listening mode). This cleanly separates it from the set_* mutators and from discover_receivers without needing to open any schema.

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?

Gives an explicit conditional prerequisite: 'If there are several receivers on the network, call discover_receivers first and pass the one you want.' That names the alternative tool and the condition that selects it. It lacks any explicit when-not-to-use guidance, so it falls short of a 5.

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

set_inputA

Select the main zone's input source. Names match the receiver's front-panel labels (e.g. "bd-dvd" for the BD/DVD input, "net" for network streaming). The receiver must be on.

ParametersJSON Schema
NameRequiredDescriptionDefault
sourceYes
receiverNoIP address of the receiver, as returned by discover_receivers. Omit to use the default receiver.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full behavioral burden. It usefully discloses a precondition ('receiver must be on') and the label convention for source names, but says nothing about failure behavior, whether the change is idempotent, or side effects on other settings — gaps that matter for a state-changing call.

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?

Three short sentences, front-loaded with the action, followed by the naming convention and the precondition. Every sentence adds information; there is no filler.

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

Completeness4/5

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

An output schema exists, so return values need not be described, and the core action plus precondition are covered. It omits any mention of multi-zone behavior or the default-receiver fallback, though the schema itself documents the latter.

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?

Schema coverage is only 50% (the receiver parameter is documented in the schema, source is not). The description compensates for the undocumented parameter by explaining that values mirror front-panel labels and giving concrete examples ('bd-dvd', 'net'), which adds meaning the bare enum cannot convey.

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 gives a specific verb and resource ('Select the main zone's input source'), which is inherently distinct from sibling operations like set_volume, set_mute, or set_power. It does not explicitly name or contrast any sibling, so it stops short of the top tier, but an agent can identify the operation without opening the schema.

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?

Usage context is clear (switch the main zone's input) and a concrete precondition is stated: 'The receiver must be on.' There is no explicit when-not guidance or reference to alternatives, but for a simple discrete setter the context is sufficient.

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

set_listening_modeA

Set the main zone's listening mode (surround processing). "direct" and "pure-audio" play the source unprocessed; "dolby-surround" and "dts-neural-x" upmix to all speakers and play Dolby Atmos / DTS:X content natively. The receiver must be on, and may reject modes that don't suit the current input signal.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeYes
receiverNoIP address of the receiver, as returned by discover_receivers. Omit to use the default receiver.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior3/5

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

No annotations exist, so the description carries the full burden. It usefully discloses a precondition (receiver must be on) and a failure mode (may reject modes unsuited to the current input signal), which is more than most. However, it says nothing about persistence, whether the setting survives power cycles, or permission 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?

Three tight sentences, front-loaded with the core action, then mode semantics, then the precondition/failure caveat. Every clause carries information and nothing is padded.

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

Completeness4/5

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

An output schema exists so return values need no explanation, and the precondition plus rejection behavior covers the main operational risk. The remaining gap is the undocumented half of the mode enum, which is material for a tool whose sole required argument is that enum.

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

Parameters3/5

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

Schema coverage is only 50%: the 'receiver' param is documented in-schema but the 12-value 'mode' enum has no descriptions. The description compensates for 4 of those 12 values (direct, pure-audio, dolby-surround, dts-neural-x) but leaves stereo, all-ch-stereo, full-mono, theater-dimensional and all four game modes unexplained, so an agent still cannot distinguish those choices.

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?

States a specific verb and resource with scope ('Set the main zone's listening mode (surround processing)'). No sibling competes for this function (set_power/set_volume/set_input/set_mute are all different domains), so an agent can route unambiguously.

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

Usage Guidelines3/5

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

The description gives value-selection guidance ('direct' and 'pure-audio' play unprocessed; 'dolby-surround'/'dts-neural-x' upmix) and a precondition (receiver must be on), but never says when this tool is the right call versus doing nothing or using set_input first. Usage is implied rather than stated.

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

set_muteC

Mute or unmute the main zone.

ParametersJSON Schema
NameRequiredDescriptionDefault
mutedYes
receiverNoIP address of the receiver, as returned by discover_receivers. Omit to use the default receiver.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.9/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full behavioral burden. It says nothing about prerequisite state (connected/selected receiver), whether the change persists, or any permission/error behavior; only the boolean toggle is implied.

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?

A single short sentence, front-loaded with the action, with no filler. It is efficient, though its brevity leaves no room for the scoping detail the tool arguably needs.

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

Completeness2/5

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

An output schema exists so return values need not be explained, but for a mutation tool with zero annotations the description should cover prerequisites and the receiver/default-receiver behavior, which it omits entirely.

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

Parameters3/5

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

Schema coverage is 50%: 'receiver' is documented in the schema (IP from discover_receivers, omit for default), while 'muted' has only a title. The description's 'mute or unmute' loosely maps to the boolean, but adds no format or edge-case 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?

States a specific verb (mute/unmute) and resource (the main zone), which is enough to distinguish it from siblings like set_volume, set_power, and set_input. It stops short of naming the receiver/zone scope that the 'receiver' parameter implies, so it doesn't fully resolve how this tool relates to multi-receiver setups.

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

Usage Guidelines2/5

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

There is no guidance on when to use this versus alternatives, no mention of whether a receiver must first be picked up via discover_receivers, and no statement of what happens when 'receiver' is omitted or that only the main zone is affected.

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

set_powerB

Turn the main zone on, or put it into standby.

ParametersJSON Schema
NameRequiredDescriptionDefault
onYes
receiverNoIP address of the receiver, as returned by discover_receivers. Omit to use the default receiver.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It usefully clarifies that 'off' means standby rather than a hard power-off, which is genuine behavioral context beyond the schema. However, it says nothing about side effects on other zones, permission requirements, or error behavior for an unreachable receiver.

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?

A single front-loaded sentence with no filler, stating both states of the toggle. Efficient, though it is arguably terse given the missing behavioral detail elsewhere.

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

Completeness3/5

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

An output schema exists, so return values need not be described, and the schema covers the receiver parameter. For a mutation tool with zero annotations, the description covers the state semantics but omits side effects and error/precondition behavior, leaving it only minimally sufficient.

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

Parameters3/5

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

Schema coverage is 50%: the 'receiver' parameter is documented in the schema (including the discover_receivers reference and default behavior), but the required 'on' parameter has no schema description. The description compensates partially by establishing that true = on and false = standby, so the required flag's meaning is recoverable. Baseline 3 fits.

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 names a specific verb (turn on / put into standby) and resource scope (the main zone), making the tool's job clear. It maps the boolean 'on' to the two states, so an agent understands the effect. It stops short of differentiating itself from siblings like get_status or set_volume, but the power semantics are unambiguous.

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

Usage Guidelines3/5

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

Usage is implied by the name and description (use this to change power state of the main zone), but there is no explicit when-to-use guidance, no exclusions, and no mention of alternatives such as get_status for reading power state. Adequate but leaves routing to inference.

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

set_volumeA

Set master volume on the receiver's 0-100 display scale (0.5 steps on newer models). Values above the configured safety cap are clamped.

ParametersJSON Schema
NameRequiredDescriptionDefault
levelYes
receiverNoIP address of the receiver, as returned by discover_receivers. Omit to use the default receiver.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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

There are no annotations, so the description carries the full behavioral burden. It does disclose two useful traits beyond the schema: values above the configured safety cap are clamped, and newer models accept 0.5 steps. However, it omits error behavior, permission/auth requirements, and whether the clamping is silent or reported.

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?

Two tight sentences with zero filler. The core action and scale are front-loaded, with the clamping caveat following immediately after.

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

Completeness4/5

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

An output schema exists, so return values need not be explained, and the description covers the key range and clamping behavior. It is nearly complete for a simple setter, missing only auth/permission notes and out-of-range error semantics.

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?

Schema description coverage is only 50%: the receiver parameter is documented in the schema, but the required level parameter has no schema description. The description compensates by defining the level's 0-100 scale and the 0.5-step granularity, adding real meaning beyond the bare number type.

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?

States a specific verb ("Set") and resource ("master volume") and adds scale semantics ("receiver's 0-100 display scale"). This clearly separates it from set_mute, set_power, and set_input, but it never names those siblings explicitly, so it sits just below the top tier.

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

Usage Guidelines2/5

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

The description explains what the tool does but gives no when-to-use context and never points to alternatives such as set_mute for temporary silencing. An agent must infer the routing between sibling setters on its own.

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.

  1. 7 tool updatesv0.1.0
    • First observeddiscover_receivers
    • First observedget_status
    • First observedset_input
    • First observedset_listening_mode
    • First observedset_mute
    • First observedset_power
    • First observedset_volume

TDQS

A3.7/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a clearly distinct action or receiver property; discover_receivers and get_status are separated by network discovery vs single-device state read. The set_* tools each control a different aspect with no overlapping purposes.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun pattern (discover_receivers, get_status, set_power, etc.). The mix of discover/get/set verbs is semantically appropriate and predictable.

Tool Count5/5

Seven tools is well-scoped for controlling an Onkyo receiver, covering discovery, status, and the main control operations without redundancy or filler.

Completeness4/5

The surface covers the core main-zone lifecycle: discovery, status, power, volume, mute, input, and listening mode. Secondary-zone control, tone adjustments, or sleep timers are absent, but these are minor gaps for the stated main-zone purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers