Skip to main content
Glama

RomM MCP

A token-efficient MCP server for a self-hosted RomM library. Runs locally over stdio or as an authenticated Streamable HTTP service. Covers the complete OpenAPI HTTP surface in RomM 5.3.1 and 5.4.0, plus the hidden 5.4 WebDAV routes and 13 callable Socket.IO events, with explicit operator switches for writes, files, administration, authentication, tasks, and realtime connections. All switches default to false.

Tools and discovery

The server advertises 10 tools by default, or 14 with writes enabled. HTTP operations are discovered on demand from the configured RomM OpenAPI schema, so hundreds of endpoint schemas do not inflate every MCP tool listing.

Tool

Purpose

list_platforms

Find platform IDs and library counts

search_roms

Search title, platform, collection, and RetroAchievements availability

get_rom

Bounded synopsis; opt into metadata, files, or personal progress

list_collections

Find regular collections by name

get_collection

Collection details and paginated contents

create_collection

Create a private collection, verified by readback; requires writes

update_collection_roms

Atomically add/remove membership, verified by readback; requires writes

update_rom_progress

Change supplied progress fields, verified by readback; requires writes

romm_api_list

Search all HTTP operations, scopes, required switches, and enabled status

romm_api_describe

Inspect one operation and resolve component schemas on demand

romm_api_read

Invoke an enabled HTTP read by its discovered operation ID

romm_api_write

Invoke an enabled HTTP operation that changes state; requires writes

romm_artifact

Stage uploads or retrieve downloads using bounded temporary handles

romm_socket

Discover, open, send, listen, and close main/netplay/device Socket.IO sessions

Disabled operations remain discoverable. Start with romm_api_list, then romm_api_describe, then call the appropriate read/write tool using the returned operation_id. Requests support path, query (including repeated values), declared headers, JSON body, form, multipart files, raw_artifact_id, or DAV xml_body. Known gaps in RomM's upload schemas have explicit corrections in operation descriptions. Callers cannot supply arbitrary destinations, URL paths, or upstream authorization headers.

For example, romm_api_read can retrieve a ROM through the generic interface:

{
  "operation_id": "get_rom_simple_api_roms__id__simple_get",
  "request": {"path": {"id": 123}, "response_pointer": "/name"}
}

All clients share the configured RomM identity, artifacts, and sessions. This is a single-user gateway. API coverage does not grant missing upstream permissions or replace external provider, emulator, browser-login, or streaming prerequisites.

Related MCP server: crewmeister-api

Environment and authorization

Variable

Default

Effect

ROMM_URL

Required

RomM base URL without /api; use its nginx front door for file downloads

ROMM_TOKEN

Required

Upstream RomM bearer/client token

ROMM_ALLOW_WRITES

false

Master switch for state changes; registers four write tools

ROMM_ALLOW_DESTRUCTIVE

false

Deletions, replacement-capable uploads, regeneration, and destructive task paths

ROMM_ALLOW_ADMIN

false

Administrative configuration, users, permissions, logs, and management endpoints

ROMM_ALLOW_AUTH

false

Authentication/token workflows and nondefault HTTP authentication modes

ROMM_ALLOW_FILES

false

Binary transfers and file-affecting operations; permits artifact read/delete

ROMM_ALLOW_TASKS

false

Task endpoints, exports, streaming mutations, refresh/redownload actions, and socket sends

ROMM_ALLOW_REALTIME

false

Main/netplay/device Socket.IO connections

ROMM_USERNAME, ROMM_PASSWORD

Empty

Optional configured credentials for HTTP auth_mode=basic

ROMM_SESSION_COOKIE

Empty

Value only of the romm_session browser cookie, required for main Socket.IO and authenticated 5.4 netplay

ROMM_DEVICE_TOKEN

Empty

Separate device-bound client token for /devices Socket.IO and HTTP auth_mode=device

ROMM_TRANSFER_DIRECTORY

System temporary directory

Existing parent for private temporary artifact storage

ROMM_MAX_TRANSFER_BYTES

67108864

Aggregate artifact storage cap in bytes, across all clients

Switches are additive, checked on every invocation, and enabled by the value true (case-insensitive). For example, a replacement-capable upload needs writes, files, and destructive access; administrative mutation also needs admin access. The operation catalog reports the required switches. Token scopes and the upstream user's role remain separate requirements; a switch cannot override a RomM denial.

