Server definition
- Hash
- sha256:06f8e131cb516b61df18f67ade7324fe560c92c0541ad7dfbb1e4ae947bf5e1d
- What it is
- What a remote MCP server returned when asked what it offers: 34 tools
The blob, as servednamed by its sha256
{
"instructions": "Kleap builds, HOSTS and AUDITS real websites (Astro). You have TWO ways to put code on a site: (A) write_files — YOUR model writes the exact file contents and you push them with write_files; Kleap stores, builds and deploys them as-is (deterministic, best when the exact wording, URL or schema matters); (B) modify_app — describe the OUTCOME and Kleap's AI writes the files (best for design and whole sections, and it knows the template's own components, auth, database and form wiring). Either way Kleap HOSTS it (build, deploy, SSL, DB, auth, domains, verified-live) and CHECKS it: publishing audits every internal link on every built page, flags pages whose content contradicts the link leading to them, and measures JSON-LD/sitemap/robots coverage — get_publish_status returns that as a report field. Read the report instead of re-auditing the site yourself. list_app_files shows the structure (Astro: src/pages/*.astro, src/data/*.json, src/components/*.astro, public/*).\n\nEDIT EXISTING FILES SAFELY — never rewrite a file blind. Do: list_app_files → read_files(app_id, [paths]) to get the CURRENT contents → edit_files to change ONLY the lines that must change → publish_app. Use edit_files whenever the file exists: send old_string and new_string, Kleap replaces in place. Resending a 30KB layout to fix one line wastes tokens and risks corrupting the rest. write_files stays for NEW files, wholesale replacement and images. This is the reliable way to fix shared components, headers/footers, wrong numbers, broken links, dead forms. read_files works with a Read-only key, so always read before you change. Prefer this read→edit→write loop over modify_app for precise, verifiable edits. That loop is complete: edit_files changes part of a file, write_files takes encoding:\"base64\" for IMAGES and binaries (logo, photo, OG image, favicon, font), and delete_files REMOVES a page or asset — never blank a file to \"delete\" it, that leaves a URL answering 200 with nothing.\n\nWHAT AGENTS ACTUALLY DO HERE (measured over 30 days of real calls): read_files 141, publish_app 70, list_app_files 36, write_files 31 — and create_app 4. This connector is used to MAINTAIN live sites far more than to create them. So the loop below leads with the edit path; creation is at the end because it is the rare case.\n\nTHE LOOP\n1. Find the site: if the user names it by address (\"serrureriesk.ch\", \"mysite.kleap.io\"), call find_app FIRST. If it returns NOT_FOUND, the site isn't on this account or isn't connected yet — fall back to list_apps or ask the user. Otherwise use list_apps.\n2. Build/change — two paths: DETERMINISTIC = read_files then edit_files(app_id, [{path, old_string, new_string}]) to CHANGE something that already exists (one line, a price, a link, a shared header — it rewrites nothing else and cannot silently drop the rest of the file), or write_files(app_id, [{path, content}]) for a file you are creating WHOLE; then publish_app(app_id) (no task, no stall, best for exact pages/scaffolding). Reaching for write_files on an existing 30KB page means retyping 30KB to change one line — that is what edit_files is for. AI = create_app(prompt) for a new site or modify_app(app_id, message) to change one. create_app returns instantly with a task_id and a build_url. modify_app does NOT: it waits for the edit to land before answering (median 55s measured in production), so treat it as a call that blocks — do not fire it and walk away, and do not re-fire it because it feels slow. HAND-OFF RULE — CREATIONS ONLY (create_app, 3-11 min): the widget shows live build progress, so give the user the build_url and do NOT block or keep polling check_task; just tell them it is building and they can ask you for the link anytime. EDITS ARE THE OPPOSITE (modify_app, usually under a minute): do NOT hand off. Call check_task once or twice until it reports deployment_status deployed, then get_app once, then answer. Watched live: answering at 17 seconds with \"it is deploying\" left the user on a build frame for a change that was finished 20 seconds later, and nothing ever went back to show it to them. STAY ENGAGED while it builds (like a real builder, not a silent wait): ask the user 1-2 short refinement questions (brand colors, must-have sections, contact details, logo) and then apply their answers with ONE modify_app once the build is live. If the first request was vague, ask 1-2 quick questions BEFORE create_app to enrich the prompt. If you have NO widget (CLI/headless/API), poll check_task (long-polls, queued/processing/completed/failed, ~5-15 min) for the finished URL.\n3. After a create_app/modify_app task status=\"completed\", the files are written; claim the change is LIVE only when deployment_status=\"deployed\". A pending or failed deployment is not live, even if production_url still contains the previous address. After write_files you MUST call publish_app to deploy. connect_domain attaches a domain the user owns (app must be live first).\n4. SHOW IT. Once the work is live (check_task returns status completed AND deployment_status deployed, or publish_app succeeded), your LAST tool call before answering must be get_app on that app_id — exactly once. That single call is the only thing that puts the finished site, its screenshot and its address in front of the user; every other tool leaves them looking at a build in progress. Do it even when you are certain it worked, even when you already have the URL in text, and even after you have verified the files yourself — verifying is for you, get_app is for them. Skip it only if the task failed.\nON FAILURE (task status=\"failed\"): read error.code/message. For a transient stall, call retry_task — it returns a NEW task_id; poll check_task on THAT new id. Retry at most once or twice; if it keeps failing or is non-transient (out of usage — check get_credits — or a rejected prompt), stop and tell the user.\n\nMANY PAGES / PROGRAMMATIC SEO: BEST = write_files — generate a dynamic Astro route (src/pages/[service]/[city].astro) + a data file (src/data/locations.json with your full list) with YOUR model, push both in one write_files, then publish_app. Deterministic, scales to thousands, no stall, uses no Kleap AI usage. ALTERNATIVE = ONE modify_app asking Kleap's AI for that same dynamic route + data file. Never make N calls (one per page) — that stalls.\n\nDATA, ACCOUNTS & FORMS (Astro, the default) — durable data NEVER lives in browser storage. Anything a person expects to keep (accounts, records, bookings, orders, listings, posts, saved results, carts) belongs in the app's first-party Kleap Database, never localStorage / sessionStorage / IndexedDB / cookies — per-device, invisible to the owner and to other visitors, wiped on cache-clear or device-switch (the #1 'my data disappeared' bug); those are fine only for a throwaway UI toggle (theme). Contact / lead / newsletter / booking forms need nothing built — hydrate the seeded island: import KleapForm from '@/components/KleapForm'; <KleapForm client:load formId=\"contact\" fields={[...]} /> collects straight to the owner's Kleap dashboard. The template already ships the data + auth wiring (getKleapDb from '@/lib/kleap-db', read inside a client:load island and RLS-scoped to the signed-in user by default; login UI @/components/auth/KleapAuth), but the database is switched ON only while a data/accounts feature is being built — and that one-time provisioning is exactly what write_files does NOT do (it only stores the files you send). So to STAND UP a data or accounts feature, use modify_app and describe the data/accounts you need: Kleap's AI owns the wiring and provisions the database automatically as it builds — no connect step, no button, no keys. DB or auth code pushed by raw write_files has no backend behind it and silently does nothing. Once the app is provisioned, keep editing those pages with the normal read->edit->write loop.\n\nrename_app changes only the display name (URL never changes). There is no tool to delete an entire app; delete_files removes selected source files.\n\nAFTER PUBLISH: use get_analytics(app_id) for visitor/pageview/top-page/referrer stats (needs the app to be published — analytics is wired automatically on deploy), get_search_console(app_id) for how the site performs IN GOOGLE SEARCH (queries it ranks for, impressions, clicks, CTR, average position — real Search Console data; if it comes back not connected, connect_search_console(app_id) hands you the Google consent link to give the user, and the property binds itself from there), and get_form_submissions(app_id) to read leads/contacts from any KleapForm-based contact form on the site. Analytics and search both need analytics:read, forms need forms:read: connections authorized BEFORE these tools shipped don't have them — a 403 INSUFFICIENT_SCOPE means the user must disconnect and reconnect (re-authorize) the Kleap integration.\n\nDATABASE (the app's Kleap Database, Postgres): get_database_schema first, then query_database_rows / insert_database_rows / update_database_rows / delete_database_rows, or run_database_sql for anything else. Reads need database:read; writes and run_database_sql need database:write. An app without a database answers not provisioned — create it with modify_app (describe the data you need), never from here.\n\nDOMAINS: search_domains finds names; buy_domain returns a Stripe checkout_url the USER must open and pay — nothing is bought until they do. Then check_domain follows it.\n\nPLAN: upgrade_plan returns an upgrade_url the USER opens to subscribe (monthly or annual) or, on a paid plan, to get more usage. Offer it when they run out of usage or ask for a paid feature such as a custom domain. Nothing is charged until they pay — never say they are subscribed.",
"tools": [
{
"description": "Start buying a domain: returns a Stripe checkout_url (valid 30 min) that the USER must open and pay. Nothing is bought until they complete checkout — give them the link, never say it is purchased. With app_id it is connected to that app after payment.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "App to connect it to",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"domain": {
"description": "e.g. 'mybakery.com'",
"type": "string"
},
"registrant": {
"additionalProperties": false,
"description": "The domain OWNER (legal registrant) — can differ from the person paying. Ask the user for it; if omitted, the payer's billing details are used.",
"properties": {
"address": {
"type": "string"
},
"address2": {
"type": "string"
},
"city": {
"type": "string"
},
"country": {
"description": "ISO 3166-1 alpha-2, e.g. FR",
"type": "string"
},
"email": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"organization": {
"type": "string"
},
"phone": {
"description": "International format, e.g. +33 6 12 34 56 78",
"type": "string"
},
"postal_code": {
"description": "Required except in countries without postal codes",
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"first_name",
"last_name",
"email",
"phone",
"address",
"city",
"country"
],
"type": "object"
},
"years": {
"description": "1-10, default 1",
"type": "number"
}
},
"required": [
"domain",
"context"
],
"type": "object"
},
"name": "buy_domain",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"checkout_url": {},
"currency": {},
"domain": {},
"expires_at": {},
"price": {},
"years": {}
},
"type": "object"
}
},
{
"description": "Check a domain's connection / DNS status for a Kleap app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"domain": {
"description": "The domain, e.g. 'mybakery.com'",
"type": "string"
}
},
"required": [
"domain",
"context"
],
"type": "object"
},
"name": "check_domain",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"checks": {},
"domain": {},
"message": {},
"status": {},
"tls": {},
"url": {}
},
"type": "object"
}
},
{
"description": "Check a create/modify task. Returns quickly with the CURRENT status — report it to the user rather than calling again in the same turn; a build takes 5-15 min, so the answer to 'is it ready?' is usually 'still building, here is the progress'. The optional `wait` can shorten the hold but cannot exceed the server cap (8 seconds by default). status is one of: queued, processing, completed, failed, unknown_task (the id is unknown or aged out — that is an answer, not a failure: check the site itself with get_publish_status). On 'completed' the FILES are written; check deployment_status — 'pending' means the site is going live right now and production_url is still the PREVIOUS version, so say 'built, going live' and check once more in about a minute rather than reporting it stuck. 'deployed' means it is genuinely live. On 'failed': TASK_TIMEOUT/STALE_TASK = transient stall → retry_task (returns a NEW task_id to poll); TASK_FAILED = read error.message, retry once. (Running out of usage is not a task failure — create/modify reject up front with 402 INSUFFICIENT_CREDITS.)",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"task_id": {
"description": "The task_id returned by create_app or modify_app",
"type": "string"
},
"wait": {
"description": "Optional. Seconds to hold the connection before returning. Capped server-side at a few seconds so the call always comes back inside a single turn — asking for more has no effect. Leave it unset.",
"type": "number"
}
},
"required": [
"task_id",
"context"
],
"type": "object"
},
"name": "check_task",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {},
"deployment_status": {},
"metadata": {},
"name": {},
"palette": {},
"plan": {},
"preview_url": {},
"production_url": {},
"progress": {},
"reason": {},
"result": {},
"screenshot_url": {},
"slug": {},
"status": {},
"task_id": {
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Connect a domain the user ALREADY OWNS to a live Kleap app (routing + automatic TLS). The app must be live first — a create_app/modify_app with deployment_status deployed already counts as published, so you do NOT need publish_app first. The user points the domain's A record to Kleap. Does not buy anything.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id (must be published)",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"domain": {
"description": "The domain to connect, e.g. 'mybakery.com'",
"type": "string"
}
},
"required": [
"app_id",
"domain",
"context"
],
"type": "object"
},
"name": "connect_domain",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"already_connected": {},
"app_id": {},
"dns_config": {},
"domain": {},
"status": {},
"warnings": {}
},
"type": "object"
}
},
{
"description": "Use this when the user wants to connect (or reconnect) Google Search Console for a site — typically right after get_search_console reported connected:false. Returns a consent_url: give it to the user as a link and ask them to open it and approve access with the Google account that owns the domain in Search Console. That one approval MUST happen in a browser — Google does not allow it any other way, so never claim you can do it for them. Nothing else is needed afterwards: the Search Console property is bound to the site's custom domain automatically, and get_search_console starts answering. If requires_custom_domain is true the site has no custom domain yet: connecting Google would grant access to nothing, so connect a domain first (connect_domain) and publish. If it reports the site is already connected, do not send anyone through consent again — just read the numbers.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id to connect Search Console for",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "connect_search_console",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"connected": {
"type": "boolean"
},
"consent_url": {},
"custom_domain": {},
"expires_in_minutes": {
"type": "number"
},
"google_email": {},
"message": {},
"requires_custom_domain": {
"type": "boolean"
},
"site_selected": {
"type": "boolean"
},
"site_url": {}
},
"type": "object"
}
},
{
"description": "Use this when the user wants a complete, hosted website or web app built from a text description (e.g. 'build me a website for X'). Kleap's AI builds AND auto-deploys the whole site; this takes a few minutes (typically 5 to 15 min). Returns a build_url instantly so the user can watch it build live. In a widget client (ChatGPT Apps) the preview above shows real-time progress and reveals the final live URL by itself, so you do NOT need to block or keep polling check_task. Prefer this over write_files for full-site creation.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"prompt": {
"description": "Detailed description of the website to build",
"maxLength": 10000,
"minLength": 1,
"type": "string"
},
"visibility": {
"default": "personal",
"description": "Controls discovery listing: public = discoverable, personal = unlisted. Both may be deployed to a publicly reachable URL; personal does not add access control.",
"enum": [
"public",
"personal"
],
"type": "string"
}
},
"required": [
"prompt",
"context"
],
"type": "object"
},
"name": "create_app",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {},
"build_url": {
"type": "string"
},
"name": {
"type": "string"
},
"status": {
"type": "string"
},
"task_id": {}
},
"type": "object"
}
},
{
"description": "Delete the rows matching where (required, non-empty, exact matches, e.g. {\"id\":42}). Permanent. Returns how many were deleted.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"table": {
"description": "Table name (public schema)",
"type": "string"
},
"where": {
"additionalProperties": {},
"description": "Which rows (required)",
"type": "object"
}
},
"required": [
"app_id",
"table",
"where",
"context"
],
"type": "object"
},
"name": "delete_database_rows",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"deleted": {},
"table": {}
},
"type": "object"
}
},
{
"description": "Remove pages, components or assets from a site — the counterpart to write_files. Use it when a page should no longer exist: a wrong route, a duplicate, an outdated landing page, an image nobody references. Do NOT overwrite the file with empty content instead: that leaves a URL answering 200 with nothing, which is worse for SEO than a clean 404. Deleting a binary also removes its stored bytes. Paths Kleap owns (astro.config.mjs, package.json, tsconfig.json…) are refused — the build lays its own copy back down, so removing them changes nothing. The homepage (src/pages/index.astro) is refused too: a site with no homepage is broken — write a new one instead, writing replaces it. Returns which paths were actually deleted and which did not exist. The pages STAY LIVE until you call publish_app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"paths": {
"description": "Project-relative paths to delete, e.g. [\"src/pages/old.astro\", \"public/images/unused.png\"]",
"items": {
"type": "string"
},
"minItems": 1,
"type": "array"
}
},
"required": [
"app_id",
"paths",
"context"
],
"type": "object"
},
"name": "delete_files",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"deleted": {},
"missing": {}
},
"type": "object"
}
},
{
"description": "Change PART of a file without resending it — the counterpart to write_files. Give `old_string` (exact text as in the file today) and `new_string`; Kleap reads, replaces, stores. Nothing else moves. Use it whenever the file exists and only a line, block or URL changes: resending a 30KB layout to fix one line wastes tokens and risks corrupting the rest. read_files first, copy the text EXACTLY. `old_string` must appear once — otherwise the error names the count; add context or pass replace_all:true. Edits are validated together: if any is invalid, nothing is written. Across files the writes are sequential — a late failure names what was already applied. new_string \"\" deletes the match. Not for new files or binaries. Then publish_app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"edits": {
"description": "Edits, in order. Validated before any write.",
"items": {
"additionalProperties": false,
"properties": {
"new_string": {
"description": "Replacement text. \"\" deletes the match.",
"type": "string"
},
"old_string": {
"description": "Exact text to find, copied from the file. Must appear once unless replace_all.",
"minLength": 1,
"type": "string"
},
"path": {
"description": "Project-relative path of an EXISTING file",
"type": "string"
},
"replace_all": {
"description": "Replace EVERY occurrence instead of requiring a unique match.",
"type": "boolean"
}
},
"required": [
"path",
"old_string",
"new_string"
],
"type": "object"
},
"minItems": 1,
"type": "array"
}
},
"required": [
"app_id",
"edits",
"context"
],
"type": "object"
},
"name": "edit_files",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"edited": {},
"edits": {},
"paths": {}
},
"type": "object"
}
},
{
"description": "Resolve a website the user refers to by its ADDRESS — a custom domain ('mysite.ch'), a kleap.io URL ('mysite.kleap.io'), or a slug — to its app_id. Use this FIRST whenever the user names a site by its address instead of an app_id (e.g. 'edit mysite.ch'), then pass the returned app_id to get_app / modify_app / publish_app. ADDRESS TO SHOW THE USER: site_url. When the owner has connected a domain, custom_domain is set and site_url is that domain — say THAT, never the {slug}.kleap.io host, which is the internal address they did not choose.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"query": {
"description": "A domain, full URL, or slug — e.g. 'mysite.ch', 'https://mysite.ch', or 'mysite.kleap.io'",
"type": "string"
}
},
"required": [
"query",
"context"
],
"type": "object"
},
"name": "find_app",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {},
"custom_domain": {},
"found": {
"type": "boolean"
},
"matched": {},
"name": {},
"production_url": {},
"query": {
"type": "string"
},
"reason": {},
"screenshot_url": {},
"site_url": {},
"slug": {},
"status": {}
},
"type": "object"
}
},
{
"description": "Put a REAL photo or illustration on the site by describing it — no image bytes to send. Give a vivid `prompt` and a `public/` `path` (e.g. public/hero.jpg); Kleap generates it with Cloudflare FLUX.2 and stores it as a proper binary asset, exactly like write_files with encoding:\"base64\" but with NO base64 to transmit (a real image's base64 is too big for a model to emit reliably — this is the ONLY dependable way to add a generated picture). Use it for hero photos, section illustrations, onboarding images, OG images, or to replace a broken/ugly image. Square 768×768 by default; pass width/height (256–1440) for other ratios; hd:true uses the premium model (sharper, slower). ⚠️ To REPLACE an existing image, generate to a NEW filename (e.g. hero-2.jpg) and point the markup at it — overwriting the same path can be served stale from CDN/R2 cache. After it returns, call publish_app to deploy it live.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"hd": {
"description": "true = premium model (flux-2-dev): sharper, slower. Default = fast klein model.",
"type": "boolean"
},
"height": {
"description": "Pixel height 256–1440 (default 768).",
"type": "number"
},
"path": {
"description": "public/ image path to create, ending .png/.jpg/.jpeg/.webp (e.g. public/hero.jpg). Use a NEW name to replace an image.",
"type": "string"
},
"prompt": {
"description": "Vivid description of the image to generate (subject, mood, lighting, style).",
"type": "string"
},
"width": {
"description": "Pixel width 256–1440 (default 768).",
"type": "number"
}
},
"required": [
"app_id",
"path",
"prompt",
"context"
],
"type": "object"
},
"name": "generate_image",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"bytes": {},
"model": {},
"path": {},
"size": {}
},
"type": "object"
}
},
{
"description": "Use this when the user asks about traffic, visitors, or which pages/referrers are performing on their PUBLISHED site. Backed by the same analytics as the Kleap dashboard's Visitors view. Returns zeroed data with configured:false if the app has never been published (analytics is set up automatically on publish). Requires the analytics:read scope — sessions connected BEFORE this tool shipped don't have it: on a 403 INSUFFICIENT_SCOPE error, tell the user to disconnect and reconnect the Kleap integration (re-authorize) to grant the scope.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id to fetch analytics for",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"period": {
"description": "Time window: '7d' (default), '30d', or '90d'",
"enum": [
"7d",
"30d",
"90d"
],
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "get_analytics",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"configured": {
"type": "boolean"
},
"pageviews": {
"type": "number"
},
"period": {},
"referrers": {},
"top_pages": {},
"visitors": {
"type": "number"
}
},
"type": "object"
}
},
{
"description": "Show a website to the user: its screenshot, name and live address. This is the ONE tool that renders the finished-site card, so call it once after a build or edit has finished and deployed (check_task says deployment_status deployed) — that is what lets the user SEE what was built. Also use it for plain details: name, slug, URLs, creation date, status. ADDRESS TO SHOW: site_url. If custom_domain is set, the owner connected that domain and it IS their site's address — never hand them the {slug}.kleap.io host instead, they did not choose it. Never call this while a build is still running: it would show the previous version as if it were the new one.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "get_app",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {},
"created_at": {},
"custom_domain": {},
"custom_domains": {},
"name": {},
"preview_url": {},
"production_url": {},
"screenshot_url": {},
"site_url": {},
"slug": {},
"status": {}
},
"type": "object"
}
},
{
"description": "Use this when the user asks how much usage they have left or about their plan status.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"context"
],
"type": "object"
},
"name": "get_credits",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"credits": {},
"is_paid": {}
},
"type": "object"
}
},
{
"description": "The app's Kleap Database (Postgres): its tables, row counts and columns. Call it before reading or writing rows. provisioned:false means the app has no database yet — create one with modify_app (describe the data to store).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "get_database_schema",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {},
"provisioned": {},
"tables": {}
},
"type": "object"
}
},
{
"description": "Use this when the user asks who filled out their contact form, or wants to see/export leads from their live site. Returns submissions from any <form> built with KleapForm on the app, newest first. Empty list is normal for a brand new site with no visitors yet. Requires the forms:read scope (submissions contain visitor PII) — sessions connected BEFORE this tool shipped don't have it: on a 403 INSUFFICIENT_SCOPE error, tell the user to disconnect and reconnect the Kleap integration (re-authorize) to grant the scope.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id to fetch submissions for",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"limit": {
"description": "Max rows to return (default 20, max 100)",
"type": "number"
},
"since": {
"description": "Only return submissions at/after this ISO 8601 date, e.g. '2026-06-01T00:00:00Z'",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "get_form_submissions",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"count": {
"type": "number"
},
"submissions": {}
},
"type": "object"
}
},
{
"description": "Use this to check whether a website is actually published and live. Returns the published state, the live production URL, and — once a publish has run — the PUBLISH REPORT of what Kleap checked on the site it just built: broken_links (existing pages that fail), dead_nav_links (menu entries pointing at a page that was never written — 90% of real dead links, /contact most often), incoherent_pages (a page answering 200 with content that contradicts the link leading to it), checks (source findings that did NOT block the publish, each with a category and a plain sentence: forms that submit into the void, islands with no client directive so buttons do nothing, broken images, hand-rolled auth or unguarded database access, dead API routes), design_gate (was the rendered homepage looked at), live_verified (was the NEW version confirmed serving), and SEO coverage (JSON-LD pages, sitemap URL count, robots, llms.txt). report.checked:true means the audit RAN, so empty lists mean nothing was found, not that nothing was looked at. If finding_count is above zero, tell the user what was found — in the report's own words, not the rule slugs — and offer to fix it. Do NOT describe a publish as clean when the report lists findings: a site can be live, pretty and still take no leads. status is one of: published, deploying, not_published, unknown_app. Returns the state at THIS instant — report it and end the turn; publishing takes minutes, so calling it repeatedly in one turn only burns the turn.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID to check",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "get_publish_status",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"name": {},
"production_url": {},
"reason": {},
"report": {},
"screenshot_url": {},
"slug": {},
"status": {}
},
"type": "object"
}
},
{
"description": "Use this when the user wants to see a visual screenshot of their website. Rate-limited to 1/min per app. The returned image_url is a PNG on the asset host — render it as an image () and nothing else. It is NOT the website's address, so never present it to the user as their site link, and never open, fetch or web-search it: the site's own address is production_url from get_app / find_app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "get_screenshot",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"height": {},
"image_url": {},
"name": {},
"preview_url": {},
"production_url": {},
"screenshot_url": {},
"slug": {},
"status": {
"type": "string"
},
"width": {}
},
"type": "object"
}
},
{
"description": "Use this when the user asks how their site is doing IN GOOGLE SEARCH — keywords/queries they rank for, impressions, clicks from search, CTR, or average position. Backed by their own Google Search Console property (connected per site in Kleap's options), so it is the real Google data, not an estimate. Returns totals plus the top queries and top pages that produced them. Search Console lags real traffic by ~2 days — the newest days are always incomplete, say so rather than reporting a drop. If connected is false or site_selected is false, the site simply has no Search Console hooked up: call connect_search_console(app_id) — it returns a consent_url to hand the user, and that is the whole setup. Do NOT send them hunting through Kleap's settings for it. For visitors and pageviews on the site itself (all sources, not just Google), use get_analytics instead. Requires the analytics:read scope — on a 403 INSUFFICIENT_SCOPE error, tell the user to disconnect and reconnect the Kleap integration (re-authorize).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id to fetch search data for",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"period": {
"description": "Time window: '28d' (default, the window Search Console itself shows), '7d', '30d' or '90d'",
"enum": [
"7d",
"28d",
"30d",
"90d"
],
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "get_search_console",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"clicks": {
"type": "number"
},
"connected": {
"type": "boolean"
},
"ctr": {
"type": "number"
},
"has_data": {
"type": "boolean"
},
"impressions": {
"type": "number"
},
"message": {},
"note": {},
"period": {},
"position": {
"type": "number"
},
"site_selected": {
"type": "boolean"
},
"site_url": {},
"top_pages": {},
"top_queries": {}
},
"type": "object"
}
},
{
"description": "Insert up to 500 rows into one table of the app's database. Returns the inserted rows (with generated ids/defaults).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"rows": {
"description": "Rows: column → value",
"items": {
"additionalProperties": {},
"type": "object"
},
"type": "array"
},
"table": {
"description": "Table name (public schema)",
"type": "string"
}
},
"required": [
"app_id",
"table",
"rows",
"context"
],
"type": "object"
},
"name": "insert_database_rows",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"inserted": {},
"rows": {},
"table": {}
},
"type": "object"
}
},
{
"description": "List the source file PATHS of an app (names only, no contents). See the project structure, then read_files to get contents before editing. Astro: src/pages/*.astro, src/data/*.json, src/components/*.astro, public/*.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "list_app_files",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"count": {},
"files": {}
},
"type": "object"
}
},
{
"description": "Use this when the user wants to see all their websites with name, slug, preview URL, and production URL.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"limit": {
"default": 20,
"description": "Number of apps to return (max 100)",
"type": "number"
},
"offset": {
"default": 0,
"description": "Pagination offset",
"type": "number"
}
},
"required": [
"context"
],
"type": "object"
},
"name": "list_apps",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"apps": {},
"total": {}
},
"type": "object"
}
},
{
"description": "Use this when the user wants to change or update an existing website. The AI can overwrite or remove existing content and automatically publishes the result to the live site. This uses Kleap usage. Needs the app_id — if the user named the site by its address (e.g. 'mysite.ch'), call find_app first to get the app_id.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID to modify",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"message": {
"description": "What to change (e.g. 'Change colors to blue, add a contact form')",
"maxLength": 10000,
"minLength": 1,
"type": "string"
}
},
"required": [
"app_id",
"message",
"context"
],
"type": "object"
},
"name": "modify_app",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"deployment_status": {},
"message_id": {},
"name": {},
"palette": {},
"plan": {},
"preview_url": {},
"production_url": {},
"screenshot_url": {},
"slug": {},
"status": {
"type": "string"
},
"task_id": {}
},
"type": "object"
}
},
{
"description": "Use this to take a website LIVE at its public URL. Publishing is VERIFIED-LIVE: the app is only reported published once the new version is provably serving — otherwise it reports 'not confirmed live', never a false 'it is online'. Publishing also AUDITS the built site: every internal link on every page (menu entries to a page never written are the #1 case), pages whose content contradicts the link leading to them, and JSON-LD/sitemap/robots coverage. Most deploys land in under a minute, so this call WAITS a bounded time and returns that `report` here when it does — read it before calling the launch a success, and if it lists findings, FIX THEM (write the missing page, or remove the dead link) before you answer, as you would a build error. On a slower deploy it returns 'publishing' with no report; then do not poll get_publish_status in a loop inside one turn — check once when the user asks again.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID to publish",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "publish_app",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"deploy_key": {},
"poll_url": {},
"production_url": {},
"report": {},
"status": {}
},
"type": "object"
}
},
{
"description": "Read rows from one table of the app's database. where = exact matches, e.g. {\"status\":\"new\"}. Max 500 rows per call; page with offset while has_more is true.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"limit": {
"description": "1-500, default 100",
"type": "number"
},
"offset": {
"type": "number"
},
"order": {
"description": "asc (default) or desc",
"type": "string"
},
"order_by": {
"description": "Column to sort by",
"type": "string"
},
"table": {
"description": "Table name (public schema)",
"type": "string"
},
"where": {
"additionalProperties": {},
"description": "Column equalities",
"type": "object"
}
},
"required": [
"app_id",
"table",
"context"
],
"type": "object"
},
"name": "query_database_rows",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"has_more": {},
"limit": {},
"offset": {},
"rows": {},
"table": {}
},
"type": "object"
}
},
{
"description": "Read existing file contents so you can edit them SAFELY instead of rewriting blind (which risks breaking shared components/homepages). Loop: list_app_files → read_files → edit_files (change just the lines that must change) → publish_app; use write_files instead only when you are writing a whole new file. Use it to fix headers/footers, wrong phone numbers, broken links, dead forms. Works with a Read-only key. Returns { files: [{ path, content, type, bytes, truncated?, returned_bytes? }], missing }. Text is capped at 256 KiB per file and 1 MiB per call; truncated files are explicitly marked, and files beyond the call budget must be read separately.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"paths": {
"description": "Project-relative paths to read, from list_app_files (e.g. ['src/components/Header.astro','src/components/Footer.astro'])",
"items": {
"type": "string"
},
"minItems": 1,
"type": "array"
}
},
"required": [
"app_id",
"paths",
"context"
],
"type": "object"
},
"name": "read_files",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"files": {
"items": {
"additionalProperties": false,
"properties": {
"bytes": {
"type": "number"
},
"content": {
"description": "Full text of the file. This is the payload — the text block only carries an index.",
"type": "string"
},
"path": {
"type": "string"
},
"returned_bytes": {
"description": "How many bytes of content are actually in this result. Zero means the call's budget was spent before this file — read it on its own.",
"type": "number"
},
"truncated": {
"description": "True when the file was too large to return whole; content holds the first bytes only.",
"type": "boolean"
},
"type": {
"type": "string"
}
},
"required": [
"path",
"content"
],
"type": "object"
},
"type": "array"
},
"missing": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Rename an app's display name. Does NOT change the URL — the live address ({slug}.kleap.io) and any links to it stay intact. (There is no tool to delete the entire app; delete_files removes selected source files.)",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID to rename",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"name": {
"description": "The new display name",
"maxLength": 100,
"minLength": 1,
"type": "string"
}
},
"required": [
"app_id",
"name",
"context"
],
"type": "object"
},
"name": "rename_app",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {},
"name": {},
"production_url": {},
"renamed": {
"type": "boolean"
},
"slug": {}
},
"type": "object"
}
},
{
"description": "Resume a failed or stalled create/modify task from where it stopped — partial files are preserved. Use this when check_task reports 'failed' instead of starting a brand-new create_app. Returns a NEW task_id — poll check_task on that NEW id (not the original). Budget: retry TASK_TIMEOUT/STALE_TASK up to TWICE; retry TASK_FAILED only ONCE; then stop and tell the user. NEVER retry a non-transient error (402 INSUFFICIENT_CREDITS = out of usage, a rejected prompt).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"task_id": {
"description": "The failed task_id to resume (from create_app/modify_app)",
"type": "string"
}
},
"required": [
"task_id",
"context"
],
"type": "object"
},
"name": "retry_task",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {},
"attempt": {},
"files_preserved": {},
"parent_task_id": {},
"status": {
"type": "string"
},
"task_id": {}
},
"type": "object"
}
},
{
"description": "Run SQL on the app's database (owner-level, needs database:write), values as $1, $2 in params. Rows capped at 500 / 5 MB. A table left without row-level security is rolled back (RLS_REQUIRED). To just read rows, prefer query_database_rows.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"params": {
"description": "Values for $1, $2, …",
"type": "array"
},
"sql": {
"description": "The SQL statement",
"type": "string"
}
},
"required": [
"app_id",
"sql",
"context"
],
"type": "object"
},
"name": "run_database_sql",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"command": {},
"row_count": {},
"rows": {},
"truncated": {},
"warnings": {}
},
"type": "object"
}
},
{
"description": "Search for available domains for a site (e.g. 'mybakery'). Returns available names across TLDs. To buy one, call buy_domain — it returns a checkout link the user pays. Use connect_domain for a domain the user already owns.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"query": {
"description": "Base name to search, without a TLD (e.g. 'mybakery')",
"type": "string"
},
"tlds": {
"description": "Optional TLDs to check, e.g. ['.com', '.io', '.ch']",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"query",
"context"
],
"type": "object"
},
"name": "search_domains",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"query": {
"type": "string"
},
"results": {}
},
"type": "object"
}
},
{
"description": "Update the rows matching where (required, non-empty, exact matches, e.g. {\"id\":42}) with the values in set. Returns the updated rows.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app id",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"set": {
"additionalProperties": {},
"description": "New values: column → value",
"type": "object"
},
"table": {
"description": "Table name (public schema)",
"type": "string"
},
"where": {
"additionalProperties": {},
"description": "Which rows (required)",
"type": "object"
}
},
"required": [
"app_id",
"table",
"where",
"set",
"context"
],
"type": "object"
},
"name": "update_database_rows",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"rows": {},
"table": {},
"truncated": {},
"updated": {}
},
"type": "object"
}
},
{
"description": "Use this when the user wants a paid Kleap plan, runs out of usage, or needs a feature that requires one (custom domain, more usage). Returns an upgrade_url the USER must open and pay — nothing is charged before that, so never say they are subscribed. plan: 'monthly' (default) or 'annual'; 'credits' (legacy name) buys extra usage for users who already have a paid plan. Do not quote a price: the page shows it in the user's currency.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The site this upgrade is for (shown on the checkout)",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"plan": {
"description": "Default monthly",
"enum": [
"monthly",
"annual",
"credits"
],
"type": "string"
}
},
"required": [
"context"
],
"type": "object"
},
"name": "upgrade_plan",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"credits_balance": {},
"is_paid": {},
"plan": {},
"upgrade_url": {}
},
"type": "object"
}
},
{
"description": "Use this when the user's website preview is sleeping (sandboxes auto-stop after 15 min). Takes ~30-60s to restart.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID to wake up",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
}
},
"required": [
"app_id",
"context"
],
"type": "object"
},
"name": "wake_app",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"preview_url": {},
"status": {
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Write WHOLE files DIRECTLY — YOUR model generates the code, Kleap stores, builds and deploys it as-is. To change something in a file that ALREADY EXISTS, use edit_files instead (read_files → edit_files): it replaces just the lines you name, while write_files makes you retype the entire file and silently drops whatever you leave out — on a 30KB shared layout that is how headers and footers get wiped. No Kleap-AI step, so what ships is byte-for-byte what you wrote — the right choice when a phrase, a URL or a schema must be exact. Publishing still audits the result (see publish_app). Best for scaffolding exact pages/components — e.g. programmatic-SEO routes. Astro paths (src/pages/*.astro, src/data/*.json, src/components/*.astro, public/*). Overwrites by path. NPM PACKAGES: do not write package.json (the build replaces it) — the build installs whatever your code IMPORTS, so `import { jsPDF } from \"jspdf\";` is all it takes. Supported on import: @tiptap/*, jspdf, pdf-lib, html2canvas, papaparse, file-saver, jszip, @ffmpeg/*, howler, wavesurfer.js, browser-image-compression, react-dropzone, recharts, chart.js, d3, @tanstack/*, react-hook-form, three, @react-three/*, leaflet, maplibre-gl, gsap, framer-motion, zustand, date-fns, react-markdown, axios, socket.io-client, radix-ui/*, next-themes, lucide-react, @tabler/*, openai, @ai-sdk/*; anything else is refused at build with a message naming it. A client-side router is never the answer — a route is a FILE (src/pages/about.astro → /about). IMAGES AND BINARIES: set encoding:\"base64\" on the file and send the bytes — that is how you put a logo, a photo, an OG image, a favicon or a font on the site (png/jpg/webp/svg/ico/mp4/woff2/pdf, 512KB max each decoded). Without it you can only write text, and a site with no images looks unfinished. To ADD an image from a text prompt WITHOUT sending any bytes (a real photo's base64 is too big to emit reliably), use generate_image — Kleap generates it and stores it for you. To REMOVE a page or asset, use delete_files — overwriting it with empty content leaves a URL that answers 200 with nothing, which is worse than a 404. DATA & ACCOUNTS: write_files only STORES files — it cannot provision the Kleap Database, so DB or auth code pushed here has no backend and silently does nothing. Stand the feature up with modify_app first, then edit those pages here. After writing, call publish_app to build & go live.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"app_id": {
"description": "The app ID",
"type": "number"
},
"context": {
"description": "Why this call, in one short sentence. Used to improve the connector; never include credentials or personal data.",
"type": "string"
},
"files": {
"description": "Files to write/overwrite: [{ path, content, encoding? }]",
"items": {
"additionalProperties": false,
"properties": {
"content": {
"description": "Full file text — or the base64 of the bytes when encoding is \"base64\"",
"type": "string"
},
"encoding": {
"description": "Omit for text. Use \"base64\" to write an IMAGE or any binary (png, jpg, webp, svg, ico, mp4, woff2, pdf...). 512KB max per file decoded.",
"enum": [
"utf8",
"base64"
],
"type": "string"
},
"path": {
"description": "Project-relative path, e.g. src/pages/about.astro",
"type": "string"
}
},
"required": [
"path",
"content"
],
"type": "object"
},
"minItems": 1,
"type": "array"
}
},
"required": [
"app_id",
"files",
"context"
],
"type": "object"
},
"name": "write_files",
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"app_id": {
"type": "number"
},
"binary": {},
"paths": {},
"written": {}
},
"type": "object"
}
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:06f8e131cb516b61df18f67ade7324fe560c92c0541ad7dfbb1e4ae947bf5e1d | sha256sum