Reference
MCP tools reference
Ellivate's MCP server exposes two flavors of tools to your AI coding tool. **Guidance** tools (eight of them: persistence, blob storage, collections, reasoning, time, notifications, user-auth, import-path) return formatted instructions the LLM follows while writing code. **Action** tools (six of them: doctor, publish, list-apps, get-app, connect-secret, viewer) talk to the Ellivate cloud directly. Together they mean the LLM produces Ellivate-ready code from the first prompt and can publish without leaving the IDE.
Install
Pick your AI tool:
- Claude Code:
claude mcp add ellivate --scope user --transport stdio -- npx -y @ellivateai/mcp-server - Cursor: Settings → MCP Servers → Add; command
npx -y @ellivateai/mcp-server, transport stdio. - Windsurf: edit
~/.codeium/windsurf/mcp_config.json— see the walkthrough.
The tools
ellivate_user_auth
Returns the Ellivate identity pattern. The LLM calls this before writing any sign-in / session / auth-related code. Teaches:
- No third-party auth libraries (NextAuth, Clerk, Firebase Auth, etc.) — they fight the shared-shell.
- No
/login//signup//auth/callbackroutes. - Viewer identity comes from the Ellivate SDK —
ellivate.viewer()in both JS and Python. - Shape:
{ id, email, username, verified }ornullfor anonymous.
Input: none.
Output: Markdown-formatted guidance the LLM incorporates into its code.
ellivate_persistence
Returns the KV storage pattern. The LLM calls this before writing any data-reading / data-writing code. Teaches:
- Don't use
localStorage, files,sqlite3,IndexedDB,redux-persist, or any persistence plugin. - Use
ellivate.kv.get/set/delete/list. The key prefix sets the scope, resolved deterministically at runtime — no scope argument. No prefix orpersonal:is "just for you" (private per viewer, the default);shared:is "shared with this group";public:is "anyone who opens it." Forget the prefix and the data stays private. - Concrete code examples for JS/TS and Python.
Input: none.
Output: Markdown-formatted guidance.
ellivate_collections
Returns the "many similar things" pattern. The LLM calls this whenever the data shape is a list of items you'd want to filter, sort, paginate, or address by id — a roster, a feed, a list of expenses, a stack of calendar events. Teaches:
- Don't model many-similar-rows as sqlite +
INSERT/SELECTloops, or as a list-of-dicts in a single KV value, or as the prefix-key workaroundellivate.set("things:" + i, ...)in a loop. - Use
ellivate.collection(name).add/list/get/update/replace/delete— platform-assigned ids, native filtering, pagination. - Scope works the same as KV — by prefix on the name. No prefix or
personal:is private per viewer (the default);ellivate.collection("shared:trips")is shared with the group;public:is readable by anyone. No scope argument — the prefix is it. - Reserved field names (
id,createdAt,updatedAt) and v1 limits onwhere/sort.
Input: none.
Output: Markdown-formatted guidance.
ellivate_reasoning
Returns the LLM-completion pattern. The LLM calls this before writing any code that imports a provider SDK (@anthropic-ai/sdk, openai, @google/genai, langchain, etc.) or when the user describes the task as "extract from text", "summarize", "classify", "draft a reply", etc. Teaches:
- Don't import provider SDKs directly — that requires per-app env vars and the user manages a key per tool.
- Use
ellivate.reason({ prompt, system?, model?, maxTokens? })— single-shot completion via the owner's BYO API key, proxied server-side. One key in account settings; every tool benefits. - Model registry: model name picks the provider (
claude-*→ Anthropic,gpt-*→ OpenAI,gemini-*→ Google). Omitmodelfor the cheapest default. - Per-app monthly soft cap (default $5) with
warningfield surfacing on threshold; never refuses.
Input: none.
Output: Markdown-formatted guidance.
ellivate_time
Returns the scheduling pattern. The LLM calls this before writing any code that runs on a recurrence, fires after a delay, or needs to schedule something for a specific datetime. Triggers: setInterval / setTimeout for app logic that should survive restarts, node-cron, apscheduler,celery beat, croniter, BullMQ schedules, AWS EventBridge, Vercel Cron Jobs, OR user phrasing like "every Monday", "daily at 9am", "remind me in 7 days", "weekly digest", "before the event". Teaches:
- Use
ellivate.schedule.{at, cron, in}— the platform calls back to your handler at the scheduled time. - What the handler receives:
{ scheduleId, firedAt, data }body + schedule-fire / app-id / viewer-token headers. - All times UTC; min interval 1 minute; per-app cap 1000 schedules; per-app fire rate 1000/hour soft; auto-pause after 5 consecutive failures.
- Don't embed large state in
data(16KB cap). Reference by id, look up in the handler.
Input: none.
Output: Markdown-formatted guidance.
ellivate_blob_storage
Returns the binary-storage pattern. The LLM calls this before writing any code that handles photos, audio, files, or other binary uploads. Teaches:
- Don't base64-encode files into
ellivate.set— KV is capped at 256KB per value. - Use
ellivate.blob.put/get/list/delfor bytes up to 25MB. The proxy URL goes in KV alongside any metadata. - How
FileReader.readAsDataURL,canvas.toDataURL, andbase64.b64encodepatterns map toblob.put.
Input: none.
Output: Markdown-formatted guidance.
ellivate_notifications
Returns the canonical ellivate.notify(...) server-side pattern. The LLM calls this before reaching for expo-notifications, OneSignal, Firebase Cloud Messaging, web-push, the browser Notification API, or APNs. Also fires on natural intent: "send me a push when X", "remind me when Y", "ping me about Z". Teaches:
ellivate.notifyis server-only — calling from a'use client'component or vanilla browser script throws synchronously and the publish-time scanner flags it.- Targeting forms: omitted (current viewer),
"owner",{ username | userId | email },{ spaceId: "..." }(posts to that Space's chat, rendered as a card — the tool must be attached to that Space), or{ space: "current" }(the Space the tool was opened from, resolved server-side — loud-fails with a 400 if the tool wasn't opened from a Space; the default form for "post to this Space"). - Rate limits exist (5/hour per pair, 100/hour per app) — no
setInterval(notify, ...). - Why no native push libs work: App Store guideline 4.7 prohibits native bridges in WebView.
Input: none.
Output: Markdown-formatted guidance.
ellivate_connections
Returns the canonical ellivate.connection(name) managed-OAuth pattern. The LLM calls this BEFORE writing or refactoring any code that talks to a third-party system with an OAuth-authenticated API — Google Calendar / Drive / Gmail, Slack, Notion, Linear, GitHub, Spotify, Strava. ALSO fires on direct provider-SDK imports (googleapiclient, googleapis npm, @slack/web-api, notion-client), on raw OAuth code (fetch("oauth2.googleapis.com/token") refresh, redirect-handler routes), and on natural intent like "add to my calendar", "sync with Google Calendar", "post to Slack", "create a Notion page". Teaches:
ellivate.connection(name)is sync + lazy — returns a handle whose.fetch()/.fetchJson()attach a valid auto-refreshing OAuth token.- The curated integration list —
google-calendar,google-drive,google-sheets,slack,stravaat time of writing. Inventing keys (notion,whoop, etc.) throws at runtime. - PERSONAL (default) = per-viewer, lazy at runtime. SHARED = builder-owned, blocks publish until connected.
EllivateConnectionNeededexception surfaces a "connect your account" prompt — must not be swallowed.- Retrofit pattern for raw
googleapiclient/googleapisnpm usage: refactor toellivate.connection, drop the SDK from dependencies.
Input: none.
Output: Markdown-formatted guidance.
ellivate_import_path
Given the current file's path relative to the project root, returns the correct relative import specifier for the Ellivate SDK. Prevents the classic bare-specifier bug (from "ellivate-client") that breaks npm ci.
Input: { filePath: string } — e.g. "app/dashboard/page.tsx".
Output: the relative import specifier — e.g. "../../ellivate-client".
How the LLM uses them
A typical flow:
- You prompt: "Build a reading tracker for Ellivate with personal books per user."
- The LLM calls
ellivate_user_authto learn the identity pattern. Output says "no login route, useellivate.viewer()". - The LLM calls
ellivate_persistenceto learn the storage pattern. Output shows the KV SDK signatures and the scope prefixes — private by default,shared:to share with the group. - The LLM calls
ellivate_import_pathwith the file it's writing (e.g."app/page.tsx"). Output:"../ellivate-client". - The LLM writes code that follows the conventions, using the returned import path.
- You run
ellivate publish. No translator rewrites needed; the code was already shaped right.
Source
The MCP server is open source. Tool implementations live in packages/mcp-server/src/tools/ in the Ellivate repo.
Guidance tools (return formatted instructions for the LLM):
persistence.ts— KV guidanceblob-storage.ts— binary file storagecollections.ts— Memory:S structured listsreasoning.ts— LLM calls viaellivate.reasontime.ts— cron / scheduled handlers viaellivate.schedulenotifications.ts— push deliveryuser-auth.ts— identity guidanceimport-path.ts— relative-path resolver
Action tools (talk to the Ellivate cloud):
doctor.ts— diagnose a publish or app healthpublish.ts— publish the current projectlist-apps.ts— list the user's appsget-app.ts— fetch one app's detailsconnect-secret.ts— wire up a connectionviewer.ts— get the signed-in viewer
Tool descriptions are kept in sync with Ellivate's server-side translators — when a pattern changes on one side, it changes on the other.
What's next
- Install + use MCP walkthrough
- App contract reference — the full specification the MCP tools teach.