Read-only mode means upstream mutations are blocked, not that every GET is safe. RomM's OpenID GETs, memory-card version listing, and task-status GET change state. Reading save content also changes sync state when session_id is supplied, or when device_id is supplied without optimistic=false. These calls require romm_api_write and the applicable switches. Some file, admin, and auth reads need their category switch even without writes enabled. Artifact creation/append requires both files and writes; deleting a local artifact requires only files.

Create a scoped RomM client token as the user whose library state you want to manage. The compact read tools need me.read, roms.read, platforms.read, collections.read, and roms.user.read; compact writes additionally need collections.write and roms.user.write. The bootstrap identity needs me.write to create a client token; notification writes in 5.4 also need me.write. For other HTTP endpoints, use the scopes returned by discovery and grant only the capabilities you enable. Service accounts have their own collections and progress.

HTTP defaults to bearer authentication. With auth enabled, a request may choose auth_mode=basic, session, device, or none. Basic mode uses configured credentials. Device mode uses only ROMM_DEVICE_TOKEN, cannot mix with an auth session, and is required for install claim/report when the main token is not device-bound. Use auth_session="new" to start an isolated cookie jar and reuse the returned opaque handle for a multi-step login flow; session mode requires such a handle. At most eight HTTP auth sessions are retained, expiring after ten minutes of inactivity. ROMM_SESSION_COOKIE is for main/netplay Socket.IO, not an implicit HTTP cookie. Credentials belong in a secret manager or protected environment, never committed client configuration. Treat auth endpoint outputs as sensitive.

Bounded responses and files

Compact searches default to 20 results (maximum 100). Follow next_offset until null; get_collection uses roms.next_offset. Platform and collection filtering is local because those upstream endpoints return full arrays. Search suppresses RomM's full-library character, filter, and ROM-ID indexes. Compact synopses cap at 1,500 characters and optional file lists at 50 entries; truncated_fields reports those limits. Summary names cap at 200 characters, regions/languages at ten values.

Generic responses support JSON Pointer selection with response_pointer and local offset/limit pagination. Follow next_offset and inspect truncation markers; select a nested field when its value was omitted. Local response pagination does not advance the upstream query: use RomM's declared query pagination to retrieve additional server-side pages. Non-download HTTP responses and OpenAPI loading are bounded at 16 MiB. Only the OpenAPI schema is cached for the process.

For uploads, create an artifact with romm_artifact, then append strict base64 chunks of at most 32,768 decoded bytes, supplying the exact current byte offset. Stale offsets reject retries. Pass its handle in a multipart files entry (field, artifact_id, filename, optional content_type) or the ROM chunk endpoint's raw_artifact_id. For downloads, set request.download=true, then read the returned artifact in chunks; reads default to 4,096 bytes, maximum 32,768.

Artifacts use opaque handles, never caller-chosen filesystem paths. At most 16 artifacts share the configured byte cap (default 64 MiB). They expire 3,600 seconds after creation; this TTL has no environment setting. Expiry is checked on operations, and shutdown cleans storage. Open uploads keep their quota and artifact slot until their last read handle closes, and cannot be appended or deleted while in use. Failed writes retain reserved capacity until cleanup succeeds. Delete artifacts when finished; failed streamed downloads are cleaned up. Size the container's temporary filesystem to accommodate the configured transfer cap.

Realtime API

romm_socket(action="catalog") describes all 13 callable main/netplay events and captured response events without opening a connection. Use open, then send and listen with the same session handle, then close. Opening requires realtime; sending additionally requires writes and tasks. Starting a scan also requires files and destructive access. Capturing logs:entry needs admin.

Main events cover scan start/stop and activity start/heartbeat/stop. Netplay events cover room open/join/leave, WebRTC signaling/error, data messages, snapshots, and inputs. Main Socket.IO and authenticated 5.4 netplay require ROMM_SESSION_COOKIE. Hosting needs a valid ROM ID in extra.game_id; passwords belong in top-level password. Legacy extra.room_password is rejected to prevent silently creating an unprotected room. Password hosting targets RomM 5.4; do not use it on 5.3. Guest password joins can omit the cookie. Main sessions also capture notification, activity refresh, and install updates. service="devices" listens on /devices using only ROMM_DEVICE_TOKEN, without the general bearer or session cookie; it captures install queue/cancellation events and accepts no send events. Binary event values use {"$binary_base64":"..."} within the payload limit.

