MCP Server
Kitbase speaks MCP (Model Context Protocol). Connect it to claude.ai, Claude Code, Cursor, or any MCP-compatible client and ask questions about your traffic, events, users, sessions, AI visibility, and bot traffic in natural language. Over an OAuth connection it also exposes management tools — add AI-visibility competitors and prompts, start scans and site audits, build workflows, manage webhooks and team members.
The server is built into the Kitbase API — there is nothing to install or run.
https://api.kitbase.dev/mcpSelf-hosted deployments serve the same endpoint at https://<your-host>/api/mcp.
No Dashboard Required
Once connected, your AI assistant can answer questions like "How many visitors are on the site right now?" or "Which domains does ChatGPT cite instead of us?" by querying Kitbase directly — and, on an OAuth connection, act on requests like "Add Vercel as a competitor we track in AI answers."
Authentication
The server accepts two kinds of credentials. Both are scoped to exactly one project — tools default to it, so no organization parameter is ever needed (project-scoped tools do accept an optional projectId to target another project in the same organization).
| Method | Best for | How |
|---|---|---|
| OAuth | claude.ai / Claude Desktop connectors | Add the server URL as a custom connector; a browser window asks you to sign in and pick the org + project to grant access to |
| Private API key | Cursor, headless clients | Send Authorization: Bearer sk_kitbase_... (or X-API-Key) with each request |
Read tools work with either credential. Management tools work only over OAuth: each one checks the signed-in user's live permission (the same permission the dashboard enforces, capped by what the connection was granted). A private API key carries no user to check, so key-authenticated calls to management tools are rejected.
WARNING
Private API keys (sk_kitbase_) are secret keys — not the public SDK token used in browser SDKs. Generate one in your Kitbase dashboard under Project Settings > API Keys.
Revoking a connection
Revoke an OAuth connection from the dashboard under Account Settings → MCP Connections. Revocation takes effect on the connection's next token refresh, and the connection cannot renew itself afterwards.
Refresh tokens rotate on every use and are single-use. If a rotated token is ever presented again — the signature of a copied credential — the whole connection is revoked immediately rather than renewed, so a leaked token buys at most one refresh before both parties are cut off. Nothing is required of you for that to happen.
Client Setup
claude.ai (web / desktop)
- Go to Settings > Connectors > Add custom connector
- Enter
https://api.kitbase.dev/mcp - Complete the sign-in flow and choose the organization and project to connect
Claude Code
claude mcp add --transport http kitbase https://api.kitbase.dev/mcp \
--header "Authorization: Bearer sk_kitbase_your_key_here"Cursor
Add to your Cursor MCP settings (.cursor/mcp.json):
{
"mcpServers": {
"kitbase": {
"url": "https://api.kitbase.dev/mcp",
"headers": {
"Authorization": "Bearer sk_kitbase_your_key_here"
}
}
}
}Other MCP Clients
The server speaks the standard MCP Streamable HTTP transport. Any client that supports remote MCP servers works — point it at the URL and supply either credential.
Discovery
Clients and agents that look for MCP servers automatically, rather than being handed a URL, find Kitbase through the standard discovery documents. None of them require authentication.
| Document | URL | Media type |
|---|---|---|
| Server card — name, version, description, transport, how to authenticate (SEP-2127) | https://api.kitbase.dev/mcp/server-card | application/mcp-server-card+json |
| AI catalog — the domain-level index that points at the server card | https://kitbase.dev/.well-known/ai-catalog.json and https://api.kitbase.dev/.well-known/ai-catalog.json | application/ai-catalog+json |
Protected-resource metadata — which authorization server protects /mcp (RFC 9728) | https://api.kitbase.dev/.well-known/oauth-protected-resource/mcp | application/json |
Authorization-server metadata — authorize/token/revocation endpoints, PKCE, scopes_supported (RFC 8414) | https://api.kitbase.dev/.well-known/oauth-authorization-server | application/json |
An unauthenticated request to /mcp is answered with 401 and a WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp" header, which is how an OAuth-aware client finds its way to the consent flow without any configuration. The server card carries the same facts in one place:
curl -s -H "Accept: application/mcp-server-card+json" https://api.kitbase.dev/mcp/server-card | jq '.remotes[0]'The card deliberately does not list tools — they depend on what the connection was granted, so clients read them at runtime with tools/list. The REST side of the same platform is described by the OpenAPI spec, which also documents POST /mcp with its OAuth security scheme.
Available Tools
The server exposes 180 tools. Most are reads for querying analytics, reports and configuration; the rest are management tools that change configuration — AI-visibility setup and runs, site audits, webhooks, projects, team, and workflows. Analytics data itself (events, sessions, visitors) can never be modified or deleted through MCP.
The tables below cover the tools you are most likely to reach for. Your client's own tool list is the complete one — ask your assistant to list the Kitbase tools if you want to see everything it has.
Unless noted otherwise, every tool accepts the standard date parameters described in Date Filtering: preset, from and to.
Web Analytics
| Tool | Description | Extra parameters |
|---|---|---|
get_web_summary | Summary KPIs — visitors, pageviews, bounce rate, average duration | filters |
get_web_timeline | Visitors/pageviews as a time series | interval (hour/day/week/month), filters |
get_web_breakdown | Break down by dimension (COUNTRY, BROWSER, OS, DEVICE, PATH, REFERRER, …) | dimension (required), page, size, filters |
All three also take the period comparison parameters, so "how does this week compare to last?" is one call rather than two.
dimension is a closed set, and the tool schema lists it, so an assistant picks from it rather than guessing. There is no page dimension — pages are PATH, ENTRY_PAGE, EXIT_PAGE and TOP_PAGE. The full set:
DEVICE, BROWSER, BROWSER_VERSION, OS, OS_VERSION, BRAND, MODEL, COUNTRY, REGION, CITY, UTM_SOURCE, UTM_MEDIUM, UTM_CAMPAIGN, PATH, ENTRY_PAGE, EXIT_PAGE, TOP_PAGE, REFERRER, TOP_REFERRER, OUTBOUND_LINK, CUSTOM_EVENTS, EVENT_NAME, USER.
The REST API takes the same dimensions in lower case (top_page); over MCP either spelling is accepted.
Custom Events
| Tool | Description | Extra parameters |
|---|---|---|
list_events | List raw tracked events | event, channel, userId, filters, page, size, sort (desc default, asc) |
get_event_stats | Grouped event counts | groupBy (event default, channel, user), channel |
get_event_timeline | Event counts over time | interval, event |
get_event_breakdown | Break events down by dimension (EVENT_NAME, USER, COUNTRY, …) | dimension (required), limit |
Users
| Tool | Description | Extra parameters |
|---|---|---|
list_users | List/search aggregated user analytics | type (all/identified/anonymous), search, filters, page, size |
get_user_summary | Comprehensive single-user summary | userId (required) |
get_user_activity | Daily activity heatmap for one user | userId (required), months (default 4); no date params |
get_user_events | Paginated event timeline for one user | userId (required), page, size; no date params |
Sessions
| Tool | Description | Extra parameters |
|---|---|---|
list_sessions | List aggregated sessions | search, filters, page, size |
get_session_detail | Single session details (metadata only) | sessionId (required); no date params |
get_session_events | Events inside one session | sessionId (required), page, size; no date params |
Funnels & Journeys
| Tool | Description | Extra parameters |
|---|---|---|
analyze_funnel | Ad-hoc funnel: conversion + drop-off per step | steps (required — ordered list of {type, value, name?, filters?}), analysisMode (session/user) |
analyze_journey | Most common multi-step event sequences | steps (count, default 3), limit (default 100) |
Frustration Signals
| Tool | Description | Extra parameters |
|---|---|---|
get_frustration_signals | Rage clicks and dead clicks, with top pages/elements | limit |
Retention
| Tool | Description | Extra parameters |
|---|---|---|
get_retention | Cohort retention: visitors grouped by the week/month of their first visit, with the share still active in each following period | interval (week default, or month) |
Cohorts are anchored to each visitor's first visit ever, not the first visit inside the requested window, so long-standing visitors are never counted as new. Offset 0 is the cohort itself (100%). The date range selects which cohorts are returned.
Realtime
| Tool | Description | Extra parameters |
|---|---|---|
get_realtime_visitors | Distinct visitors active right now | windowMinutes (1–60, default 5); no date params |
AI Visibility
How often your brand appears in AI search answers (ChatGPT, Gemini, Perplexity, Claude), which domains those answers cite, and how you stack up against competitors.
Most of these tools accept a providers filter — a list of platforms such as ["CHATGPT", "GEMINI"], where omitting it means every platform — and a jobs parameter, how many of the most recent scan jobs to aggregate when no date window is given (default 10). Six of them also take the period comparison parameters, which need a date window rather than a jobs count.
| Tool | Description | Extra parameters |
|---|---|---|
list_ai_brands | Configured brands (yours + competitors) | none |
list_ai_prompts | Prompts tracked against AI platforms | none |
list_ai_topics | Prompt topics (thematic groupings of prompts) | includeArchived (default false); no date params |
get_ai_visibility_series | Visibility score over time | providers, limit (default 30) |
get_ai_visibility_domains | Domains AI answers cite, ranked by citation share | providers, jobs, limit (default 25) |
get_ai_cited_pages | The specific pages (URLs, with titles) AI answers cite, ranked by citation count | providers, mentioningBrand, topicIds, jobs, limit (default 25) |
get_ai_competitors | Your brand vs competitors (mentions, sentiment) | providers, jobs, limit |
get_ai_share_of_voice | Your share of all brand mentions over time | providers, jobs |
get_ai_prompts_breakdown | Per-prompt: did the brand appear in each provider's answer | jobs |
Bot & AI-Crawler Traffic
Which bots and AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Googlebot, …) hit your site, from where, and what they read.
| Tool | Description | Extra parameters |
|---|---|---|
get_bot_timeline | Bot requests over time, grouped by vendor | interval |
get_bot_countries | Per-country bot traffic (requests + distinct bots) | page, size (default 8) |
get_top_bots | Top bots ranked by request count | size (default 10) |
get_bot_top_paths | Pages most requested by bots | size (default 10), vendor (e.g. GPTBot) |
All four also take the period comparison parameters, which is how "is ChatGPT crawling us more than last month?" gets answered in one call.
Backlinks
Referring domains detected from the project's real traffic — search engines, social networks, AI assistants, and self-referrals are excluded. These tools use a days window instead of the standard date parameters.
| Tool | Description | Extra parameters |
|---|---|---|
list_backlinks | Referring domains with referred-visit counts | status (all default, active, ignored, lost, untapped), sort (first_seen default, sessions), q (domain search), days (default 30), page, size |
get_backlink_detail | One referring domain: daily visit timeline, landing pages, and the linking-page URLs | domain (required), days (default 30) |
get_backlink_reclamation | Dead pages that still receive referral traffic — backlinks recoverable with a redirect | days (default 90) |
get_backlink_opportunities | Domains AI answers cite where your brand is absent — sites worth earning a link from; requires AI Visibility to be configured | jobs, limit (default 25) |
Content Recommendations
| Tool | Description | Extra parameters |
|---|---|---|
get_content_recommendations | AI-generated create/update-page recommendations, each with the analytics, AI-visibility, and SERP facts it is grounded in | status (SUGGESTED/ACCEPTED/DONE/DISMISSED, default all), page, size; no date params |
Workflow Reads
Workflows are the automations built on the dashboard's workflow canvas. These reads require workflow.view; the tools that change a workflow are under Workflows. None accept date parameters.
| Tool | Description | Extra parameters |
|---|---|---|
list_workflows | The project's workflows with their status (DRAFT, ACTIVE, PAUSED, ARCHIVED); graphs omitted | page, size (default 20) |
get_workflow | One workflow with its full graph — every step, its config, and the connections between them | workflowId (required) |
list_workflow_step_types | The catalog of step types: what each does, the payload types its inputs accept and its outputs emit, whether it costs AI credits, and every config key it takes | none |
list_workflow_runs | A workflow's runs, most recent first, with status, trigger, cost and any error | workflowId (required), page, size |
get_workflow_run | One run in detail: every step's status, what arrived on its inputs, what it emitted, and why it failed or was skipped | workflowId, runId (required) |
Site Audit Reads
Everything a site audit produced. All of them require siteaudit.view, and none accept date parameters.
Each report tool takes an optional auditId and falls back to the project's most recent audit of its own website, so an assistant that has just been told about an audit does not need a second call to name it. An audit can be pointed at any address, and a competitor's report is never what an unqualified question means — so reading one means naming its id, which list_site_audits returns. There is no living page inventory behind these — every answer comes from one run's snapshot, so two figures read together were measured by the same crawl.
| Tool | Description | Extra parameters |
|---|---|---|
list_site_audits | Recent audits, most recent first | limit (default 10) |
get_site_audit_worklist | The whole audit as one table to work through, worst first: every failed rule with why it matters, how to fix it, how many pages carry it, and the first few of those URLs. list_site_audit_issues plus the first page of list_site_audit_issue_pages for every rule, in one call — the place to start when the task is "fix what the audit found" | auditId, limit (default 20, max 100), examplesPerIssue (default 3, max 10) |
get_latest_site_audit | The most recent audit of the project's own website: weighted AI-readiness score, the 16-item scorecard, headline crawl statistics | includeExternal (default false) |
get_site_audit | One audit in full, by id: which site it ran against and whether that is your own, the score and its category scores, the scorecard's verdicts, which checks the run was narrowed to, headline statistics | auditId |
get_site_audit_summary | One audit's headline statistics: pages crawled, issues by severity, average response time, and how many pages came back blocked, broken or erroring | auditId |
list_site_audit_issues | What the audit found, one row per rule, worst first — why it matters, how to fix it, how many pages it affects | auditId |
list_site_audit_checks | Every check the audit graded, worst first, including the ones that hold up — each with what this run measured, how to fix it, and the pages it names. The issue tools are issues-only, so this is the only way to tell "passed" from "never ran", and the only place that reports how many checks ran at all | auditId |
list_site_audit_performance | Lighthouse measurements, one row per page and device: performance, accessibility, SEO and best-practices scores plus LCP, FCP, CLS, TBT, TTFB and Speed Index | auditId, device, band, failuresOnly, sort, q, page, size |
get_site_audit_performance_page | One measurement with the audits it failed, worst first — what Lighthouse objected to (render-blocking resources, unsized images, long main-thread work), not just the score it ended on | resultId (required), auditId |
list_site_audit_duplicates | Pages that say the same thing, clustered by meaning and tightest first. NEAR_DUPLICATE is two pages that are nearly the same page — the ones worth merging or canonicalising; RELATED is normal for a site about one subject | auditId |
list_site_audit_issue_pages | The pages behind one issue. Pass both source and findingId exactly as list_site_audit_issues returned them — a rule id is only unique within its source | source and findingId (both required), auditId, page, size |
list_site_audit_crawled_pages | The page-by-page snapshot of one audit's crawl: status, title, word count, images missing alt text, response time, crawl depth, issue count | auditId, status, sort, q, page, size |
list_site_pages | The same page list for the project's latest completed audit of its own website — the shortcut for "what does our site consist of right now" | page, size, sort, filter, q |
get_site_audit_page | Everything one audit knows about one page: what the crawl measured, which checks it failed and what each found, how a model read it, and the nearest pages by meaning. Address it by url or by the pageId from list_site_audit_crawled_pages | url or pageId (one required), auditId |
get_page_content | The same page detail for the project's own site, addressed the way a person names it — by path | path (required), e.g. /pricing |
sort takes URL, STATUS, SPEED, WORDS or DEPTH (default URL). The status filter — status on list_site_audit_crawled_pages, filter on list_site_pages — takes ALL, OK, REDIRECT, BROKEN, SERVER_ERROR, BLOCKED or MISSING (default ALL). q is a case-insensitive substring match on the URL.
On list_site_audit_performance, device takes ALL, MOBILE or DESKTOP, band takes ALL, GOOD, NEEDS_WORK or POOR, and sort takes PERFORMANCE, URL, LCP, CLS or TTFB (default PERFORMANCE, worst first).
Two empty answers mean "did not run" rather than "nothing found": no Lighthouse rows means no measurement happened — no provider configured, or the audit predates it — not that the pages are fast, and list_site_audit_duplicates reporting pagesCompared: 0 means the similarity pass never ran, not that no page repeats another.
A project with no finished audit has no pages
list_site_pages and get_page_content read stored rows only. If the project has never completed an audit of its own website there is nothing to read — start one with start_site_audit first. A path nobody crawled is reported as not found rather than as an empty page, because "we looked and there is nothing there" and "we never looked" are different answers.
Reviewing a Draft Before You Publish
Every tool above reads a crawl, so the earliest they can see an article is after it is live — and by then the expensive mistake is already quotable. audit_draft takes the file instead: your agent reads the draft off disk, passes the text, and gets back the checks the site audit runs on a published page, plus the one only a pre-publish review can make — whether the draft contradicts something your site already says.
| Tool | Description | Extra parameters |
|---|---|---|
audit_draft | Review an unpublished article: the prose checks the page report runs, plus the figures, structure words and titles it would contradict on the live site | content (required), format (markdown/html, detected when omitted), title, metaDescription, path, auditId |
Requires siteaudit.view. Nothing is stored: the draft is read, graded and forgotten. The dashboard runs the same review on the same endpoint — Website Scan → Review a draft — for the times nobody is at a terminal.
"Audit blog/ai-visibility.md before I publish it"Pass the text, not a path. The server cannot read your disk — the client opens the file. Markdown front matter is read for title and description, so a normal blog file needs nothing else; path is worth passing when you know where the piece will live, because it enables the check against the page already at that address.
The response answers "publish or not" first and gives the reasons under it:
| Field | What it says |
|---|---|
verdict | BLOCK only when the draft contradicts the published site. A thin description or a missing opening answer is a fix, not a contradiction, and comes back WARN; CLEAR means nothing this review can see would be contradicted |
summary | One line: contradictions, what to fix, what is worth a look, and how many checks hold up |
checks[] | Every graded line — passes included — with status (FAIL/WARNING/PASS/INFO), what was measured, and what to do about it |
comparedSite | The audit the draft was read against and how many pages that comparison saw. null when the project has no completed audit of its own site |
comparisonNote | Why the comparison is missing or partial, when it is |
onlyAfterPublishing | The checks this review deliberately does not answer |
What it grades depends on what you send. A markdown file is the prose you own, so it is graded on the opening answer, question headings, statistics, heading order, lists and tables, length, title, description and image alt text. Structured data, social tags and the byline belong to the template that renders it — asked only of an HTML draft, which is the whole page. Internal versus outbound links need to know which host is yours, so they are graded only when there is an audit supplying the domain.
A CLEAR draft is not a clean audit
onlyAfterPublishing exists because a file cannot answer everything: HTTP status, the canonical tag, sitemap membership, whether AI crawlers are allowed in, and whether anyone has cited the page are all properties of a live URL. Review the draft here, then audit the page once it ships.
Without a completed audit of your own website the contradiction half cannot run — the prose checks still do, and comparisonNote says exactly that. start_site_audit fixes it.
Configuration Reads
Unlike the analytics reads above, these expose org/project configuration, so each requires the same view permission its dashboard page enforces. None accept date parameters.
| Tool | Description | Permission | Extra parameters |
|---|---|---|---|
list_projects | All projects in the connected organization | project.read | none |
list_webhooks | The organization's webhooks | webhook.view | page, size (default 50) |
Management Tools
These tools change configuration — never analytics data. They work only over an OAuth connection (see Authentication): each checks the listed permission on the signed-in user and fails without it; private-API-key calls are rejected.
AI Visibility Setup & Runs
All of these require the aivisibility.manage permission.
| Tool | Description | Parameters |
|---|---|---|
add_ai_brand | Add a brand — your own (isSelf: true, only one allowed) or a competitor | name (required), primaryDomain, isSelf, aliases, excludedTopicIds |
add_ai_competitor | Add a competitor brand — shorthand for add_ai_brand without isSelf | name (required), primaryDomain, aliases, excludedTopicIds |
update_ai_brand | Edit a brand's name, domain, aliases or topic scope, or (de)activate it | brandId, name (required), primaryDomain, active, aliases, excludedTopicIds |
delete_ai_brand | Delete a brand | brandId (required) |
Scoping a competitor to certain topics. excludedTopicIds takes topic ids from list_ai_topics and mutes that competitor for them: it is treated as absent from every answer on those topics, so they leave its visibility rate and its share of voice, and it drops out of the leaderboard and charts whenever results are filtered to one. Resolve the topic name to an id with list_ai_topics first, and read a brand's current scope from list_ai_brands.
The set is replaced wholesale, so send the full list. On update_ai_brand, omitting the parameter leaves the current scope untouched — unlike aliases, which clears when omitted — so editing a name can't wipe a scope set in the dashboard. Send an empty array to deliberately track the competitor everywhere again. It is rejected for your own brand. | add_ai_prompt | Add a prompt tracked across answer platforms | text (required), locale (default en-US), topicId, personaId | | update_ai_prompt | Edit a prompt's text or locale, or (de)activate it. It cannot change the topic or persona — use the two tools below | promptId, text (required), locale, active | | move_ai_prompts_to_topic | File prompts under one topic, or take them out of every topic by omitting topicId. Pass one id to move one prompt; all or nothing across the list | promptIds (required, ≤500), topicId | | assign_ai_prompt_persona | Assign one persona to prompts, or unassign them by omitting personaId. Never touches their topic or text | promptIds (required, ≤500), personaId | | delete_ai_prompt | Deactivate (remove) a prompt | promptId (required) | | add_ai_topic | Create a prompt topic (thematic grouping) | name (required) | | update_ai_topic | Rename a topic | topicId, name (required) | | delete_ai_topic | Archive a topic — its prompts become uncategorized; historical runs keep the topic | topicId (required) | | suggest_ai_prompts | Generate prompt ideas for a brand — nothing is saved; pass the keepers to add_ai_prompt | brandName (required), primaryDomain, count (1–15, default 8) | | list_ai_exploration_engines | The platforms Prompt Explorer can run right now. Call it before explore_ai_prompt: this list is not the tracked-analysis platform list, and anything outside it is rejected | none | | explore_ai_prompt | Ask one question of up to 4 platforms at once and read every answer, the brands each named, and the sources it cited. Spends the organization's AI budget on every call — ask the user first, and don't loop over reworded variations: an identical question is free for 7 days, a reworded one is a fresh purchase, and a daily cap will start refusing calls. Nothing is tracked; use add_ai_prompt for a question worth monitoring | promptText, providers (required, 1–4), highlightBrand, region (US/EU), analyze (default true), runFresh | | pause_run, resume_run, cancel_run | Control an in-flight analysis run | jobId (required) |
Site, SEO & Content
| Tool | Description | Permission | Parameters |
|---|---|---|---|
start_site_audit | Start a link-following crawl and technical/SEO/AI-readiness audit of the connected project's website | siteaudit.manage | maxPages (defaults to the service setting), followLinks (default true) |
update_backlink_status | Set a backlink source to active (shown) or ignored (dismissed as noise) | backlinks.manage | backlinkId, status (required) |
update_recommendation_status | Move a content recommendation to ACCEPTED, DONE, or DISMISSED | contentrecs.manage | recommendationId, status (required), dismissedReason |
start_site_audit always audits the connected project's own website, and runs every check the server can run. Auditing somebody else's site, or narrowing a run to a subset of the checks, is a dashboard decision — an assistant cannot spend your daily allowance for audits of other websites on its own.
Projects & Organization
| Tool | Description | Permission | Parameters |
|---|---|---|---|
create_project | Create a project in the connected organization | project.create | name, projectType (required), description, websiteDomain |
update_project | Update the project's name, description, or website domain | project.update | name (required), description, websiteDomain (empty string clears it) |
update_organization | Organization settings: name, logo, 2FA requirement, data-retention notification emails | organization.update | name, logoUrl, require2fa, dataRetentionNotificationsEnabled (all optional) |
Webhooks
Webhooks are organization-scoped, not per-project.
| Tool | Description | Permission | Parameters |
|---|---|---|---|
create_webhook | Create a webhook that POSTs subscribed events to a URL | webhook.create | name, url, events (required), secret, enabled (default true) |
update_webhook | Update name, URL, events, secret, or enabled state | webhook.update | webhookId (required); the rest optional — events replaces the whole set, empty secret clears it |
delete_webhook | Delete a webhook | webhook.delete | webhookId (required) |
Workflows
Everything the workflow canvas can do: author a graph, validate it, publish it, run it. Authoring requires workflow.manage and running requires workflow.run — the same permissions the dashboard enforces — and both are held to the plan's workflow entitlements (feature enabled, active-workflow cap, monthly run allowance, AI budget).
Start with list_workflow_step_types: it returns each step type's ports (which decide what can connect to what) and its config keys, so a graph can be built without guessing. Every authoring tool returns the workflow with its updated graph.
| Tool | Description | Permission | Parameters |
|---|---|---|---|
create_workflow | Create a workflow, empty or with its steps and connections in one call. It starts as a DRAFT | workflow.manage | name (required), description, steps ({type, key?, config?}), connections ({fromKey, toKey, fromHandle?, toHandle?}) |
update_workflow | Rename a workflow or change its description; omitted fields are left alone | workflow.manage | workflowId (required), name, description |
duplicate_workflow | Copy a workflow's steps, connections and settings into a new DRAFT | workflow.manage | workflowId (required), name (defaults to "<name> (copy)") |
delete_workflow | Delete a workflow and its run history; can report that it is pending schedule teardown — retry shortly | workflow.manage | workflowId (required) |
add_workflow_step | Add a step, optionally wiring it to an existing one in the same call | workflow.manage | workflowId, type (required), config, key (defaults to the lowercased type), afterKey |
update_workflow_step | Change a step's settings; the given keys are merged into its config, and a null clears one | workflow.manage | workflowId, stepKey, config (required) |
remove_workflow_step | Remove a step and every connection that touched it | workflow.manage | workflowId, stepKey (required) |
connect_workflow_steps | Feed one step's output into another's input | workflow.manage | workflowId, fromKey, toKey (required), fromHandle (default out), toHandle (default in) |
disconnect_workflow_steps | Remove the connection(s) between two steps, leaving both in place | workflow.manage | workflowId, fromKey, toKey (required) |
set_workflow_graph | Replace the whole graph — for rebuilding rather than editing. Anything not listed is dropped | workflow.manage | workflowId, steps (required), connections |
validate_workflow | Check whether the draft could be published; returns each error pinned to a step or a connection | workflow.manage | workflowId (required) |
publish_workflow | Compile the draft, make it the live version, and start its schedule. Fails with the validation errors if it is not runnable | workflow.manage | workflowId (required) |
unpublish_workflow | Retire the live version, stop the schedule, and return the workflow to DRAFT | workflow.manage | workflowId (required) |
run_workflow | Start a run and return its id; runs are asynchronous, so poll get_workflow_run | workflow.run | workflowId (required), mode (PUBLISHED default, or DRAFT_TEST), upToStepKey (runs only that step and everything feeding it) |
cancel_workflow_run | Cancel a run that is still in flight | workflow.run | workflowId, runId (required) |
A worked example — a weekly check of the site's busiest pages, emailed out:
list_workflow_step_types → what steps exist and what they accept
create_workflow name: "Weekly page health"
add_workflow_step type: SCHEDULE_TRIGGER config: {"frequency": "WEEKLY"}
add_workflow_step type: MY_SITE_PAGES config: {"source": "TOP_TRAFFIC", "limit": 10}
afterKey: schedule_trigger
add_workflow_step type: PAGE_HEALTH_CHECK afterKey: my_site_pages
add_workflow_step type: EMAIL_DELIVER config: {"recipients": ["you@company.com"]}
afterKey: page_health_check
validate_workflow → fix anything it reports
publish_workflow → live, and running every weekTeam
| Tool | Description | Permission | Parameters |
|---|---|---|---|
invite_member | Invite a user to the organization by email, with a role | member.invite | email, roleId (required) |
cancel_invitation | Cancel a pending invitation | invitation.cancel | invitationId (required) |
change_member_role | Change a member's role | member.update_role | memberId, roleId (required) |
remove_member | Remove a member from the organization | member.remove | memberId (required) |
Common Parameters
Date Filtering
Most tools accept date filtering via either a preset or an explicit date range:
preset— one oflast_30_minutes,last_hour,today,yesterday,last_7_days,last_30_days,this_month,this_yearfrom/to— explicit date range inYYYY-MM-DDformat (inclusive)
If both a preset and explicit dates are provided, the preset takes precedence.
Every window is resolved on the server in the project's reporting timezone — the same way the dashboard resolves it. That is why a relative period should be asked for with its preset rather than with dates the assistant computes: the dashboard's Last 7 days is last_7_days (today plus the six days before it), and an assistant that sends from = today − 7, to = today instead reads one day more and reports different numbers for the same funnel. Reserve from/to for explicit calendar dates. analyze_funnel echoes the days it actually covered as from/to in its response, so the period an assistant quotes is the one the numbers came from.
For the AI visibility tools, omitting all date parameters aggregates the last jobs scan jobs instead of a time window.
Period comparison
Thirteen of the read tools answer for an earlier window in the same call, so an assistant can say what changed without running the query twice and subtracting. They do it by default; these parameters change which window:
comparePreset— one ofprevious_period,previous_week,previous_month,previous_quarter,previous_yearcompareFrom/compareTo— a custom comparison window inYYYY-MM-DDformat (inclusive); send both or neither
comparePreset takes precedence when both are given, and omitting all three compares against the previous period — an assistant gets the change for free and only names a parameter to ask for a different window. previous_period keeps the length of your window and ends where it starts; the calendar presets are instead the week, month, quarter or year running up to it, which are usually longer — so an assistant comparing a day against previous_month is comparing it with the month behind it, not with the same day a month ago. Compare to an earlier period has the full semantics, the one-year guard, and how the extra fields read.
| Area | Tools |
|---|---|
| Web analytics | get_web_summary, get_web_timeline, get_web_breakdown |
| Bots & crawlers | get_bot_timeline, get_bot_countries, get_top_bots, get_bot_top_paths |
| AI visibility | get_ai_visibility_series, get_ai_visibility_domains, get_ai_cited_pages, get_ai_competitors, get_ai_share_of_voice, get_ai_prompts_breakdown |
AI visibility comparisons need a date window
The AI visibility tools fall back to aggregating the last jobs scans when no dates are given — a count, not a period. A comparison asked for in that mode is refused rather than silently dropped, so pass preset or from/to alongside it.
Pagination
List tools support pagination with page (0-indexed) and size.
Filters
Web analytics and event tools support filters in the format dimension:operator:values:
"country:is:US,UK"
"browser:is:Chrome"
"page:contains:/blog"Pass multiple filters as an array to combine them.
Example Prompts
| Question | Tools Used |
|---|---|
| "How many visitors are on the site right now?" | get_realtime_visitors |
| "How many visitors did we get last week?" | get_web_summary |
| "Compare this week's traffic to last week by country" | get_web_breakdown with comparePreset |
| "What's our weekly retention looking like this quarter?" | get_retention |
| "Show me the signup funnel conversion rate" | analyze_funnel |
| "How visible is our brand in AI search this month?" | get_ai_visibility_series |
| "Which domains does ChatGPT cite instead of us?" | get_ai_visibility_domains |
| "What are the most cited pages for our lead-capture topic?" | get_ai_cited_pages |
| "How do we compare to competitors in AI answers?" | get_ai_competitors |
| "Is ChatGPT crawling our docs? Which pages?" | get_top_bots + get_bot_top_paths |
| "Which pages have the most rage clicks this week?" | get_frustration_signals |
| "Show me a summary of user U-123's activity" | get_user_summary |
| "Add Vercel as a competitor we track in AI answers" | add_ai_competitor |
| "Stop counting Blinq on the badge-scanning topic" | list_ai_topics + list_ai_brands + update_ai_brand |
| "Suggest prompts for my brand and track the good ones" | suggest_ai_prompts + add_ai_prompt |
| "What does AI say about us right now?" | list_ai_exploration_engines + explore_ai_prompt |
| "Run a site audit and walk me through the findings" | start_site_audit + get_latest_site_audit + list_site_audit_issues |
| "Fix everything the last audit found, in my codebase" | get_site_audit_worklist + list_site_audit_issue_pages |
| "Which pages are slowest, and what is slowing them down?" | list_site_audit_performance + get_site_audit_performance_page |
| "What's wrong with our pricing page?" | get_page_content |
| "Check this draft before I publish it" | audit_draft |
| "Which sites should we try to get links from?" | get_backlink_opportunities |
Connect external MCP servers to the assistant
The direction above is Kitbase acting as an MCP server. The project assistant can also act as an MCP client: connect any Streamable HTTP MCP server and its tools become available to the assistant in chat.
Where: Project Settings → Assistant → Connect server.
| Field | Rules |
|---|---|
| Name | 2–24 chars, lowercase letters/digits/hyphens. Immutable — it namespaces the server's tools as mcp__<name>__<tool>. |
| URL | The server's Streamable HTTP endpoint. https only. |
| Authentication | Auth header or OAuth, chosen at creation and immutable afterwards. |
| Auth header | Header connections only. Either a full Name: value line, or a bare token sent as Authorization: Bearer <token>. Stored encrypted; write-only — it can be replaced or removed, never read back. |
| Require approval | On by default: every tool call from this server pauses the chat for your approval, showing the exact arguments. Turn it off only for servers you trust. |
OAuth-protected servers
Servers that authenticate with OAuth — Atlassian's https://mcp.atlassian.com/v1/mcp/authv2, for example — need no token pasted in. Create the connection with OAuth, then press Connect: Kitbase asks the server who authorizes it, registers itself as a client, and sends you to that server's own consent screen. Approve there and you land back on the project's settings page with the connection live.
- The grant belongs to the account you approved it with, and Kitbase keeps it alive by refreshing it in the background. Tokens are encrypted at rest and are never shown, exported, or returned by the API.
- Until you complete the flow, an OAuth connection holds no credential and contributes no tools.
- If the server revokes the grant — or you remove Kitbase's access on its side — its tools stop appearing. Press Connect again to re-authorize.
- Servers that do not offer dynamic client registration cannot be connected this way; use an auth header instead.
Behavior and limits:
- Up to 10 connections per project; the first 40 tools per server are offered.
- Tool lists refresh about once a minute; an unreachable server simply contributes no tools until it answers again. Use Test to dial a connection on demand and list its tools.
- External results are treated as untrusted data by the assistant — a page or tool output cannot instruct it to change its behavior.
- Connections are project-scoped, changes are audit-logged, and creating or editing them requires the
project.updatepermission.
Requirements
- A Kitbase account with an active project
- An MCP-compatible client that supports remote servers over Streamable HTTP
- For API-key auth: a private API key (
sk_kitbase_) from Project Settings > API Keys
Next steps
- Project Assistant — the same tools, built into the dashboard, with no client to connect.
- CLI — the same operations from your terminal instead of an AI assistant, and where
kitbase loginlives. - API reference — the REST API behind every MCP tool.
- Analytics dashboard guide — the data these tools query.