Skip to navigation

MeetStream MCP Server

Give Claude, Cursor, Codex or any MCP client live access to the MeetStream API. Send bots into Zoom, Google Meet and Teams, pull transcripts and summaries, talk into live meetings, and debug real bot sessions from a prompt.
View as Markdown

The MeetStream MCP server exposes the whole meeting-bot lifecycle as Model Context Protocol tools. Connect it once and your assistant can run real bots against your account:

“Send a bot to https://meet.google.com/abc-defg-hij with Deepgram transcription. When the call ends, give me the summary and the action items.”

“Bot 4f1c… never made it into the meeting. Find out why.”

“Re-transcribe yesterday’s 3 pm call with AssemblyAI and compare speaker labels with the original.”

This is the action server: it calls the MeetStream API on your account. The separate docs-search MCP (https://docs.meetstream.ai/_mcp/server) only searches these docs and needs no key. Most agents should have both.

At a glance

Hosted endpointhttps://mcp.meetstream.ai/mcp (legacy SSE clients: https://mcp.meetstream.ai/sse)
TransportMCP Streamable HTTP, stateless (no session to keep alive)
InstallNone. MeetStream hosts the server; there is no local version
AuthSign in with OAuth from your client, or send your MeetStream API key per request. The hosted server stores no key of its own
Tools19: bots, transcripts, media, live interaction, calendar, webhook reference
SourceOpen source (Go): meetstream-ai/meetstream-mcp

Quickstart

1

Connect your client

Pick your client in the tabs below. Most clients only need the URL https://mcp.meetstream.ai/mcp. Every option exposes the same 19 tools.

2

Sign in

When your client opens app.meetstream.ai, sign in and click Allow. The dashboard creates an API key for that connection, so there is no key to copy. If your client cannot sign in with OAuth, create a key yourself (it starts with ms_) and send it as the tab shows.

3

Verify

Ask: “Using meetstream, list my bots.” A list of bots, or a clean empty list, means you are connected. An auth problem comes back as a clear error, never a silent failure.

Hosted, sign in with OAuth:

claude mcp add --transport http meetstream https://mcp.meetstream.ai/mcp

Then run /mcp in Claude Code, choose meetstream and Authenticate. Your browser opens app.meetstream.ai: sign in and click Allow.

Hosted, with an API key:

claude mcp add --transport http meetstream https://mcp.meetstream.ai/mcp \
--header "Authorization: Bearer $MEETSTREAM_API_KEY"

Check it with claude mcp list. Add --scope project to share the server config with your team through .mcp.json; each teammate signs in or supplies their own key.

For MeetStream-specific coding knowledge on top of the tools, also install the agent skills plugin:

/plugin marketplace add meetstream-ai/claude-plugin
/plugin install meetstream@meetstream-ai

The plugin ships skills only, so install it alongside the MCP server, not instead of it.

Do not use npx @meetstream/mcp. That npm package is the old Node server, frozen at 0.3.0, and it predates the audio-only create_bot defaults and later fixes. If a client config still runs it, switch it to the hosted URL.

Authentication

  • OAuth or a key. Sign in with OAuth and the dashboard creates an API key for that connection, or send a key you created yourself. Each request carries its own credential and the hosted server keeps nothing between requests. Every action runs as the account that owns the key, with that account’s bots, calendars and provider settings.
  • Bearer here, Token on REST. The MCP server expects Authorization: Bearer <key>. The REST API at api.meetstream.ai expects Authorization: Token <key>. Sending Token to the MCP server returns 401.
  • No credentials, no call. A request without a key or token gets 401 with setup instructions and a WWW-Authenticate header that points OAuth clients at the sign-in flow.
  • Disconnect. OAuth access tokens last an hour and refresh automatically. To cut a connection off, delete the key named after the app on the API keys page.
  • Is there a local version? No. MeetStream hosts the server, so it is always the current version and there is nothing to install or update. Clients that only speak the older HTTP+SSE transport use https://mcp.meetstream.ai/sse.

Key hygiene: one key per person or per agent, stored in an environment variable or your client’s secret store rather than in a committed file. Rotate a key from the dashboard if it ever appears in a chat, a screenshot or a log.

What your agent can and cannot do

Every tool declares what kind of action it is, so your client can ask before anything with side effects.

CategoryToolsEffect
Read onlylist_bots, get_bot_status, get_bot_detail, get_bot_summary, get_transcript, list_transcriptions, get_media_urls, get_participants, get_chats, get_speaker_timeline, list_calendar_events, webhook_events_guideReads data. Safe to allow freely
Starts work on your accountcreate_bot, transcribe_audio, schedule_calendar_botA bot joins a real meeting or a transcription job runs. These use your account’s usage
Acts inside a live meetingsend_chat_message, send_image, remove_botEveryone in the call can see the message or image; remove_bot makes the bot leave (recordings are kept)
Destructivedelete_bot_dataPermanently deletes a bot’s audio, video and transcripts. Requires confirm: true, and the tool is marked destructive so clients prompt first

Not exposed as tools (use the REST API, an SDK or the CLI): creating and editing MIA agent configs, connecting a calendar, custom storage, registering signed-in bot domains and accounts (Google and Teams, so passwords never pass through a chat), custom automatic_leave values and deduplication_key. create_bot can still use all of them once they exist: agent_config_id attaches a MIA agent, google_login_domain / teams_login_domain make a signed-in join, and zoom_zak_url / zoom_obf_url make an authenticated Zoom join.

Tools

ToolParametersWhat it does
create_botmeeting_link (required), plus the options belowSends a bot to a Zoom, Google Meet or Teams meeting now, or schedules it with join_at. Returns bot_id, and transcript_id when a post-call provider is set
list_botsnoneAll bots on the account, paginated
get_bot_statusbot_idCurrent status, e.g. Joining, InWaitingRoom, InMeeting, Recording, Stopped, NotAllowed, Denied, Done
get_bot_detailbot_idFull session metadata: platform, timings, status timeline, the canonical transcript_id, the original request
get_bot_summarybot_idCurrently unavailable: the REST summary route is not exposed. Fetch the transcript with get_transcript and summarize it with your own model.
remove_botbot_idMakes the bot leave now. Data is kept
delete_bot_databot_id, confirmPermanently deletes the bot’s media and transcripts and fires a data_deletion webhook. Irreversible
ToolParametersWhat it does
get_transcriptbot_id; optional wait, timeout_seconds (default 300), rawFetches the transcript by bot id. It resolves the transcript_id for you, which is never in a webhook. With wait: true it polls until ready, up to the timeout
list_transcriptionsbot_idEvery transcription run for the bot, with provider, status and download URLs
transcribe_audiobot_id; optional provider (deepgram default, assemblyai, sarvam, meetstream, jigsawstack), language, callback_urlTranscribes, or re-transcribes, the stored audio. It is also the way to get a post-call transcript for a bot that used a streaming-only provider
ToolParametersWhat it does
get_media_urlsbot_id; optional kind: audio (default), video, audio_streams, video_streams, screenshotsPresigned download URLs. Audio links last about an hour and video links about 10 minutes, so fetch fresh ones rather than storing them. Per-participant streams require separate_audio_streams / separate_video_streams at create time
get_participantsbot_idParticipants detected in the meeting
get_chatsbot_idIn-meeting chat messages
get_speaker_timelinebot_idWho spoke when
ToolParametersWhat it does
send_chat_messagebot_id, messagePosts a chat message into the live meeting as the bot
send_imagebot_id, img_url; optional display_duration_secondsShows an image or GIF as the bot’s video tile. The URL must be publicly reachable
ToolParametersWhat it does
list_calendar_eventsnoneUpcoming events from connected Google Calendars. Connect a calendar first through the Calendar API
schedule_calendar_botevent_id; optional action: schedule (default) or unscheduleSends a bot to, or pulls it from, one calendar event
webhook_events_guidenoneThe verified reference for webhook payloads: envelope, the two-layer bot.stopped terminal model, status codes and streaming caveats. Have your agent read it before it writes any webhook handler

create_bot options

The tool uses friendlier names than the REST body. If your agent moves from prototyping over MCP to writing REST or SDK code, this is the mapping:

MCP parameterREST fieldNotes
meeting_linkmeeting_linkFull invite URL. Keep Zoom’s ?pwd= part
bot_namebot_nameDefaults to MeetStream Bot over MCP; required in REST
record_videovideo_requiredDefaults to false over MCP (audio only). The REST API defaults to true
transcription_providerrecording_config.transcript.providerPost-call: deepgram, assemblyai, sarvam, meetstream, jigsawstack. Live: deepgram_streaming, assemblyai_streaming, meeting_captions
languageprovider language / language_codeIn the provider’s own format, e.g. en, en_us, en-IN
callback_urlcallback_urlPublic HTTPS URL for webhooks
live_transcript_webhook_urllive_transcription_required.webhook_urlNeeds a streaming provider
join_atjoin_atISO 8601 time to schedule a future join
bot_messagebot_messageChat message posted when the bot joins
bot_image_urlbot_image_urlPublic image URL for the bot’s tile
separate_audio_streamsaudio_separate_streamsPer-participant audio
separate_video_streamsvideo_separate_streamsPer-participant video
retention_hoursrecording_config.retentionSent as { type: "timed", hours }. Without it, data is kept for the API default of 30 days
agent_config_idagent_config_idAttaches an existing MIA voice agent
custom_attributescustom_attributesString key/values echoed back on webhooks
idempotency_keyIdempotency-Key headerA retry with the same key returns the original bot (HTTP 507) instead of a duplicate
google_login_domaingoogle_meet: { login_required: true, google_login_domain }Google signed-in join. The domain must already be registered
teams_login_domainteams: { login_required: true, teams_login_domain }Teams signed-in join. The bot shows the Microsoft account’s name and picture; one bot per account at a time
sign_in_email / strict_emailsame blockPin one registered account; strict_email: false falls back to any available one
zoom_zak_url / zoom_obf_urlzoom: { zak_url } / zoom: { obf_url }Authenticated Zoom join through a token URL you host. Send one, never both

Every bot created over MCP also gets safe automatic_leave defaults, so a bot never sits in an empty call or a lobby indefinitely: 300 s in the waiting room, 60 s after everyone leaves, a 4 hour recording cap, and 60 s for Zoom’s recording-permission prompt.

Example workflows

“Send a notetaker called ‘Acme Notes’ to https://zoom.us/j/123?pwd=abc with Deepgram. When it’s done, give me the summary, the action items with owners, and the full transcript.”

The agent calls create_bot with transcription_provider: "deepgram", checks get_bot_status while the meeting runs, then calls get_transcript with wait: true and summarizes the result.

“Bot 4f1c… never showed up in the meeting. Diagnose it.”

get_bot_status and get_bot_detail show the status timeline. NotAllowed means nobody admitted it from the waiting room before the timeout. Denied means a host refused it. For Zoom meetings outside your own account, check that your Zoom app is out of development mode (production submission). The debugging guide covers the rest.

“The speaker labels on yesterday’s standup look wrong. Re-run it with AssemblyAI and compare.”

list_bots finds the bot, transcribe_audio starts a new run with provider: "assemblyai", and list_transcriptions shows both runs side by side.

“I used deepgram_streaming for this call, and now I need a proper post-call transcript.”

Streaming-only bots never produce a post-call transcript, so get_transcript stays not-ready. transcribe_audio generates one from the stored audio.

“Post the agenda in the meeting chat, then show our logo on the bot’s tile for 30 seconds.”

send_chat_message, then send_image with a public image URL and display_duration_seconds: 30.

“What’s on my calendar tomorrow? Put a bot on every external call.”

list_calendar_events, then schedule_calendar_bot for each event it picks. Ask the agent to list the events it chose before it schedules anything.

“Read the MeetStream webhook guide, then write an Express handler that stores transcripts when they’re ready and alerts me when a bot isn’t admitted.”

webhook_events_guide gives the agent the real payload shapes. Every ending arrives once as event: "bot.stopped" and bot_event says why (bot.stopped, bot.kicked, bot.notallowed, bot.denied, bot.failed). bot.done is the final event on every path.

create_bot recording parameters

The MCP tool’s recording arguments map onto the Create Bot API like this. The tool defaults differ from the raw API defaults on purpose, so an assistant that just says “join my meeting” gets an audio-only bot.

MCP argumentCreate Bot fieldMCP defaultAPI defaultNotes
record_videovideo_requiredfalsetrueThe tool always sends the field explicitly, so video is off unless you ask for it. Transcripts, summaries, diarization and speaker timelines all work without video.
video_layoutrecording_config.video_layoutspeaker_viewgrid_viewspeaker_view follows the active speaker; grid_view is a mosaic of everyone. Sent only when record_video is true, and ignored by the API otherwise. Google Meet, Teams and Zoom accept both; WhatsApp accepts only grid_view.
separate_video_streamsvideo_separate_streamsunsetfalsePer-participant video is opt-in. The tool never enables it implicitly, since it multiplies processing and storage per participant.
separate_audio_streamsaudio_separate_streamsunsetfalsePer-participant audio is unchanged by the recording defaults above.

Ask for video explicitly (“record video of this meeting”) to get record_video: true, and say “grid view” or “gallery view” if you want the mosaic instead of speaker view.

Notes

  • Stateless & scalable — the remote server treats every request independently; there’s no session to keep alive.
  • Safe defaults on create_bot — sensible automatic_leave timeouts are applied so bots never sit in empty meetings.
  • Audio-only by default: since server 0.3.3, record_video defaults to false and is always sent explicitly, and when you do ask for video the server sends video_layout: "speaker_view". Per-participant video is never enabled unless you ask for it.
  • Destructive ops are gated — delete_bot_data requires explicit confirmation.
  • Idempotency — a retried create_bot returns the original bot rather than creating a duplicate.