There are at most four sessions, each lasting 300 seconds, with bounded queues of 20 events, 16 KiB JSON payload limits, and listen waits of at most ten seconds. Truncation is explicit. Disconnect clears activity and leaves netplay rooms; background scans continue. A successful send confirms transport acceptance only; inspect received events and HTTP state to verify its effects.

RomM 5.4 HTTP behavior

New REST endpoints are discovered from the running server; restart MCP after an upstream upgrade to refresh its cached schema. Device install mutations require tasks and files. Scans require tasks, files, and destructive access. Save/state file renames require files. Audit history and notification-channel mutations require admin: an administrator-owned token can otherwise reach broader data or private-network notification destinations despite narrow declared scopes. Sending a notification to explicit recipients also requires admin.

A ROM download GET with query.format can start a background conversion and must use romm_api_write with writes, tasks, and files enabled. HTTP 202 returns a pending result and retry-after, without a download artifact or automatic retry. Check status and retry deliberately; a subsequent completed download yields an artifact.

The synthetic romm_webdav_* operations expose /api/sync/retroarch/ on 5.4+. Supply a relative path.file_path (empty for root), with literal slash-separated segments. Encoded traversal, URL destinations, and caller authorization headers are rejected. PUT uses raw_artifact_id; PROPFIND and LOCK may use a bounded xml_body. XML responses use normal bounded text output or download artifacts. All DAV operations require files; GET/HEAD also require writes because upstream can update device/asset records. PUT, DELETE and MOVE require destructive access. RomM 5.4 implements MOVE as deletion and ignores Destination: it is not a rename. ROM-library GET redirects are returned without following them; use the regular ROM content endpoint to retrieve those bytes. Upstream user roles and scopes still apply.

Run locally

Install Python 3.12+ and uv, then:

git clone https://github.com/sharkusmanch/romm-mcp.git
cd romm-mcp
uv sync --locked
export ROMM_URL=https://romm.example.com
export ROMM_TOKEN=YOUR_ROMM_CLIENT_TOKEN
uv run romm-mcp --transport stdio

To enable compact mutations, add ROMM_ALLOW_WRITES=true. Enable additional category switches only for the operations you intend to use.

HTTP / containers

export MCP_AUTH_TOKEN=YOUR_SEPARATE_RANDOM_TOKEN_AT_LEAST_32_CHARACTERS
export MCP_ALLOWED_HOSTS=localhost:8080,127.0.0.1:8080
uv run romm-mcp --transport http --host 127.0.0.1 --port 8080

# Published multiarchitecture image (HTTP on port 8080 by default):
docker run --rm --read-only --tmpfs /tmp:rw,nosuid,nodev,size=80m \
  -p 127.0.0.1:8080:8080 \
  -e ROMM_URL -e ROMM_TOKEN -e MCP_AUTH_TOKEN -e MCP_ALLOWED_HOSTS \
  ghcr.io/sharkusmanch/romm-mcp:v0.3.0

# Container as a local stdio server:
docker run --rm -i --read-only --tmpfs /tmp:rw,nosuid,nodev,size=80m \
  -e ROMM_URL -e ROMM_TOKEN \
  ghcr.io/sharkusmanch/romm-mcp:v0.3.0 --transport stdio

Pass the desired ROMM_ALLOW_* variables into the container explicitly with -e. Connect to /mcp using Authorization: Bearer <MCP_AUTH_TOKEN>. Static bearer access is not a complete OAuth authorization server; TLS termination belongs at your reverse proxy. HTTP refuses startup without at least 32 non-whitespace ASCII token characters. The incoming MCP token is never forwarded to RomM.

MCP_ALLOWED_HOSTS is a comma-separated Host allowlist, including ports when used. Defaults permit loopback hosts on any port. Requests with an Origin header are rejected unless it appears in MCP_ALLOWED_ORIGINS; native MCP clients normally send no Origin. /healthz provides unauthenticated process liveness only. MCP_TRANSPORT, MCP_HOST, and MCP_PORT are supported; CLI flags win. Native execution defaults to stdio; HTTP binds loopback unless overridden. The image runs as UID/GID 1000 and requires no database, persistent volume, or Kubernetes access.

