vibo-mcp
MCP server for Vibo — plan your event music as a host/couple: events, timeline sections, song requests, playlists, and exports, via natural language.
- npm: npmjs.com/package/vibo-mcp
- Source: github.com/chrischall/vibo-mcp
Setup
Option A — npx (recommended)
Add to .mcp.json in your project or ~/.claude/mcp.json:
{
"mcpServers": {
"vibo": {
"command": "npx",
"args": ["-y", "vibo-mcp"],
"env": {
"VIBO_EMAIL": "you@example.com",
"VIBO_PASSWORD": "your_password"
}
}
}
}
Authentication
Pick one:
- Email + password (recommended): set
VIBO_EMAILandVIBO_PASSWORD. The server signs in server-side and manages the token (refreshing as needed). - Captured token (for Apple/Google/Facebook accounts): set
VIBO_ACCESS_TOKEN(andVIBO_REFRESH_TOKEN) with values captured from a signed-inweb.vibodj.comsession — no password needed. - Browser capture (SSO, automatic): with the ContextMint Bridge browser extension
(https://github.com/nullnet-app/contextmint-bridge/releases — the fetchproxy
extension renamed, same maintainer, public source; Chrome only for now)
installed and yourself signed into https://web.vibodj.com, run
vibo_capture_sessiononce — it grabs the token from your tab (approve the pair code), saves it to~/.vibo-mcp/session.json, and reuses it thereafter.
The server boots without credentials (so it can be installed and probed); the config error only appears on the first tool call.
Tools
Reads
vibo_get_me— your profile (and whether Spotify/Apple Music are connected).vibo_list_events— your upcoming (orpast:true) events.vibo_get_event— full details for one event.vibo_list_sections— an event's timeline (Ceremony, First Dance, Dinner, …).vibo_get_section_songs— songs requested in a section, with likes/flags/comments.vibo_list_section_questions— the DJ's planning questions for a section (type, options, current answer).vibo_search_songs— find songs to add (Vibo catalog or connected Spotify).vibo_list_section_song_ideas/vibo_list_song_ideas_songs— browse the DJ's suggested song collections per section.vibo_get_playlists/vibo_get_playlist_songs— your connected-service playlists.vibo_list_event_users— the hosts and guests on an event.vibo_list_notifications/vibo_get_notifications_count.vibo_healthcheck— confirm connectivity + auth.
Writes (confirmation-gated)
Each mutating tool asks the user to confirm before anything is sent. Where the
client can show a confirmation prompt, it does (unless the server sets
MCP_CONFIRM_ELICITATION=off, which sends every client down the token path
below). Otherwise the first call makes
no network call and returns status: "confirmation-required" with a preview
of exactly what would be sent (preview.action + preview.willSend) and a
confirmToken. Show that preview to the user, and only after they approve in
chat call the tool again with the same arguments plus confirmToken. A
token works once; changing any argument is refused as DRAFT_CHANGED (with a
fresh preview and token to re-approve), and a reused one as TOKEN_REUSED.
MCP_CONFIRM_MODE (ask-user default / auto / refuse) controls this flow.
vibo_add_song_to_section— add a searched song to a section.vibo_remove_song_from_section— every id is checked against the section first; unknown ids are listed and nothing is sent.vibo_move_song/vibo_reorder_songs— reorder placessourceSongIdsdirectly aftertargetSongId(omit it for the top). A host needs the section's "hosts can order songs" setting on — Vibo turns it off for sections a host creates, and only the DJ can turn it on.vibo_update_song— mark must-play / do-not-play, or set a comment (at most 90 characters; an emoji counts as 2).vibo_add_song_to_sectionre-reads the section after adding and errors if the song isn't actually there.vibo_toggle_song_like— like/unlike a song.vibo_comment_on_song/vibo_comment_on_section(+ delete) — leave the DJ notes.vibo_import_playlist_to_section— pull tracks from a connected Spotify/Apple playlist.vibo_join_event— join via a share link/hash (e.g. avibodj.app.link/...URL).vibo_leave_event.vibo_create_event_contact— add a host/guest contact.vibo_invite_users/vibo_change_user_role/vibo_remove_user— manage who's on the event.vibo_update_section— edit a section's name, time, or note.vibo_create_section— add a section (name ≤ 45 characters;visibilityhost/public; optional time and note — Vibo drops a host's description) and place it withafterSectionIdorposition. Returns the new_id.vibo_delete_section— delete a section; the preview shows its name, song count and answered questions.dontPlay/headlinesections needforce: true.vibo_reorder_sections— move sections to directly aftertargetSectionId(omit for the start).vibo_answer_question— answer a planning question (text / option ids / link / image+file uploads).vibo_set_profile_photo— set your profile photo from a local image in the upload directory (VIBO_UPLOAD_DIR, default~/Downloads/vibo-mcp).vibo_capture_session— capture your login from a signed-in browser tab (SSO accounts).vibo_mark_notifications_read.vibo_export_event_to_spotify/vibo_export_event_to_apple_music.
Response shape (view)
Eight of this server's 42 tools take view: "compact" | "full", and on every
one of them compact is the DEFAULT. You get the slim rung without asking.
They are exactly the eight reads whose GraphQL document asks Vibo for media:
| Tool | What compact drops |
|---|---|
vibo_search_songs |
thumbnails { s180x180 original } per track |
vibo_get_section_songs |
thumbnails { s180x180 original } per song |
vibo_list_song_ideas_songs |
thumbnails { s180x180 original } per song |
vibo_list_event_users |
email + imageUrl per person — projected to _id/firstName/lastName/role on both exits (merged and filtered); view: "full" for emails |
vibo_list_notifications |
imageUrl per notification |
vibo_get_me |
imageUrl |
vibo_get_playlists |
images { url width height } (cover art) per playlist |
vibo_get_playlist_songs |
images { url width height } (artwork) per track — songUrl survives |
That correspondence is not a coincidence to be maintained by hand: a test in
tests/view.test.ts counts the media selections in src/gql.ts and asserts
the roster of view-taking tools matches. Add a ninth selection and it fails.
Compact here is media stripping, not a field projection. src/view.ts
writes no field list, because this repo holds no captured Vibo payload to
derive one from honestly; instead it removes keys whose value is a picture,
which is subtractive and so cannot drop a field nobody knew about.
The one exception is vibo_list_event_users: its query fixes the member field
list, so compact projects each member to _id/firstName/lastName/role
and keeps other people's email addresses out of the default answer (fleet-audit
#1136). Ask for view: "full" only when an email is actually needed.
What compact does not touch is the point of these tools: songUrl, the
links block (spotify / youtube / appleMusic) and the quality verdict
all survive. A streaming link is this server's product, not decoration —
vibo_add_song_to_section cannot add anything without songUrl, and the
quality verdict is computed from how many services carry a track. A null link
survives too: an absent key and a null one are the same to JSON.parse but not
to a reader deciding whether a service was checked.
view: "full" returns Vibo's payload untouched, cover art included. There is
deliberately no raw rung: nothing here re-serialises or normalises the
GraphQL response, so full already IS the upstream payload and a third value
would silently alias one that exists.
The other 34 tools have no view
- The 27 mutating tools (every confirmation-gated write, plus
vibo_capture_session) answer with a confirmation preview or a receipt — an id, a count, a status. Nothing in a receipt is decoration, and slimming one is how you lose the field that says what actually happened. vibo_healthcheckanswers with a connectivity/auth diagnostic. It runs the sameGET_MEdocument asvibo_get_meand still takes no rung, because it never returns Vibo's user object — it builds{ok, userId, email}here. Aviewon it would be a parameter that changes nothing.- The 6 remaining reads (
vibo_list_events,vibo_get_event,vibo_list_sections,vibo_list_section_questions,vibo_list_section_song_ideas,vibo_get_notifications_count) hand back Vibo's GraphQL payload as it arrived, and their documents select no media, so there is nothing for a rung to remove.
A view passed to a tool that does not declare one is dropped by zod without a
warning, so a successful call is never evidence the rung was honoured. Check
the table above rather than assuming.
Typical flow
vibo_list_events→ pick an event id.vibo_list_sections→ pick a section id.vibo_search_songs→ get a song'ssongUrl/viboSongId.vibo_add_song_to_section— show the user the preview it returns, then call again with theconfirmTokenonce they approve.
