Koskamo

osc-bridge MCP

An open-source OSC to MIDI/SysEx bridge and MCP server that allows AI agents to control hardware synthesizers, load presets, and manage device configurations via a hosted endpoint or local installation.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

osc-bridge MCP logo, by roomi-fieldsCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-01Published by roomi-fields
MCP endpoint (Streamable HTTP)
https://mcp.synthhub.roomi-fields.com/mcp
Vendor documentation

What you can do with it

  • Find and load presets into hardware synthesizers
  • Control synth parameters via OSC addresses
  • Detect connected MIDI devices and drivers
  • Backup and restore SysEx presets

Source and maintenance

Community listingRegistry 0.19.1
Maintenance checked

Protocol and capabilities

Server
SynthHub 0.19.1
MCP protocol
2025-06-18
Tools
29 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {}
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

SynthHub: the MIDI implementations (CC, NRPN, SysEx, drum maps) of the synths, drum machines and DAWs in the osc-bridge catalogue, and the presets its users share. Start with list_devices (query: 'korg minilogue'), then list_routes with the slug; get_trust tells how far other users confirmed a driver, per firmware. find_presets and load_preset bring shared sounds to the user's device; share_preset shares one the user made. After testing a driver on the real device, call report_result with the firmware and the device's Identity Reply. This server issued you the account d1eece0e830d91d8e6051c7593c4cb79 (no sign-up, no personal data); your reports and shared presets belong to it. You connected through the shared address, so the next session gets a new account. Tell the user once, in one sentence: to keep this account, replace https://mcp.synthhub.roomi-fields.com/mcp in their MCP settings with https://mcp.synthhub.roomi-fields.com/u/d1eece0e830d91d8e6051c7593c4cb79/mcp (ready-made settings for each app: https://synthhub.roomi-fields.com/#install). Until then, pass user_id: "d1eece0e830d91d8e6051c7593c4cb79" in tool calls.

Tools

29 advertised

list_devices
Advertised by the server during the last successful anonymous check.
Advertised read-only

Find device drivers in the catalogue of synths, drum machines, controllers and DAWs. Without arguments it lists them all; `query` keeps drivers whose vendor, name or slug contain every word (e.g. 'korg minilogue'). Returns name, vendor, OSC prefix (slug), kind, source tier and firmware version when the source states one. Pass the slug to list_routes for the full CC/NRPN/SysEx map.