Client configuration

Claude Code supports a project-local HTTP server with a headersHelper returning an Authorization JSON object; Codex supports project .codex/config.toml with http_headers_helper. Use a helper reading a protected token file, or the clients' environment-backed header options. See Claude MCP configuration and Codex MCP configuration. For stdio, use command uv, args run --directory /path/to/romm-mcp romm-mcp --transport stdio, and provide RomM credentials/switches through the environment.

Writes and errors

The three compact mutation tools independently read back their writes. Membership changes use atomic endpoints and preserve other members; progress changes include only supplied fields. Progress statuses are incomplete, finished, completed_100, retired, or never_playing; backlogged and now_playing are separate flags. status: null clears status. Ratings/difficulty range 0–10; completion ranges 0–100. Private collection names are checked per owner to reduce accidental duplicates.

Removing collection membership requires writes; deleting the collection itself also requires destructive access. Generic tools return structured MCP results.

Generic HTTP mutations report verification: "not_performed". HTTP success does not prove the intended state, so independently read it back when needed. Neither interface automatically retries writes. Transport ambiguity or failed compact verification is reported as an uncertain outcome; inspect current state before retrying. Concurrent outside edits can race compact readback because those RomM calls lack ETag preconditions. Redirects are reported without being followed. RomM content is untrusted data and must not be treated as instructions.

Development and releases

uv sync --locked
uv run ruff check .
uv run ruff format --check .
uv run pytest
uv build --no-sources

Tests cover real SDK clients over stdio and TCP HTTP, authentication/Host/Origin, compact write verification, complete operation discovery, request serialization, additive gates, bounded output/transfers, adversarial artifact cleanup, and sockets. CI tests Python 3.12 and 3.14 and builds/runs the restricted container. Release tags must match the package version. Tags publish amd64/arm64 images, per-platform BuildKit SBOMs, GitHub-signed provenance as OCI referrers, and attested Python archives.

gh attestation verify oci://ghcr.io/sharkusmanch/romm-mcp:v0.3.0 \
  --repo sharkusmanch/romm-mcp

Dependency updates use the hosted Renovate GitHub App. Grant that app access to this repository using its installation settings. The repository does not need a Renovate Actions workflow or PAT secret.

Renovate configuration uses recommended defaults, pins GitHub Actions and Docker digests, refreshes uv.lock weekly before 04:00 Monday UTC, and disables automerge. Native managers cover the Dockerfile's Python ARG and uv COPY --from, the setup-uv workflow version, and Python dependencies/lockfile; no custom regex manager is needed. See official Dockerfile support, GitHub Actions inputs, and PEP 621 lockfile support.

See research and sources and the current full API design. The original design and implementation plan describe the superseded v0.1.0 scope. Licensed under MIT.

Available Tools

10 tools
get_collectionA
Read-onlyIdempotent

Get a regular collection and one page of its ROMs. Follow roms.next_offset.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo
collection_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
romsYes
collectionYes

TDQS

A3.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, non-destructive and closed-world, so the safety profile is covered. The description adds value beyond that by disclosing that the response is paginated ('one page of its ROMs') and how to advance ('Follow roms.next_offset'), which the annotations do not convey.

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 short sentences with zero waste, pagination guidance front-loaded second. Every clause earns its place 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?

With a rich annotation set and an existing output schema, the description appropriately defers return-shape details and instead explains pagination mechanics via roms.next_offset. It is nearly complete for this tool, with only the parameter semantics gap preventing a 5.

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

Parameters2/5

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

Schema coverage is 0%, so the description must compensate, but it only alludes to pagination via 'one page' and 'next_offset'. It never mentions the limit, offset, or collection_id parameters, leaving their semantics entirely to 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+resource pair ('Get a regular collection and one page of its ROMs'), which is clear and distinguishes the tool from the list_collections sibling by implying single-item retrieval. It also scopes the return to 'one page of its ROMs', but does not explicitly name the sibling it contrasts with.

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 phrase 'Follow roms.next_offset' gives concrete pagination guidance for iterating, which is a real usage hint. However, there is no explicit statement of when to use this versus list_collections or search_roms, leaving usage only partially implied.

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

