Spotka speaks MCP.
Add one line to Claude, Cursor, or any app that speaks MCP, and it can find things to do, make events, and answer invitations for you, in your name, with your own account.
https://spotka.co/api/v1/mcp
It speaks MCP over plain HTTP: one POST per message, which is what Claude,
Cursor and Windsurf send. Your key travels in an X-API-Key header.
There is nothing to install and no server to run. Two protocol
versions are supported, 2025-06-18 and 2025-03-26; your
app picks one on its own.
Open Spotka on the web, Android or iPhone and go to Settings → API access → Create a key, or jump straight there:
You get a short key like spk_4KAS22M1JQFQ. It is shown once. If you
lose it, make a new one. It takes one tap, and you can revoke the old one on the
same screen.
A key belongs to one person: yours. Whatever you connect can do only what you can do in the app yourself.
claude mcp add --transport http spotka https://spotka.co/api/v1/mcp \
--header "X-API-Key: spk_XXXXXXXXXXXX"
These keep a small config file listing the MCP servers they use. Add Spotka to it:
{
"mcpServers": {
"spotka": {
"type": "http",
"url": "https://spotka.co/api/v1/mcp",
"headers": { "X-API-Key": "spk_XXXXXXXXXXXX" }
}
}
}
Then restart the app. Spotka's tools show up in its tool list.
Some apps have nowhere to put a header. Put the key in the URL instead. It works exactly the same:
https://spotka.co/api/v1/mcp?key=spk_XXXXXXXXXXXX
Treat that URL like a password, because it now contains one.
| Tool | What it does |
|---|---|
ideas | Things to do in the city, picked for you |
events | Events other members are hosting that suit you. Text search can find public events beyond your current suggestions. Filter with query or its alias search, and bound dates with date_from/date_to or starts_after/starts_before |
my_events | Events you host, events you joined, invitations waiting for you |
create_event | Add an event. Title up to 120 characters; longer is rejected, not cut short. about up to 1000 characters; longer is rejected, not cut short. Angle brackets in about are preserved, not stripped. max_guests is 2–8; out of range is rejected. capacity is accepted as the same field (the name every event read returns). when may be a weekday phrase, an ISO instant, a date-and-time with no offset (2026-09-26 18:00 is 18:00 Europe/Warsaw, the same as typing 6pm), or a dated wall-clock with an IANA zone (2026-09-10 12:00 Europe/Warsaw); starts_at/ends_at may be sent as direct ISO fields instead. An unreadable time is time_not_applied, not a guessed date. A bare number (a Unix timestamp) is time_not_applied, not converted to a date. A UTC offset no civil timezone uses (+15:00) is time_not_applied, not converted with arithmetic. Leave when and starts_at out to leave the draft with no time rather than inventing a start. where is a known public-place name, JSON with lat/lng, or later to decide with guests. A title-only create stays a draft: publishing needs a time and a place, the same as update_event |
update_event | Change an event you host: the event must be the full event id; a truncated id is invalid_event_id. Partial, so anything you leave out stays as it is. Title up to 120 characters; longer is rejected. about up to 1000 characters; longer is rejected. Angle brackets in about are preserved, not stripped. If the supplied time cannot be applied, or publish=true cannot complete, the call fails and the other fields are not changed. A when-less and starts_at-less draft stays with no time rather than inventing a start, and cannot be published until one is set. Same where shapes as create. On a published event, where= is place_not_applied (the place is fixed while it is live), not invitation_not_draft |
invite | Invite people to an event, or make the event and invite in one go. Success means a pending invitation the guest can see and answer, not just a green reply. A truncated event id is invalid_event_id, and one that does not exist is event_not_found. Neither sends anything, and neither uses any of your daily recipient allowance |
event | One event in full: lifecycle, held seats vs calendared guests, guest states, seats remaining, allowed actions. The event must be the full event id; a truncated id is invalid_event_id |
join | Take a seat at someone else's event, at the time the host set. An event with no time yet is time_not_set |
leave | Give up a seat you took. A host cannot leave their own event (cannot_leave_own_event). Archive or delete it instead. A missing event is event_not_found, not candidate_stale. The rest of the member's event suggestions stay |
respond | Accept, decline, or interested. Accept takes a seat; interested is a soft RSVP that records the person on the host's interested list without taking a seat. Changing interested to accept takes a seat; it is not already_responded. Accepting an event with no time yet is time_not_set. A never-answered invite on an archived event is event_archived (the host retired it), not already_responded. Repeating the same decision is a no-op success, not already_responded. An id that is not an event is event_not_found |
archive | Retire an event you host. The event must be the full event id; a truncated id is invalid_event_id. An event you cannot see is event_not_visible, not invitation_not_found |
delete_event | Delete an unpublished draft. The event must be the full event id; a truncated id is invalid_event_id. Already gone is event_not_found. An event you cannot see is event_not_visible, not invitation_not_found |
inbox | What is waiting: unread conversations and invitations. unread_total is global, not the page |
conversation | One conversation, oldest first, without marking it read. oldest_at is the cursor for before= |
mark_read | Mark a conversation read, on purpose |
send_message | Send a message as you. Needs a key with messaging enabled |
activity_history | What this API changed on your account, including keys you minted or revoked. succeeded=false lists only failed actions. verb narrows to one action; only actions that change something are recorded, so a read verb is refused and the error lists what you may filter by |
revoke_invite | Take back an invitation you sent. The id do=event lists is enough on its own |
calendar | What you have coming up, hosted and joined |
profile | Your own profile: public half and private context |
update_profile | Change your own profile; only the fields you name. display_name and first_name cannot be blank. Names refuse line breaks and control characters. Overlong text (bio up to 2000 characters) is rejected, not shortened. Over-long lists are rejected, not cut short (interests 40, dietary_preferences and allergies 20, languages 12). Each interests / dietary_preferences / allergies item is up to 120 characters; longer is rejected, not sliced. languages must be on the app list; invented words are invalid_languages, not stored. personal_url must be a public-page slug (invalid_personal_url). instagram, linkedin and telegram must be a handle or profile URL (invalid_social_handle). HTML tags on bio, city, company, job_title, community_goals, current_focus, allergies, linkedin and personal_url are stripped on save, the same way event titles do, rather than stored raw. List fields parse a JSON array string; invalid JSON is refused, not comma-split |
notification_settings | Which notifications you get by push and by email, and whether any device is registered to deliver them |
update_notification_settings | Turn notifications on or off, on one rail or both; only the ones you name change |
report_bug | Tell the Spotka team something is broken. Default is no auto-fix. Send autofix=true on a clear bug to send it to a coder. Duplicates fold onto the open report they match; send check_only=true to get that verdict without filing. Pass product_url, app_version, platform, and a screenshot when you have them. If you are an AI agent, send agent with your own name: the account is a shared seat and does not say who wrote the report. Poll report_status; when waiting for a re-test, call verify_bug |
report_feature | Ask for something Spotka does not do yet: same queue, same rule |
report_status | Poll a report this account filed. Omit report to list recent ones. A fleet agent may pass waiting=true to list actionable reports waiting for a re-test; each item carries verify_surface. Pass surface=api/web/ios/android/site/intranet/person with waiting=true to fetch only that lane's queue, or tier to fetch only one tester's work |
verify_bug | Use probe=true with note and dataset_version to save an own-report observation at any time or contest a closure: still_broken reopens it; works outside the queue saves evidence without verifying a fix. Normally, submit the retest verdict without the email token. verdict=works, still_broken or unverified. A fleet agent may also verify any waiting report. A cascade tester sends tier and reason, so an unverified answer passes the report to the next tester |
capabilities | What your key may do, what each tool changes in the world, and how much budget is left |
If this key belongs to a test account, report_bug and
report_feature file as soon as you observe a problem. Do not wait for a
person to confirm. Those reports show up in the review queue tagged as a test filing.
Default is no auto-fix. Send autofix=true on a clear bug to send it to a
coder. Poll report_status; when waiting for a re-test, call
verify_bug. Do not wait on email.
next Friday at 7pm,
2026-08-22T18:00:00+02:00, or
2026-09-26 18:00 (18:00 Europe/Warsaw). If the time cannot be read, or publishing
cannot complete, the tool fails and names the unmet fields rather than leaving a
silent draft.
A few more tools exist for writing test suites and work only with a test
key: actors, seed, reset,
key_list, key_create and key_revoke.
They are described in the
full API guide.
Once it is connected, just ask in ordinary words:
If you would rather not use MCP at all, the same things work with
one curl line. See the
full API guide.
They go out in your name, so it is worth telling your assistant to check with you before it invites anyone.
A name a tool does not take comes back as unknown_parameter,
naming the extra key, rather than being ignored. When the guess is close,
the hint offers the right name (q → query on
events). The call does not run.
If you are signed in as a test or bot account, file with
report_bug or report_feature as soon as something
is wrong. Do not wait for a person to confirm. The report is tagged as a
test filing. Default is no auto-fix. Send autofix=true on a
clear bug to send it to a coder. Feature requests still wait for a
person.
A bot cannot click the verification email. Poll
report_status, re-test on production
when waiting_for_retest is true, then call
verify_bug with verdict=works or still_broken.
If you could not run the re-test at all, send
verdict=unverified, which leaves the report waiting instead
of marking a fix wrong. A QA fleet agent may also pass
waiting=true on report_status to pick up reports
another person filed, then verify those after a real check. Do not wait
for the original reporter. Do not read the mailbox.
Same key, same limits as the rest of the API: a per-minute and per-day call
budget, a tighter one for events and invites, and a daily cap on people invited.
What you have left is in the X-RateLimit-Remaining header of every
reply, and X-RateLimit-Bucket names which budget it is counting:
always the one closest to running out, usually the per-minute one.
The numbers, and how long each call takes, are on the full API guide, kept in one place on purpose, so the two pages cannot quietly disagree about them. If you need more, write to support@spotka.co.
Hosted assistants can use the member-only OAuth endpoint https://spotka.co/api/v1/connector/mcp. Sign in and choose permissions when your assistant asks to connect. Disconnect through Spotka Settings → API access. Connector writes require an operation ID for safe retries.
Meta Muse and OpenAI Dots platform review is pending. The API-key connection above remains available.
Report status separates fix_merged (claimed fix) from fix_verified (successful re-probe). fix_landed is a compatibility alias for verified. API-only reporters do not need an email address to enter the retest queue. The default fleet queue excludes person-only, postponed and closed reports. Fetch waiting=true with your tier; request surface=person or tier=person explicitly to inspect work assigned to a person.