list_devices input schema
{
  "type": "object",
  "properties": {
    "kind": {
      "enum": [
        "hardware",
        "software"
      ],
      "type": "string"
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "description": "Return at most this many drivers."
    },
    "query": {
      "type": "string",
      "description": "Words that must all appear in the vendor, name or slug (case-insensitive)."
    },
    "vendor": {
      "type": "string",
      "description": "Exact vendor name, case-insensitive (e.g. 'Moog')."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
list_devices output schema
{
  "type": "object",
  "required": [
    "count",
    "devices"
  ],
  "properties": {
    "count": {
      "type": "integer",
      "description": "Number of matching drivers, before `limit`."
    },
    "devices": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "vendor",
          "slug",
          "kind"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Driver id (path in the catalogue), e.g. 'korg/minilogue'."
          },
          "file": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "'hardware' or 'software'."
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "OSC prefix without the leading slash."
          },
          "vendor": {
            "type": "string"
          },
          "firmware": {
            "type": [
              "string",
              "null"
            ],
            "description": "Firmware the source documents; null when it does not say."
          },
          "revision": {
            "type": "string"
          },
          "source_tier": {
            "type": "string"
          },
          "usage_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hosted server only: trust from usage reports (see get_trust)."
          }
        }
      }
    }
  }
}
list_devices annotations
{
  "title": "List devices",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
get_device_docs
Advertised by the server during the last successful anonymous check.
Advertised read-only

Fetch the markdown companion documentation for one device, if present. The slug is the device's OSC prefix without the leading slash (e.g. 'ableton' for /ableton).

get_device_docs input schema
{
  "type": "object",
  "required": [
    "slug"
  ],
  "properties": {
    "slug": {
      "type": "string",
      "description": "Device slug, e.g. 'ableton' or 'minilab3'"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  }
}
get_device_docs output schema
{
  "type": "object",
  "required": [
    "slug",
    "has_docs",
    "markdown"
  ],
  "properties": {
    "slug": {
      "type": "string"
    },
    "has_docs": {
      "type": "boolean",
      "description": "False when no companion .md exists for the device."
    },
    "markdown": {
      "type": "string",
      "description": "The companion documentation, or a not-found message when has_docs is false."
    }
  }
}
get_device_docs annotations
{
  "title": "Get device docs",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
list_routes
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return the OSC routes a device exposes: declarative commands (OSC paths it accepts), cc/nrpn params, sysex params, named note triggers (drum sounds), and reply patterns. Use this to discover what a device can do.

list_routes input schema
{
  "type": "object",
  "required": [
    "slug"
  ],
  "properties": {
    "slug": {
      "type": "string",
      "description": "Device slug, e.g. 'minilab3'"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  }
}
list_routes output schema
{
  "type": "object",
  "required": [
    "device",
    "osc_prefix",
    "commands",
    "cc_params",
    "params",
    "triggers",
    "replies"
  ],
  "properties": {
    "kind": {
      "type": "string"
    },
    "device": {
      "type": "string"
    },
    "params": {
      "type": "array",
      "items": {
        "type": "object"
      },
      "description": "SysEx parameters, each mapped to an OSC address. Each entry carries an 'expects' field — see cc_params."
    },
    "vendor": {
      "type": "string"
    },
    "replies": {
      "type": "array",
      "items": {
        "type": "object"
      },
      "description": "Reply patterns the device emits back onto the OSC surface."
    },
    "commands": {
      "type": "array",
      "items": {
        "type": "object"
      },
      "description": "Declarative OSC paths the device accepts, with typed args and mode (forward/frame)."
    },
    "triggers": {
      "type": "array",
      "items": {
        "type": "object"
      },
      "description": "Named note-triggered sounds (drum machines, samplers). Send '<address> [velocity] [note] [channel]' to fire a Note On; 'note' is required when the entry has no natural note."
    },
    "cc_params": {
      "type": "array",
      "items": {
        "type": "object"
      },
      "description": "CC / NRPN parameters, each mapped to an OSC address. Every entry carries an 'expects' field (continuous/switch/momentary/trigger/clock/discrete) describing the device-side nature of the control — informative only, the signal realization is the caller's concern."
    },
    "osc_prefix": {
      "type": "string"
    }
  }
}
list_routes annotations
{
  "title": "List device routes",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
export_device
Advertised by the server during the last successful anonymous check.
Advertised read-only

Write one driver in a format other tools read: 'oscquery' gives its OSC namespace as OSCQuery JSON (every route with type tags, ranges and access, for OSC controllers and browsers); 'midnam' gives its MIDI names as a MIDI Name Document (controllers incl. NRPN/RPN, named values, drum notes per channel, for DAWs such as Ardour or Logic). Both carry the credit and licence of the driver's sources. The document is the text content; an OSCQuery namespace is large (every address, each CC 0-127 included).

export_device input schema
{
  "type": "object",
  "required": [
    "device",
    "format"
  ],
  "properties": {
    "device": {
      "type": "string",
      "description": "Driver id (e.g. 'korg/minilogue') or slug, from list_devices."
    },
    "format": {
      "enum": [
        "oscquery",
        "midnam"
      ],
      "type": "string"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
export_device output schema
{
  "type": "object",
  "required": [
    "device",
    "format",
    "media_type",
    "file_name",
    "bytes"
  ],
  "properties": {
    "bytes": {
      "type": "integer",
      "description": "Size of the document, which is the text content."
    },
    "device": {
      "type": "string",
      "description": "Driver id."
    },
    "format": {
      "type": "string"
    },
    "file_name": {
      "type": "string",
      "description": "A file name to save it under."
    },
    "media_type": {
      "type": "string",
      "description": "'application/json' or 'application/xml'."
    }
  }
}
export_device annotations
{
  "title": "Export a driver",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
report_result
Advertised by the server during the last successful anonymous check.

Tell the catalogue how a driver behaved on a real device, after testing it: 'works', 'fails' or 'partial', for the whole driver or one OSC address (from list_routes). Give the firmware version, and the device's reply to the MIDI Identity Request (F0 7E 7F 06 01 F7) as identity_hex when you can: trust is counted per firmware, so a failure on another firmware does not count against the driver, and a report of unknown firmware cannot be placed. Several accounts that agree on one firmware mark the driver usage-verified there; a report that several others contradict is rolled back and puts its account under review. Report only what was actually tested.

report_result input schema
{
  "type": "object",
  "required": [
    "device",
    "outcome"
  ],
  "properties": {
    "note": {
      "type": "string",
      "description": "What happened, briefly (500 characters at most): wrong range, no effect, other parameter moved…"
    },
    "device": {
      "type": "string",
      "description": "Driver id (e.g. 'korg/minilogue') or slug, from list_devices."
    },
    "address": {
      "type": "string",
      "description": "One OSC address of the driver (e.g. '/minilogue/filter/cutoff'); omit to report on the whole driver."
    },
    "outcome": {
      "enum": [
        "works",
        "fails",
        "partial"
      ],
      "type": "string"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "firmware": {
      "type": "string",
      "description": "Firmware version of the tested device."
    },
    "identity_hex": {
      "type": "string",
      "description": "The device's reply to the MIDI Identity Request, in hex (e.g. 'F0 7E 00 06 02 42 2C 01 00 00 02 01 00 00 F7'). Proves the device was connected and carries its firmware version."
    }
  },
  "additionalProperties": false
}
report_result output schema
{
  "type": "object",
  "required": [
    "recorded",
    "report",
    "status",
    "trust"
  ],
  "properties": {
    "trust": {
      "type": "object",
      "description": "The driver's trust after this report (see get_trust)."
    },
    "report": {
      "type": "integer",
      "description": "The report's id."
    },
    "status": {
      "enum": [
        "accepted",
        "pending",
        "rolled-back",
        "rejected"
      ],
      "type": "string",
      "description": "accepted: counts in the trust; pending: the account is under review; rolled-back: other accounts contradict it on this firmware."
    },
    "recorded": {
      "type": "boolean"
    }
  }
}
report_result annotations
{
  "title": "Report a test result",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_trust
Advertised by the server during the last successful anonymous check.
Advertised read-only

How far a driver has been confirmed by people who used it, per firmware: status (unreported, unconfirmed, usage-verified, firmware-dependent, failing, disputed), how many users report it works / fails / partly works, each firmware's own status, the device identities seen for each firmware, and the same per OSC address. needs_firmware: true means reports disagree and some have no firmware — identify the device before reporting (see learn). Check it before relying on a driver, together with its source_tier.

get_trust input schema
{
  "type": "object",
  "required": [
    "device"
  ],
  "properties": {
    "device": {
      "type": "string",
      "description": "Driver id (e.g. 'korg/minilogue') or slug, from list_devices."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
get_trust output schema
{
  "type": "object",
  "required": [
    "device",
    "overall",
    "addresses"
  ],
  "properties": {
    "device": {
      "type": "string"
    },
    "overall": {
      "type": "object"
    },
    "addresses": {
      "type": "object"
    }
  }
}
get_trust annotations
{
  "title": "Get a driver's trust",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
report_mapping
Advertised by the server during the last successful anonymous check.

Teach the catalogue which MIDI message a control really sends: after the user moved one control on the device (see relay_listen), give the driver address it is (from list_routes) — or, for a control the driver lacks, its panel label — and the CC, NRPN or note it sent, with the firmware and the device's Identity Reply when you have them. When several accounts observe the same thing on one firmware the mapping is learned; get_trust shows learned mappings and where they differ from the driver.

report_mapping input schema
{
  "type": "object",
  "required": [
    "device"
  ],
  "properties": {
    "cc": {
      "type": "integer",
      "maximum": 127,
      "minimum": 0
    },
    "note": {
      "type": "integer",
      "maximum": 127,
      "minimum": 0
    },
    "label": {
      "type": "string",
      "description": "The control's panel label, when the driver has no address for it."
    },
    "device": {
      "type": "string",
      "description": "Driver id or slug."
    },
    "address": {
      "type": "string",
      "description": "The driver's OSC address for the control."
    },
    "channel": {
      "type": "integer",
      "maximum": 16,
      "minimum": 1
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "firmware": {
      "type": "string"
    },
    "nrpn_lsb": {
      "type": "integer",
      "maximum": 127,
      "minimum": 0
    },
    "nrpn_msb": {
      "type": "integer",
      "maximum": 127,
      "minimum": 0
    },
    "identity_hex": {
      "type": "string",
      "description": "The device's reply to the MIDI Identity Request, in hex."
    }
  },
  "additionalProperties": false
}
report_mapping annotations
{
  "title": "Report what a control sends",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
submit_driver
Advertised by the server during the last successful anonymous check.
Open-world

Contribute a driver for a device the catalogue lacks (or a better one): the full driver file as a JSON object, in the osc-bridge device schema (device.name, device.vendor, device.osc_prefix, and cc_params / params / commands / triggers — see https://synthhub.roomi-fields.com/DEVICE_JSON_SCHEMA/). It is checked, then merged into the SynthHub catalogue by the merge job if it parses, lints and passes the tests, as its own file of source 'agent-contributed'. Say where the data comes from (manual page, tested on the device).

submit_driver input schema
{
  "type": "object",
  "required": [
    "driver"
  ],
  "properties": {
    "note": {
      "type": "string"
    },
    "driver": {
      "type": "object",
      "description": "The driver file."
    },
    "source": {
      "type": "string",
      "description": "Where the mapping comes from (e.g. 'manual v1.2 p. 34, tested on the device')."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "firmware": {
      "type": "string",
      "description": "Firmware the driver was written or tested for."
    }
  },
  "additionalProperties": false
}
submit_driver annotations
{
  "title": "Contribute a driver",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
submit_fix
Advertised by the server during the last successful anonymous check.
Open-world

Contribute a corrected variant of a driver from what the catalogue learned: where learned mappings (get_trust → mappings, differs: true) disagree with the driver on one firmware, builds a copy of the driver with the learned CC / NRPN numbers, as a new file for that firmware, and queues it for the merge job.

submit_fix input schema
{
  "type": "object",
  "required": [
    "device"
  ],
  "properties": {
    "device": {
      "type": "string",
      "description": "Driver id or slug."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "firmware": {
      "type": "string",
      "description": "Needed when learned mappings differ on several firmwares."
    }
  },
  "additionalProperties": false
}
submit_fix annotations
{
  "title": "Contribute a fix from learned mappings",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
get_contribution
Advertised by the server during the last successful anonymous check.
Advertised read-only

Where a contribution stands: pending (waiting for the merge job), merged (with its pull request), rejected (with the reason), or held (its account is under review).

get_contribution input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "integer"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
get_contribution annotations
{
  "title": "Contribution status",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
share_preset
Advertised by the server during the last successful anonymous check.
Open-world

Share something the user made on a device with every SynthHub user, under CC BY-SA 4.0: a sound, a sequence or pattern, a kit, a project, a bank of their own sounds, or a MIDI clip any device can play. Its content: the device's own data (SysEx, e.g. from backup_presets), settings by driver address (from list_routes, e.g. {'/filter/cutoff': [90]}, which also works for devices without dumps), and/or a standard MIDI file. Only what the user made: never factory presets, nor sounds or sequences bought or downloaded from others — set own_sound only after asking the user. Made from someone else's shared preset? Pass derived_from: it credits them, as the licence requires. Describe it well (category, genres, tags, tempo, key, tips): that is how people find it. The same content shared twice returns the existing id; the author publishes new versions with update_preset and can withdraw it (withdraw_preset). Through a relay, the device data can be captured from the device itself: pass code and start the dump from the device's menu during the call, or give request_hex (the device's dump-request message, which the user accepts at the relay). An audio preview is added by its author with PUT /u/<account>/v1/presets/<id>/audio (MP3, Ogg, M4A or WebM, 1 MB at most).

share_preset input schema
{
  "type": "object",
  "required": [
    "device",
    "name",
    "own_sound"
  ],
  "properties": {
    "hex": {
      "type": "string",
      "description": "The device data as SysEx, in hex (64 KB at most)."
    },
    "key": {
      "type": "string",
      "description": "Musical key, e.g. 'A minor'."
    },
    "code": {
      "type": "string",
      "description": "A relay's pairing code: capture the device data from the device instead of hex."
    },
    "kind": {
      "enum": [
        "sound",
        "sequence",
        "kit",
        "project",
        "bank",
        "clip"
      ],
      "type": "string",
      "description": "What it is (default sound)."
    },
    "name": {
      "type": "string",
      "description": "Its name (80 characters at most)."
    },
    "port": {
      "type": "string",
      "description": "With code: the device's port name (or part of it), when the relay has several."
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Character and free words: 'warm', 'dark', 'evolving'… (8 at most)."
    },
    "tips": {
      "type": "string",
      "description": "How to play it: mod wheel, aftertouch, register… (500 characters at most)."
    },
    "tempo": {
      "type": "number",
      "description": "BPM, for sequences and clips."
    },
    "device": {
      "type": "string",
      "description": "Driver id (e.g. 'korg/minilogue') or slug."
    },
    "genres": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Musical styles: 'techno', 'ambient'… (8 at most)."
    },
    "seconds": {
      "type": "integer",
      "maximum": 30,
      "minimum": 1,
      "description": "With code: how long to wait for the dump (default 5)."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "category": {
      "enum": [
        "bass",
        "lead",
        "pad",
        "pluck",
        "keys",
        "organ",
        "brass",
        "strings",
        "bell",
        "arp",
        "sequence",
        "drums",
        "percussion",
        "fx",
        "texture",
        "vocal",
        "other"
      ],
      "type": "string",
      "description": "The kind of sound or part."
    },
    "firmware": {
      "type": "string",
      "description": "Firmware version of the device it was made on."
    },
    "settings": {
      "type": "object",
      "description": "Settings by driver address: {'/filter/cutoff': [90], '/amp/attack': [12]} (512 at most).",
      "additionalProperties": true
    },
    "librarian": {
      "type": "string",
      "description": "The synth the librarian took it from (take_sound's librarian): loading it then goes through the same exchange, fitted to the receiving synth."
    },
    "own_sound": {
      "type": "boolean",
      "description": "Must be true: the user made it (not a factory preset, not someone else's)."
    },
    "description": {
      "type": "string",
      "description": "What it sounds like (500 characters at most)."
    },
    "midi_base64": {
      "type": "string",
      "description": "A standard MIDI file, base64 (64 KB at most)."
    },
    "request_hex": {
      "type": "string",
      "description": "With code: the device's dump-request SysEx, sent first (e.g. 'F0 42 30 00 01 2C 10 F7')."
    },
    "derived_from": {
      "type": "string",
      "description": "Id of the shared preset it was made from."
    }
  },
  "additionalProperties": false
}
share_preset annotations
{
  "title": "Share a preset",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
update_preset
Advertised by the server during the last successful anonymous check.
Open-world

Publish a new version of a preset this account shared: new content (hex, file, settings or midi_file) makes a new version, kept with a change note — earlier versions stay available; the description fields alone change it in place. Someone else's preset: share yours with derived_from instead.

update_preset input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string"
    },
    "hex": {
      "type": "string"
    },
    "key": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "tips": {
      "type": "string"
    },
    "tempo": {
      "type": "number"
    },
    "genres": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "category": {
      "enum": [
        "bass",
        "lead",
        "pad",
        "pluck",
        "keys",
        "organ",
        "brass",
        "strings",
        "bell",
        "arp",
        "sequence",
        "drums",
        "percussion",
        "fx",
        "texture",
        "vocal",
        "other"
      ],
      "type": "string"
    },
    "firmware": {
      "type": "string"
    },
    "settings": {
      "type": "object",
      "additionalProperties": true
    },
    "changelog": {
      "type": "string",
      "description": "What changed in this version (500 characters at most)."
    },
    "description": {
      "type": "string"
    },
    "midi_base64": {
      "type": "string",
      "description": "A standard MIDI file, base64 (64 KB at most)."
    }
  },
  "additionalProperties": false
}
update_preset annotations
{
  "title": "Update a preset",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
find_presets
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Search what SynthHub users shared (CC BY-SA 4.0): sounds, sequences, kits, projects, banks, MIDI clips. Filter by device, kind, category, genre, tag, author (pseudonym) or words; sort by newest, most stars, most loaded into a device or most trusted (confirmed on real devices). Returns, per preset, its id, name, kind, device, description, author, version, whether it has device data, settings, a MIDI file or an audio preview (URL), and its counts. Get one with get_preset.

find_presets input schema
{
  "type": "object",
  "properties": {
    "tag": {
      "type": "string"
    },
    "kind": {
      "enum": [
        "sound",
        "sequence",
        "kit",
        "project",
        "bank",
        "clip"
      ],
      "type": "string"
    },
    "sort": {
      "enum": [
        "new",
        "stars",
        "loads",
        "trusted"
      ],
      "type": "string",
      "description": "new (default), most stars, most loaded into a device, or most confirmed on real devices."
    },
    "genre": {
      "type": "string"
    },
    "limit": {
      "type": "integer",
      "maximum": 50,
      "minimum": 1,
      "description": "At most this many (default 20)."
    },
    "query": {
      "type": "string",
      "description": "Words that must all appear in the name, description, tags, genres, category or device id ('dx7 piano')."
    },
    "author": {
      "type": "string",
      "description": "An author's pseudonym (e.g. 'u1a2b3c4d')."
    },
    "device": {
      "type": "string",
      "description": "Driver id or slug (its other variants are included)."
    },
    "offset": {
      "type": "integer",
      "minimum": 0,
      "description": "Skip this many: the next page (the reply's total says how many match)."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "category": {
      "enum": [
        "bass",
        "lead",
        "pad",
        "pluck",
        "keys",
        "organ",
        "brass",
        "strings",
        "bell",
        "arp",
        "sequence",
        "drums",
        "percussion",
        "fx",
        "texture",
        "vocal",
        "other"
      ],
      "type": "string"
    }
  },
  "additionalProperties": false
}
find_presets annotations
{
  "title": "Find presets",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
get_preset
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

One shared preset in full: its content (SysEx hex, settings by driver address, MIDI file), description and playing tips, versions with their change notes, what it was derived from and its derivatives (remixes), comments, preview URLs, author, licence and attribution line, trust and counts. Load it with load_preset; credit it as the attribution line says when you publish something made from it.

get_preset input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Preset id from find_presets (e.g. 'p3fa9c1d2e4b7')."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "version": {
      "type": "integer",
      "minimum": 1,
      "description": "An earlier version (default the current one)."
    }
  },
  "additionalProperties": false
}
get_preset annotations
{
  "title": "Get a preset",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
report_preset
Advertised by the server during the last successful anonymous check.

Tell SynthHub how a shared preset behaved once loaded on a real device: 'works' (it loaded and sounds as described), 'fails' (refused, wrong sound), or 'factory' (it is a factory preset or someone else's sound: presets that several users flag are hidden until reviewed). Give the firmware.

report_preset input schema
{
  "type": "object",
  "required": [
    "id",
    "outcome"
  ],
  "properties": {
    "id": {
      "type": "string"
    },
    "note": {
      "type": "string",
      "description": "What happened, briefly (500 characters at most)."
    },
    "outcome": {
      "enum": [
        "works",
        "fails",
        "factory"
      ],
      "type": "string"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "firmware": {
      "type": "string"
    }
  },
  "additionalProperties": false
}
report_preset annotations
{
  "title": "Report on a preset",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
withdraw_preset
Advertised by the server during the last successful anonymous check.
Advertised destructive

Withdraw a preset this account shared: it is no longer listed nor served. Copies others already made stay under CC BY-SA.

withdraw_preset input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
withdraw_preset annotations
{
  "title": "Withdraw a preset",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
comment_preset
Advertised by the server during the last successful anonymous check.
Open-world

Comment on a shared preset — how it sounds, how you used it, what you changed — optionally attaching your remix (a preset you shared with derived_from). Comments are public at once. Also: remove one of this account's comments (remove), or flag someone else's as abusive or off-topic (flag); comments several accounts flag are hidden until reviewed.

comment_preset input schema
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The preset to comment on."
    },
    "flag": {
      "type": "integer",
      "description": "Id of someone else's comment to flag (instead of commenting)."
    },
    "text": {
      "type": "string",
      "description": "The comment (2000 characters at most)."
    },
    "remix": {
      "type": "string",
      "description": "Id of your remix, to attach."
    },
    "remove": {
      "type": "integer",
      "description": "Id of this account's comment to remove (instead of commenting)."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
comment_preset annotations
{
  "title": "Comment on a preset",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
star_preset
Advertised by the server during the last successful anonymous check.

Star a shared preset for this account, as on GitHub (on: false takes the star back). Without id, lists the presets this account starred.

star_preset input schema
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "on": {
      "type": "boolean",
      "description": "Default true."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
star_preset annotations
{
  "title": "Star a preset",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
preset_collection
Advertised by the server during the last successful anonymous check.

Collections of shared presets, public, made by one account (e.g. 'Dark basses for minilogue'). action: create (name, description), rename (collection, name, description), add or remove (collection, id), delete (collection), get (collection: its presets), list (this account's collections, or author: someone's).

preset_collection input schema
{
  "type": "object",
  "required": [
    "action"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Preset id to add or remove."
    },
    "name": {
      "type": "string"
    },
    "action": {
      "enum": [
        "create",
        "rename",
        "add",
        "remove",
        "delete",
        "get",
        "list"
      ],
      "type": "string"
    },
    "author": {
      "type": "string",
      "description": "With list: an author's pseudonym."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "collection": {
      "type": "string",
      "description": "Collection id (e.g. 'c1a2b3c4d5e6')."
    },
    "description": {
      "type": "string"
    }
  },
  "additionalProperties": false
}
preset_collection annotations
{
  "title": "Preset collections",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": false,
  "destructiveHint": false
}
follow_author
Advertised by the server during the last successful anonymous check.

Follow an author of shared presets (by pseudonym), or stop (on: false); with author alone and on omitted, shows their page: profile, presets, followers. Without author, lists the newest presets of the authors this account follows.

follow_author input schema
{
  "type": "object",
  "properties": {
    "on": {
      "type": "boolean"
    },
    "limit": {
      "type": "integer",
      "maximum": 50,
      "minimum": 1
    },
    "author": {
      "type": "string"
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
follow_author annotations
{
  "title": "Follow an author",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
set_profile
Advertised by the server during the last successful anonymous check.

Set the public profile shown on this account's author page and with its shared presets and comments, instead of its pseudonym alone: display name, link (https), a few words, the presets put first, where they are, more links, their instruments and a README. A field left out stays as it is; an empty one is cleared. Ask the user what they want shown; all of it is public.

set_profile input schema
{
  "type": "object",
  "properties": {
    "bio": {
      "type": "string",
      "description": "A few words about them and their sounds, 600 characters at most."
    },
    "gear": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "maxItems": 20,
      "description": "The instruments they play, e.g. 'Korg minilogue'."
    },
    "link": {
      "type": "string",
      "description": "An https:// address: their site, SoundCloud, Bandcamp…"
    },
    "name": {
      "type": "string",
      "description": "40 characters at most."
    },
    "about": {
      "type": "string",
      "description": "Their README in Markdown: who they are, how they work, what they offer; 8000 characters at most."
    },
    "links": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "maxItems": 8,
      "description": "More https:// pages of theirs: a channel, a shop, a band."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "featured": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "maxItems": 6,
      "description": "Ids of their own listed presets, shown first on their page, in this order."
    },
    "location": {
      "type": "string",
      "description": "Where they make music, 60 characters at most."
    }
  },
  "additionalProperties": false
}
set_profile annotations
{
  "title": "Set the public profile",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
relay_status
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Check a relay: the user opened https://synthhub.roomi-fields.com/connect/ (or ran osc-bridge connect) and gave you its pairing code. Returns the MIDI output and input ports of their machine, and devices: the driver the user confirmed for each port on the page (use it directly, no detection needed). Nothing is sent to the hardware.

relay_status input schema
{
  "type": "object",
  "required": [
    "code"
  ],
  "properties": {
    "code": {
      "type": "string",
      "description": "The pairing code the relay page or program shows (e.g. 'K7QM-2XPA')."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
relay_status annotations
{
  "title": "Relay status",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
relay_detect
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Find which devices are connected to the user's machine through a relay: sends the MIDI Identity Request (F0 7E 7F 06 01 F7, changes nothing on the device) to every output and matches the answers — manufacturer, model, firmware version — against the drivers' identity blocks. With maker_requests, also sends the makers' own identity requests the drivers name (they change nothing either, but the relay asks the user to accept them, once per output: tell the user first), which recognise devices that ignore the universal one. Returns the best driver ids (recognised_by and firmware when an identity block recognised the device) and identity_hex to pass to report_result. A device that does not answer is found by its knobs with listen_ms (by_controls), or by what people confirmed of its port name (learned); when several remain, ask names the control to have the user turn next (expect: what each candidate would send), then call again with listen_ms.

relay_detect input schema
{
  "type": "object",
  "required": [
    "code"
  ],
  "properties": {
    "code": {
      "type": "string",
      "description": "The pairing code the relay page or program shows (e.g. 'K7QM-2XPA')."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    },
    "listen_ms": {
      "type": "integer",
      "maximum": 20000,
      "minimum": 0,
      "description": "Listen this long for a device that does not answer: ask the user first to turn three or four of its knobs during that time; the controls they send are matched against every driver (by_controls). Confirm the device with the user, then send its fingerprint to POST /v1/fingerprints so the next detection knows it."
    },
    "timeout_ms": {
      "type": "integer",
      "maximum": 5000,
      "minimum": 100,
      "description": "How long to wait for answers (default 1000)."
    },
    "maker_requests": {
      "type": "boolean",
      "description": "Also send the makers' identity requests, after the user accepts them at the relay (default false)."
    }
  },
  "additionalProperties": false
}
relay_detect annotations
{
  "title": "Detect devices through a relay",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
relay_send
Advertised by the server during the last successful anonymous check.
Open-world

Play or set something on the user's hardware through a relay: give a driver (id or slug) and one of its OSC addresses from list_routes with its arguments (e.g. address '/filter/cutoff', args [64]; '/note/on', args [60, 100]) — the server turns it into the right CC, NRPN, note or SysEx message. Or give raw MIDI bytes as hex. Values are the device's own numbers, clamped to the parameter's range. Any SysEx but the Identity Request (patch dumps, stores, settings, preset restores) may overwrite the device's memory: the relay asks the user to accept it first and this call waits for the answer (up to 2 minutes), so tell the user what you are about to send.

relay_send input schema
{
  "type": "object",
  "required": [
    "code"
  ],
  "properties": {
    "hex": {
      "type": "string",
      "description": "Raw MIDI messages instead of device/address, e.g. 'B0 2B 40'."
    },
    "args": {
      "type": "array",
      "items": {},
      "description": "OSC arguments (numbers, strings, booleans)."
    },
    "code": {
      "type": "string",
      "description": "The pairing code the relay page or program shows (e.g. 'K7QM-2XPA')."
    },
    "port": {
      "type": "string",
      "description": "Output port name (or part of it); needed when the relay has several."
    },
    "device": {
      "type": "string",
      "description": "Driver id (e.g. 'korg/minilogue') or slug."
    },
    "gap_ms": {
      "type": "integer",
      "maximum": 2000,
      "minimum": 0,
      "description": "Pause between the SysEx messages of a dump, for devices that write slowly (default 50)."
    },
    "address": {
      "type": "string",
      "description": "OSC address of the driver, with or without its prefix."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
relay_send annotations
{
  "title": "Send through a relay",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
relay_listen
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Listen to what the user's hardware sends through a relay for a few seconds: notes, CC, NRPN, SysEx, decoded. With a device, each CC or NRPN that moved is matched to the driver's OSC addresses — ask the user to move one control on the device while listening to learn which address it is, or to check that the driver's map is right (then record what you saw with report_mapping, so the catalogue learns it).

relay_listen input schema
{
  "type": "object",
  "required": [
    "code"
  ],
  "properties": {
    "code": {
      "type": "string",
      "description": "The pairing code the relay page or program shows (e.g. 'K7QM-2XPA')."
    },
    "device": {
      "type": "string",
      "description": "Driver id or slug, to match what moved to its addresses."
    },
    "seconds": {
      "type": "integer",
      "maximum": 15,
      "minimum": 1,
      "description": "How long to listen (default 3)."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
relay_listen annotations
{
  "title": "Listen through a relay",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": false
}
take_sound
Advertised by the server during the last successful anonymous check.
Open-world

Take the sound the user's synth is playing — or one of its stored programs — straight from the synth through a relay, with its name. The synth is found among those SynthHub's librarian can talk to (the KnobKraft Orm adaptations, about 90 synths) by the identity and detect messages, then asked for its sound. The person accepts each step at the relay (finding the synth, asking it): tell them first. To share it: ask the user whether they made this sound themselves (never a factory preset, nor one bought or downloaded), then call share_preset with the device, name, hex, librarian and firmware returned here, and own_sound: true. When several synths answer, or none did, call again with port.

take_sound input schema
{
  "type": "object",
  "required": [
    "code"
  ],
  "properties": {
    "code": {
      "type": "string",
      "description": "The pairing code the relay page or program shows."
    },
    "port": {
      "type": "string",
      "description": "Output port name (or part of it): look on that port only, for every synth the librarian knows."
    },
    "program": {
      "type": "integer",
      "minimum": 1,
      "description": "A stored program (from 1) instead of the sound being played."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
take_sound annotations
{
  "title": "Take a synth's sound through a relay",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
load_preset
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

Load a shared preset (find_presets, get_preset) into the user's device through a relay: its settings are sent through the driver, its patch data as SysEx — which replaces the sound the device holds, so the relay asks the user to accept it and this call waits for the answer (up to 2 minutes): tell the user first. Afterwards, tell SynthHub how it went with report_preset.

load_preset input schema
{
  "type": "object",
  "required": [
    "code",
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Preset id (e.g. 'p3fa9c1d2e4b7')."
    },
    "code": {
      "type": "string",
      "description": "The pairing code the relay page or program shows."
    },
    "port": {
      "type": "string",
      "description": "Output port name (or part of it); needed when the relay has several."
    },
    "device": {
      "type": "string",
      "description": "The device it goes into, when not the preset's own: one of get_preset's loads_on (an M-VAVE FM-1 takes DX7 voices); the sound is sent unchanged."
    },
    "gap_ms": {
      "type": "integer",
      "maximum": 2000,
      "minimum": 0,
      "description": "Pause between the SysEx messages, for devices that write slowly (default 50)."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
load_preset annotations
{
  "title": "Load a preset through a relay",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": true
}
link_account
Advertised by the server during the last successful anonymous check.
Open-world

Link this account to the user's SynthHub account on the site: returns a one-time address (valid 15 minutes) for the user to open and sign in (passkey, e-mail, Google or Discord). Afterwards what this account shared appears under their profile, and they manage it — and their stars, collections, comments — from the site. Offer it when the user wants to see or manage what you shared for them.

link_account input schema
{
  "type": "object",
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
link_account annotations
{
  "title": "Link to the user's account",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
claim_presets
Advertised by the server during the last successful anonymous check.
Open-world

Claim presets SynthHub imported from another site (their page says 'imported', with the author's name and page there) when the user is that author: give the id of one of them; the server answers with a code for the user to add to their author page at that site (profile or bio). Once it is there, call again with verify: true: every preset imported from that author becomes the user's, to edit or withdraw.

claim_presets input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Id of one of the imported presets."
    },
    "verify": {
      "type": "boolean",
      "description": "True once the code is on the author page."
    },
    "user_id": {
      "type": "string",
      "description": "Your anonymous SynthHub id, if you kept it from an earlier session (see the server instructions). Optional."
    }
  },
  "additionalProperties": false
}
claim_presets annotations
{
  "title": "Claim imported presets",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

Not advertised

No resource definitions available.

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
987 ms
95th percentile latency
987 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 987 ms · metadata changed · 29 tool(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http osc-bridge-mcp-roomi-fields https://mcp.synthhub.roomi-fields.com/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add osc-bridge-mcp-roomi-fields --url https://mcp.synthhub.roomi-fields.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable osc-bridge-mcp-roomi-fields in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "osc-bridge-mcp-roomi-fields": {
      "url": "https://mcp.synthhub.roomi-fields.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "osc-bridge-mcp-roomi-fields": {
      "type": "streamableHttp",
      "url": "https://mcp.synthhub.roomi-fields.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start osc-bridge-mcp-roomi-fields and inspect its tools.
VS Code configuration
{
  "servers": {
    "osc-bridge-mcp-roomi-fields": {
      "type": "http",
      "url": "https://mcp.synthhub.roomi-fields.com/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http osc-bridge-mcp-roomi-fields https://mcp.synthhub.roomi-fields.com/mcp

Claude Desktop

Merge this into claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude Desktop.
Claude Desktop configuration
{
  "mcpServers": {
    "osc-bridge-mcp-roomi-fields": {
      "url": "https://mcp.synthhub.roomi-fields.com/mcp"
    }
  }
}

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "osc-bridge-mcp-roomi-fields": {
      "serverUrl": "https://mcp.synthhub.roomi-fields.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like osc-bridge MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.