get_romA
Read-onlyIdempotent

Get one ROM and synopsis. Opt into metadata, files (max 50), or progress.

ParametersJSON Schema
NameRequiredDescriptionDefault
rom_idYes
sectionsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
nameYes
filesNo
ra_idNo
regionsNo
summaryNo
metadataNo
platformNo
progressNo
languagesNo
platform_idNo
truncated_fieldsNo

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds one genuine behavioral constraint beyond that — the 50-file cap — but says nothing about truncation, permissions, or error behavior.

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 short sentences, zero filler, and the core action ('Get one ROM') is front-loaded before the optional-section detail. Every clause earns its place.

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 rich annotations cover safety. For a simple two-parameter read tool the definition is nearly complete, missing only error/empty-result behavior and explicit sibling routing.

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 0%, so the description must carry the param burden. It explains that sections are opt-in and adds the 'max 50' constraint on files (not represented in the schema's maxItems=3), but rom_id is left entirely unexplained and the enum values themselves merely restate 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 and resource ('Get one ROM and synopsis'), making the single-item retrieval scope clear against siblings like search_roms or list_collections. It does not explicitly name the sibling to avoid, so it stops just 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.

Usage Guidelines3/5

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

'Opt into metadata, files (max 50), or progress' gives useful guidance on when to include optional sections, but there is no statement of when to use this tool versus search_roms, nor any prerequisite or exclusion. Usage is implied rather than prescribed.

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

list_collectionsB
Read-onlyIdempotent

List regular collections and counts; filter by name. Follow next_offset.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryNo
offsetNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
limitYes
totalYes
offsetYes
next_offsetYes

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare read-only, idempotent, non-destructive, so the safety profile is covered. The description adds one genuinely useful behavior ('Follow next_offset') that is not in the annotations or schema, but says nothing about what the counts contain or rate-limit behavior.

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 tight sentence with no filler and the operation is front-loaded. The compressed phrasing ('and counts') is slightly elliptical but stays within an acceptable length.

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 shape need not be described, and annotations cover safety. Still, 'regular' is unexplained, the name-filter parameter is not tied to the query field, and pagination semantics are reduced to two words – enough to be called but with clear gaps.

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 0%, so the description must compensate, but it only gestures at 'filter by name' and 'next_offset' without mapping either to the actual parameter names (query, offset) or clarifying limit/default/max. It is marginally better than nothing, which is the baseline 3.

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+resource ('List regular collections') and adds scope ('and counts'), which distinguishes it from the sibling get_collection. However, 'regular' is undefined jargon and it does not distinguish itself from list_platforms or the paginated siblings; a small gap keeps it from a 5.

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?

No when-to-use vs alternatives guidance at all; the agent must guess whether get_collection or list_collections is appropriate. 'filter by name' is the only conditional, and it is not framed as such.

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

list_platformsB
Read-onlyIdempotent

List library platforms and ROM counts; optional name filter. Follow next_offset.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryNo
offsetNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
limitYes
totalYes
offsetYes
next_offsetYes

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds paging behavior ("Follow next_offset"), which is genuinely useful context, but says nothing about result size, rate limits, or what a page contains.

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?

Two short, front-loaded clauses with no filler; the core capability comes first and the operational note second. The only cost is that "Follow next_offset" is cryptic against an input parameter actually named offset.

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-value explanation is unnecessary, and annotations cover safety. Still, with 0% schema description coverage the agent is left guessing about limit semantics and the offset/next_offset relationship for a paginated list tool.

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 0%, so the description must carry the parameter burden. It explains the query filter and points at offset-based paging, but never clarifies limit or the offset parameter's range/default, and it names "next_offset" (an output field) rather than the input parameter "offset".

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 uses a specific verb+resource ("List library platforms") and adds the distinguishing payload ("ROM counts"), which separates it from search_roms and list_collections. It stops short of explicitly naming a sibling or stating scope boundaries, so it is clear but not fully differentiated.

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?

"optional name filter" implies when to pass a query and "Follow next_offset" implies iterative paging, so usage is inferable. However, there is no explicit when-to-use versus search_roms (the obvious alternative for filtered lookups), and no stated prerequisites.

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

romm_api_describeC
Read-onlyIdempotent

Fetch one operation's schema; resolve #/components/schemas/... on demand.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo
schema_refNo
operation_idYes
response_pointerNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description usefully adds that schema references can be dereferenced on demand, but says nothing about pagination behavior for limit/offset or how response_pointer alters output.

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 compact sentence with the core action front-loaded and no filler. The semicolon-clause about #/components/schemas/... is slightly cryptic but does carry information.

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?

Five parameters with 0% schema coverage, including pagination controls, and the description addresses only the schema-fetch/ref-resolution aspect. An output schema exists so return values need no explanation, but the parameter and pagination story is materially incomplete for a tool of this complexity.

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

Parameters2/5

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

Schema description coverage is 0%, so the schema documents parameter names only. The description hints at schema_ref/pointer resolution behavior but leaves limit, offset, and response_pointer entirely unexplained, so it only partially compensates for the coverage gap.

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 and resource: 'Fetch one operation's schema', and adds the second capability of resolving component schema references. An agent can distinguish this introspection tool from data fetchers like get_rom, though siblings such as romm_api_list and romm_api_read are never named for contrast.

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?

'resolve ... on demand' faintly implies when ref resolution is needed, but there is no explicit when-to-use, no when-not, and no routing among the api_* siblings (romm_api_list, romm_api_read, romm_artifact). The agent must infer the boundaries.

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

romm_api_listC
Read-onlyIdempotent

Discover every HTTP operation, required scopes and switches. Follow next_offset.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNo
limitNo
queryNo
methodNo
offsetNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.8/5.0
Behavior3/5

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

Annotations already grant readOnlyHint, idempotentHint, destructiveHint=false and closed-world, so the safety profile is covered. The description contributes one extra behavioral fact — that results are cursor-paginated via next_offset — which is real added value beyond the annotations, but it discloses nothing about result size, rate limits or what 'switches' contains.

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?

Eleven words in two sentences, with the discovery purpose front-loaded before the pagination note. Nothing is padded, though the terseness shades into cryptic rather than efficient at points.

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-value shape need not be spelled out, and annotations cover safety. The gap is input-side: five undocumented filter/pagination parameters with 0% schema coverage and no compensating prose leaves an agent unable to use the catalog's filters correctly.

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

Parameters2/5

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

Schema description coverage is 0% across five parameters (tag, limit, query, method, offset), so the description carries the full burden and adds nothing. It never mentions filtering by tag, query, method or paging via limit/offset, leaving the agent to guess the filter semantics from bare property names.

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

Purpose3/5

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

The description names the resource (HTTP operations) and what it surfaces (required scopes, switches), which is more specific than a bare name restatement. However, 'switches' is undefined jargon, and it draws no line against close siblings romm_api_describe and romm_api_read, so an agent cannot tell from the text alone which of the trio to pick.

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?

'Follow next_offset' is a pagination instruction, not usage guidance. There is no statement of when to call this versus romm_api_describe or romm_api_read, and no prerequisites or exclusions. The agent is left to infer the discovery-vs-inspection split from the name.

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

romm_api_readC
Read-onlyIdempotent

Invoke a read operation by discovered ID. Select/paginate output with request fields.

ParametersJSON Schema
NameRequiredDescriptionDefault
requestNo
operation_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.4/5.0
Behavior2/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered. The description adds only 'Select/paginate output with request fields,' which hints at pagination but says nothing about how request fields (auth_mode, download, response_pointer, etc.) alter behavior — the biggest behavioral unknowns for this tool.

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

Conciseness3/5

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

Two short sentences with no filler, and the core action is front-loaded. But the brevity is under-specification rather than genuine conciseness given the tool's complexity, and the second sentence is vague about which request fields do what.

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. Still, for a dynamic dispatcher with a large nested request object at 0% schema coverage, the description leaves the agent unable to construct a valid request or know how to discover the operation_id.

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

Parameters2/5

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

Schema description coverage is 0%: neither operation_id nor any of the many APIRequest properties are documented beyond bare titles. The description mentions a 'discovered ID' and 'request fields' to select/paginate, but does not explain the meaning of limit/offset, auth_mode, download, or response_pointer, so it fails to compensate for the coverage gap.

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

Purpose3/5

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

The description names a specific verb+resource ('invoke a read operation') and identifies the key input ('discovered ID'), so the agent knows this is a read dispatcher. However, it does not distinguish this tool from its siblings, especially romm_api_list or romm_api_describe, which likely share the same dynamic-dispatch pattern.

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 phrase 'by discovered ID' faintly implies the operation_id must first be obtained (presumably via romm_api_describe), but no explicit when-to-use, when-not-to-use, or alternative is stated. An agent has no guidance on choosing this over romm_api_list or the dedicated get_rom/get_collection tools.

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

romm_artifactC
Destructive

Move file bytes through opaque temporary handles. Requires FILES; create/append also WRITES.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
actionYes
offsetNo
artifact_idNo
data_base64No

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.7/5.0
Behavior3/5

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

Annotations already declare destructiveHint=true, readOnlyHint=false, and idempotentHint=false, so the safety profile is covered. The description adds a real detail the annotations do not: which specific actions (create/append) mutate versus which do not, plus a FILES permission requirement. It stops short of describing handle lifetime, offset/limit behavior, or error modes, so the added value is moderate.

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?

Two terse fragments with no filler, and the core operation leads before the permission caveat. The capitalized FILES/WRITES emphasizes the constraints effectively, though "opaque" costs clarity for brevity.

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?

With five parameters at 0% schema coverage and a destructive mutation surface, the description should explain the create-then-handle workflow, offset/limit paging, and data format. An output schema exists so return values need not be described, but the parameter and workflow gaps leave an agent unable to invoke this correctly from the description alone.

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

Parameters2/5

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

Schema description coverage is 0% across five parameters, so the description carries the full burden and largely fails it. Only artifact_id is faintly implied ("opaque temporary handles"); limit, offset, and data_base64 receive no explanation of units, base64 encoding, or paging semantics.

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

Purpose3/5

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

The description states a rough verb+resource ("Move file bytes") but the operative phrase "through opaque temporary handles" is jargon that obscures what a caller actually does. It never references the create/append/read/delete actions in the enum, and it does nothing to separate this tool from siblings like romm_api_read or romm_api_list. Purpose is inferable but vague.

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?

"Requires FILES; create/append also WRITES" gestures at a precondition but never says when to choose this tool over the byte-oriented siblings (romm_api_read, romm_api_list, romm_socket). There is no when-to-use, no when-not-to-use, and no named alternative.

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

romm_socketC
Destructive

Discover/use bounded realtime sessions. REALTIME enables connections; sends require WRITES+TASKS.

ParametersJSON Schema
NameRequiredDescriptionDefault
eventNo
actionYes
payloadNo
secondsNo
serviceNomain
max_eventsNo
session_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.9/5.0
Behavior3/5

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

Annotations already declare destructiveHint=true, openWorldHint=true, and non-idempotent, so the safety profile is partly covered. The description does add value beyond annotations by disclosing the WRITES+TASKS permission requirement for sends and framing sessions as 'bounded'. It still omits what a send can destroy, session lifetime, and the bounded window (seconds/max_events) semantics.

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?

Two short clauses, front-loaded, with no filler. It is terse to the point of being cryptic, but nothing is wasted and the structural discipline is good.

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 described. But this is a multi-action lifecycle tool (catalog/open/send/listen/close) with 7 parameters and zero schema coverage, and the description neither maps actions to behavior nor ties them to the session_id/seconds/max_events controls. It is substantially incomplete for the tool's complexity.

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

Parameters2/5

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

Schema description coverage is 0% and there are 7 parameters, so the description must carry the burden, but it explains none of them. event, payload, seconds, max_events, session_id and service are left entirely undocumented; only the action enum supplies any meaning. REALTIME/WRITES/TASKS are permissions, not parameters, so they do not compensate.

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

Purpose3/5

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

The description names a resource (realtime sessions) but pairs it with a vague dual verb ('Discover/use'), so an agent cannot tell whether this lists sessions, opens them, or both. It never references the action enum (catalog/open/send/listen/close) that actually defines what the tool does. The sibling set is a different domain so confusion is limited, but the purpose remains under-specified.

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?

'REALTIME enables connections; sends require WRITES+TASKS' gives a genuine prerequisite for the send path, implying usage conditions tied to permissions. However it gives no when-to-use-vs-alternatives guidance and no explanation of which action maps to which lifecycle step. Usage is only partially implied.

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

search_romsB
Read-onlyIdempotent

Search ROMs by title/platform/collection/RA. Compact pages; follow next_offset.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryNo
has_raNo
offsetNo
platform_idsNo
collection_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
limitYes
totalYes
offsetYes
next_offsetYes

TDQS

B3.1/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered. The description adds genuinely useful pagination behavior ('Compact pages; follow next_offset'), but does not explain what 'compact' omits or how the result set behaves across pages.

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?

Two terse sentences, front-loaded with the purpose and then the pagination instruction. Nothing is wasted, though the extreme brevity borders on under-specification rather than pure conciseness.

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?

With six parameters, zero schema description coverage, and no usage guidance, the description is too thin to call the tool correctly without opening the schema. An output schema exists, so return values need not be described, but the input-side gaps remain significant.

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 0%, so the description carries the burden, and it does loosely map four of six parameters (query→title, platform_ids→platform, collection_id→collection, has_ra→RA). However, limit and offset semantics are only hinted at by 'next_offset', and the query string format is never explained.

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 (Search) and resource (ROMs) and enumerates the dimensions searchable — title, platform, collection, RA. This clearly separates it from list_platforms, list_collections, and get_rom, though it does not name those siblings explicitly.

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 when-to-use or when-not-to-use guidance, no prerequisites, and no mention of the sibling tools an agent should prefer for unfiltered listings. The agent must infer that this is the tool for filtered ROM lookup.

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. 10 tool updatesv0.2.1
    • First observedget_collection
    • First observedget_rom
    • First observedlist_collections
    • First observedlist_platforms
    • First observedromm_api_describe
    • First observedromm_api_list
    • First observedromm_api_read
    • First observedromm_artifact
    • First observedromm_socket
    • First observedsearch_roms

TDQS

B3.1/5.0

Scored across 10 tools

Disambiguation4/5

Most tools target distinct resources and actions: list_platforms, search_roms, get_rom, list_collections, and get_collection are clearly separable. However, romm_api_read is a generic read escape hatch that can overlap conceptually with the specific read tools, which could cause an agent to hesitate between dedicated and generic paths.

Naming Consistency3/5

Several tools follow a clean verb_noun pattern (list_platforms, search_roms, get_rom, list_collections, get_collection). Others use a romm_ prefix with varied forms (romm_socket, romm_api_list, romm_api_describe, romm_api_read, romm_artifact), creating a mixed convention that remains readable but not fully predictable.

Tool Count5/5

Ten tools is well-scoped for a ROM management server that needs library browsing, collection access, generic API discovery, realtime sessions, and artifact transfer. Each tool appears to earn its place without excessive duplication.

Completeness3/5

The surface covers reading, searching, listing, API discovery, realtime sessions, and file bytes. However, explicit create, update, and delete operations for ROMs or collections are missing; romm_api_read is read-only and romm_artifact only moves bytes, leaving notable lifecycle gaps.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    B
    maintenance
    Exposes the SSH + tmux client over stdio so agents can drive hosts, tmux sessions, commands, broadcasts, tunnels and audit logs programmatically. It offers 47 grouped tools covering host and session management, connectivity checks, and background port forwarding.
    47
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to interact with the Crewmeister API over local stdio, covering operations for members, teams, time tracking, salary exports, and related platform resources.
    Apache 2.0
  • A
    license
    B
    quality
    A
    maintenance
    Enables querying RetroAchievements data — user profiles, unlocks, game progress, game and achievement details, leaderboards, comments, tickets, and site feeds — through 15 read-only, token-efficient tools that cover all documented Web API endpoints over stdio or Streamable HTTP.
    15
    1
    MIT
  • A
    license
    D
    quality
    C
    maintenance
    Enables secure, configurable access to one or more Syncthing instances over MCP, with read-only defaults and opt-in write, destructive, and administrative operations. Supports stdio and authenticated Streamable HTTP transports, typed tools, bounded responses, and multi-instance configuration.
    40
    MIT