{
  "markdown": "# meetergo MCP server\n\nLets an AI agent actually run a calendar: find slots, book, reschedule, cancel,\nreview what is coming up, and keep the contact record straight.\n\nNot to be confused with the **docs** MCP server at\n`https://developer.meetergo.com/mcp`, which searches documentation and cannot\nchange anything. Both are useful and they do different jobs:\n\n| | Docs MCP | This server |\n|---|---|---|\n| Endpoint | `developer.meetergo.com/mcp` | `mcp.meetergo.com/mcp`, or `npx` over stdio |\n| Tools | `SearchMeetergo` | 57 scheduling, CRM, Mira and config tools |\n| Can it book? | No | **Yes** |\n| Use it to | write an integration | be the integration |\n\n## Setup\n\nCreate a Personal Access Token at\n[my.meetergo.com/integrations](https://my.meetergo.com/integrations) — it looks\nlike `rgo-…` — then either point your client at the hosted server or run this\npackage locally over stdio. The token works on every plan, including Free.\n\n### Hosted\n\n```\nhttps://mcp.meetergo.com/mcp\n```\n\nStreamable HTTP, authenticated with `Authorization: Bearer rgo-…`. The path\nmatters: `mcp.meetergo.com` alone is not the endpoint. For clients that take a\nremote URL and headers:\n\n```json\n{\n  \"mcpServers\": {\n    \"meetergo\": {\n      \"url\": \"https://mcp.meetergo.com/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer rgo-your_token_here\" }\n    }\n  }\n}\n```\n\n### Local (npx)\n\n```json\n{\n  \"mcpServers\": {\n    \"meetergo\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@meetergo/mcp-server\"],\n      \"env\": { \"MEETERGO_TOKEN\": \"rgo-your_token_here\" }\n    }\n  }\n}\n```\n\nWorks with Claude Desktop, Claude Code, Cursor, or anything else that speaks\nMCP.\n\n### Scope the token\n\nWhen you create the token you can limit it to the capabilities the agent\nactually needs (scheduling, contacts and deals, Mira, forms, account). A limited\ntoken is refused on everything outside those groups, including reads, so give it\nevery group whose tools you intend to use — a Mira-only token cannot book, and a\nscheduling-only token cannot read your knowledge base.\n\n### Signing in instead of pasting a token\n\nOAuth sign-in is live on the hosted endpoint. Discovery is published at\n`/.well-known/oauth-protected-resource` (RFC 9728), so a capable client can\nstart the flow from the MCP URL. Clients are pre-registered rather than created\nthrough dynamic client registration. For a Claude custom connector, enter the\npublic client id `mcp-claude` under Advanced settings and leave the client secret\nblank. The directory clients for Claude and ChatGPT are configured with their\nrespective providers.\n\n#### Cursor and Grok Bot\n\nThis repository includes the Cursor Marketplace plugin used by both Cursor and\nGrok Bot. Install **meetergo** from Settings, Plugins, Marketplace, then finish\nthe browser sign-in. The plugin connects to the hosted endpoint and uses the\npublic PKCE client id `mcp-cursor`; there is no client secret or token to paste.\n\nFor local review before the marketplace listing is published, load this\nrepository as a local Cursor plugin. Its `.cursor-plugin/plugin.json` manifest\npoints at `mcp.json`, which contains the same hosted URL and OAuth client id.\n\nA Personal Access Token works in every MCP client, on every plan including Free.\nThat is what the rest of this page assumes.\n\n### Acting for another user\n\nA Personal Access Token always acts as its owner. To run an agent across a whole\ncompany — an assistant booking on behalf of several colleagues — use a **Platform\nAPI Key** (`ak_live:<uuid>:<secret>`) and name the target user:\n\n```json\n\"env\": {\n  \"MEETERGO_TOKEN\": \"ak_live:...\",\n  \"MEETERGO_USER_ID\": \"the-user-uuid\"\n}\n```\n\nThe two token types have opposite requirements, and the server checks both at\nstartup rather than letting you find out mid-booking:\n\n- a Platform API Key **must** have `MEETERGO_USER_ID` — the API demands an\n  acting user on nearly every route;\n- a Personal Access Token **must not** — it always acts as its owner, and the\n  API rejects the header outright.\n\nAgainst the hosted endpoint the acting user travels as the\n`X-Meetergo-Api-User-Id` request header instead of an environment variable; the\nsame two rules apply, and sending it with a Personal Access Token is refused.\n\n### Environment\n\nThe stdio entry (`meetergo-mcp`, what `npx` runs):\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `MEETERGO_TOKEN` | **yes** | `rgo-…` Personal Access Token or `ak_live:…` Platform API Key |\n| `MEETERGO_USER_ID` | with a Platform API Key | The user to act as |\n| `MEETERGO_API_URL` | | API base override, default `https://api.meetergo.com/v4` |\n| `MEETERGO_NEXT_URL` | | Booking-page host rendered into widget install snippets, default `https://cal.meetergo.com` |\n| `MEETERGO_TIMEOUT_MS` | | Per-request timeout, default `30000` |\n\n### Running the hosted entry yourself\n\nThe package also ships `meetergo-mcp-http`, the Streamable HTTP entry that runs\nbehind `https://mcp.meetergo.com/mcp`. Credentials arrive per request in the\n`Authorization` header rather than from the environment, so one process serves\nany number of accounts — `MEETERGO_TOKEN` and `MEETERGO_USER_ID` are not read\nhere. It reads:\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `PORT` | | Listen port, default `8080` |\n| `MEETERGO_API_URL` | | API base override, default `https://api.meetergo.com/v4` |\n| `MEETERGO_NEXT_URL` | | Booking-page host rendered into widget install snippets, default `https://cal.meetergo.com` |\n| `MEETERGO_DASHBOARD_URL` | | Dashboard host used for upgrade links in plan-limit errors, default `https://my.meetergo.com` |\n| `MCP_PUBLIC_URL` | | This server's public URL, default `http://localhost:$PORT`. Only its **origin** is used: origin + `/mcp` is the resource identifier — the `resource` field of the discovery document, and the value an OAuth token must carry in `aud`. `https://host`, `https://host/` and `https://host/mcp` are therefore the same setting. Anything that is not an absolute http(s) URL fails at startup |\n| `OAUTH_ISSUER` | all three or none | OpenID issuer of the authorization server, e.g. `https://login.meetergo.com/realms/meetergo`. Must be absolute and **https** — the exchange posts this server's client secret and the user's token to it — or the process refuses to start. A trailing slash is trimmed |\n| `OAUTH_CLIENT_ID` | all three or none | Confidential client this server exchanges tokens into (RFC 8693) |\n| `OAUTH_CLIENT_SECRET` | all three or none | That client's secret |\n\n**The three `OAUTH_*` variables are all-or-nothing.** Set all three and an\ninbound access token is validated first — issuer, `aud`, `typ: Bearer`, RS256\nsignature against the issuer's JWKS, expiry — and only then exchanged for a\nseparate token for the upstream API. The MCP spec forbids forwarding the token a\nclient handed you, so the exchange is not an optimisation; it is the only path.\n\nSet none and the process is bearer-token-only: Personal Access Tokens and\nPlatform API Keys work, both `.well-known` paths answer 404, the 401 challenge\ncarries no `resource_metadata`, and an OAuth token is refused rather than passed\nupstream.\n\nSet one or two and you get the bearer-token-only behaviour above, not a partial\nOAuth — plus a warning log, `oauth_disabled_incomplete_config`, naming the\nvariables that are missing.\n\n### Retries\n\nBoth entries behave the same here. Rate limits and transient upstream errors\n(429, 502, 503, 504) get up to three attempts in total (so two retries),\nhonouring `Retry-After` where the API sends one.\n\nRetries are **not** applied blindly. A booking or cancellation that fails\nambiguously — a timeout, a dropped connection, a 502 — may already have been\napplied by the API, and there is no idempotency key to make a second attempt\nsafe. Only reads are retried on those; writes are retried solely on a 429, the\none response that states the request was never processed.\n\n## One-prompt onboarding\n\nIf your client supports MCP prompts, run **`meetergo: onboard`**. Otherwise\npaste this:\n\n> Set up meetergo for my company. Call get_me and get_setup_status first and\n> tell me what already exists. Then analyse my website with\n> propose_conversion_setup and present the proposed setup — meeting types,\n> qualification questions, the website assistant. Build nothing until I approve.\n> After I approve: create what's missing, turn the questions into a routing form\n> with create_qualification_form, crawl my site, then PROVE it works with\n> run_test_drive and show me the verdicts. Finish by giving me the install\n> snippet, and verify with verify_widget_install after I've pasted it.\n\nThe agent audits what exists, proposes, waits for your yes, builds, and then\n**shows you scripted visitors booking through your own assistant** before\nanything goes live. A second prompt, **`meetergo: weekly-review`**, pulls last\nweek's conversations and offers to teach the assistant every answer it missed.\n\n## Plan limits\n\nEvery tool reports plan walls structurally: which limit was hit and where\nupgrading happens, so your agent explains the situation instead of failing\nvaguely. `get_me` also returns a `plan` block (tier, limits) so a good agent\nwarns you *before* starting something your plan cannot finish. Connecting the\nserver itself is never gated — a token from any plan, including Free, works.\n\n## Tools\n\n57 tools, covering scheduling end to end. **Scheduling** is the loop most agents\nlive in; the rest is there so an agent never has to fall back to raw REST.\n\n### Scheduling\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `get_me` | | Confirm the token works — start here when something looks empty |\n| `list_meeting_types` | | What can be booked |\n| `get_availability` | | Bookable slots for a meeting type |\n| `book_appointment` | **yes** | Book a slot |\n| `reschedule_appointment` | **yes** | Move an appointment |\n| `cancel_appointment` | **destructive** | Cancel, or drop one attendee |\n| `list_appointments` | | Paginated calendar with filters |\n| `get_todays_appointments` | | Today only |\n| `get_appointment` | | One appointment in full, including `attendeeId`s |\n| `add_guest` | **yes** | Add a guest email to an appointment |\n| `update_appointment_notes` | **yes** | Write call prep or an outcome back |\n| `create_one_time_booking_link` | **yes** | Send a single-use link instead of booking for someone |\n| `list_calendar_connections` | | Which calendars are attached |\n\n### Follow-up\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `send_quick_email` | **yes** | One-off email to an attendee (5 per 5 min) |\n| `update_meeting_transcription` | **yes** | Attach a transcript or summary from a notetaker |\n\n### Meeting types\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `get_meeting_type` | | Full config — read before updating |\n| `create_meeting_type` | **yes** | Create a bookable meeting type |\n| `update_meeting_type` | **yes** | Change one |\n| `delete_meeting_type` | **destructive** | Remove one; its page stops working |\n\n### Booking page\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `get_personal_page` | | Colours, header, links, meeting-type order |\n| `update_personal_page` | **yes** | Change branding |\n\n### Routing forms\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `list_routing_forms` | | All forms and funnels |\n| `get_routing_form` | | Steps, fields and routing rules |\n| `create_routing_form` | **yes** | Build a qualification form |\n| `update_routing_form` | **yes** | Change one |\n| `delete_routing_form` | **destructive** | Remove one; shared links break |\n| `send_routing_form` | **yes** | Send by email or SMS, or mint a link |\n| `list_form_recipients` | | Who got it, who answered |\n| `list_data_fields` | | Reusable fields across forms |\n| `create_data_field` | **yes** | Add one |\n\n### CRM\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `search_contacts` | | Find a contact before creating a duplicate |\n| `get_contact` | | Full record, by `contactId` or by `attendeeId` from a booking |\n| `create_contact` | **yes** | Add a contact |\n| `update_contact` | **yes** | Edit a contact |\n| `bulk_create_contacts` | **yes** | Import many at once (3 calls per min) |\n| `delete_contact` | **destructive** | Remove a contact and its form answers |\n\n### Mira, the website assistant\n\nEverything needed to take a website from \"no assistant\" to a live one that\nanswers from the company's own pages and books meetings.\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `get_setup_status` | | The launch checklist: what exists, what's missing, the next move |\n| `get_mira_settings` | | The whole assistant config — read before changing it |\n| `update_mira_settings` | **destructive** | Change it; returns the previous settings so you can put them back |\n| `restore_mira_settings` | **destructive** | Restore a snapshot taken from an earlier update |\n| `propose_conversion_setup` | | Read a crawled site and propose an assistant, qualification and booking setup |\n| `create_qualification_form` | **yes** | Turn proposed questions into a real, editable routing form |\n| `run_test_drive` | | Scripted visitors talk to the saved assistant; verdicts + transcripts back |\n| `get_mira_widget_embed` | | The public key, the embed snippet, and a preview URL |\n| `verify_widget_install` | | Fetch a page of the customer's site and confirm it serves THEIR widget |\n| `answer_visitor_question` | **yes** | Teach the assistant an answer it was missing |\n| `get_conversation_insights` | | What visitors asked and where the assistant had no answer |\n\n### Knowledge base\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `crawl_company_website` | **yes** | Ingest a website so the assistant can answer from it |\n| `get_crawl_status` | | Progress of a running crawl |\n| `list_knowledge_documents` | | What has been ingested |\n| `delete_knowledge_document` | **destructive** | Remove a document; the assistant stops citing it |\n| `search_company_knowledge` | | Retrieve the passages a question would be answered from |\n\n### Webhooks\n\n| Tool | Writes? | Purpose |\n|---|---|---|\n| `list_webhooks` | | Endpoints in use (max 6 per company) |\n| `create_webhook` | **yes** | Register an HTTPS endpoint |\n| `update_webhook` | **yes** | Change URL or events |\n| `delete_webhook` | **destructive** | Remove one; events stop immediately |\n\nWrites carry `readOnlyHint: false`, and everything marked **destructive** above\ncarries `destructiveHint: true`, so hosts can require confirmation before an\nagent removes something a human would miss.\n\n## What the tools do for you\n\nThe API asks for things a model has no way to know. Rather than describing that\nboilerplate in a docstring and hoping, the tools supply it:\n\n- **`book_appointment`** builds the nested `attendee` object, defaults\n  `receiveReminders` and the required empty `notes`, and refuses a booking with\n  no name rather than writing a blank one into the invitation.\n- **`get_availability` and `book_appointment`** resolve which hosts to compute\n  for. The API rejects both with `Expected hostIds or queueId` before it even\n  loads the meeting type, and a model only ever has a `meetingTypeId`.\n- **`create_meeting_type`** fills the six required-but-irrelevant `meetingInfo`\n  fields (`customChannelName`, `connectChannelName`, an empty\n  `confirmationButton`, …) that reject the whole request when missing. Anything\n  the schema does not name goes through `advanced`.\n- **`list_appointments`** supplies the required `page` and `pageSize`, which the\n  API has no defaults for.\n\n## Development\n\n```bash\nnpm test          # vitest\nnpm run build     # tsc -> dist\n```\n\nThe tests assert the **wire format**, not just the tool list: which path each\ntool calls, and the exact body shape the API's DTOs require. That is deliberate.\n0.1.x shipped five tools that could never succeed — wrong paths, wrong query\nkeys, a flat body where `BookingDto` wants a nested `attendee` — and every test\npassed, because they only ever checked that the tools existed. Adding or\nchanging a tool means pinning its request against the route in `apps/api`.\n",
  "bytes": 15918,
  "sha": "1411dc3f244581fad09f8b99599a6b04102cf4b40df3315178bd997ab65b6369",
  "repo_slug": "meetergo/meetergo-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_com_meetergo_mcp_server_077fc8f5/readme"
}