{"name":"dev.lekta/lekta","slug":"lekta","title":null,"description":"Audits how AI answer engines read a page and grades it A+ to F across four measured layers.","url":"https://mcp.market/server/lekta","rating":null,"grade":"C","score":57,"certified":false,"status":"active","category":"other","tags":[],"presence":{"score":5,"stars":null,"forks":null,"downloads_week":null,"last_push_at":null,"license":null},"uptime":{"percent":100,"checks":7,"ok":7,"last_checked_at":"2026-09-21T02:55:48.519Z","last_ok_at":"2026-09-21T02:55:48.519Z","latency_ms":327},"claimed":false,"transport":"remote","callable_via_gateway":true,"default_price_micros":0,"repository":null,"website":null,"version":"2026.7.0","remotes":[{"type":"streamable-http","url":"https://lekta.dev/mcp","headers":[{"description":"Free API key created at https://lekta.dev/en/panel/api; keys start with lekta_. Authorization: Bearer <key> is accepted as an alternative.","isRequired":true,"isSecret":true,"name":"X-API-Key"}]}],"packages":[],"tools":[{"name":"lekta_audit","description":"Audits ONE live page for AEO (Answer Engine Optimization), also called GEO (Generative Engine Optimization): whether ChatGPT, Claude, Perplexity, Google AI Overviews and Bing can reach, read, quote and cite it. Fetches the page the way those engines do — a plain HTTP GET as LektaBot, then a headless-Chromium render pass — and grades it A+ to F across four weighted layers: Access 25% (robots.txt permission for 36 published AI crawler tokens: GPTBot, OAI-SearchBot, ClaudeBot, Claude-SearchBot, PerplexityBot, Googlebot, bingbot, CCBot and more), Indexability 25% (noindex / nosnippet / canonical controls, and how much main content survives with JavaScript off), Answerability 30% (concrete data density, external evidence, semantic section structure, hedging), Recency 20% (a machine-readable and visible last-updated date). Returns Markdown under fixed headings: \"## Verdict\" (grade, score, per-layer scores, and the URL actually measured after redirects), \"## Top issues\" (failing and warned checks ranked by points lost, tagged critical/serious/moderate/minor, with evidence), \"## Fixes\" (the full remediation text for each). Unmeasured layers cap the grade at B and say so. USE THIS for \"run an AEO audit\", \"run a GEO audit\", \"why is my page not cited in AI answers\", \"will ChatGPT / Claude / Perplexity quote this page\", \"check my robots.txt for AI crawlers\" — and again after every deploy to re-measure. DO NOT use it when code will parse the result (lekta_report is the same run as JSON), when an audit already exists and you only want the ranked work list (lekta_fix_plan, which never fetches), or to compare two runs (lekta_diff). It scores one page, not a site: no crawling, no sitemap expansion. COST AND BEHAVIOUR: read-only — the audited site is never modified. It READS AND GRADES robots.txt rather than obeying it as a fetch gate: the audit runs even where LektaBot is disallowed, and the report flags that. A blocking call — a live fetch plus a render pass, cut off at a 75 s hard limit. NOT idempotent: a URL not audited in the last 15 minutes starts a fresh run and spends one slot of the daily MCP quota (free plan default 10 fresh audits per UTC day across 1 hostname; every result prints the count used and the host slot in use), while a repeat inside that window replays the cached measurement for free. An unreachable, blocked or HTTP-error target still returns a report, graded U for \"unknown\" — never F. Only these return an error instead of a grade: a timeout or a server-side engine failure, an exhausted daily quota or host slot, 2 audits already in flight for this account, or the per-target ceiling of 1 audit per minute and 5 per hour.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"url":{"type":"string","description":"Required. The one absolute http(s) page URL to audit, e.g. \"https://example.com/pricing\". A bare host+path (\"example.com/pricing\") is accepted and upgraded to https; the #fragment is dropped and the hostname lower-cased, but the query string is kept and is part of the page identity (?variant=b is a distinct target). ONE page per call — not a domain, a sitemap or a list. Prefer a representative content page over the homepage: scoring is per-URL, not per-site. Redirects are followed and the verdict names the final measured URL, but the audit is STORED under the URL you pass here — give lekta_fix_plan and lekta_diff this same string, not the redirect destination."}},"required":["url"]}},{"name":"lekta_diff","description":"Compares the two most recent scorable audits stored for ONE URL and reports the movement: score and grade before → after, which checks improved, which regressed, with both run timestamps. This is the progress meter of the fix loop. USE THIS to prove a deploy actually moved the number: lekta_audit → apply the fixes → deploy → lekta_audit again → lekta_diff. DO NOT use it to compare two different URLs or two pages of one site — it takes ONE url and compares that page against its own history — and do not call it when fewer than two scorable audits exist for that URL, which returns an error rather than a partial answer. For the ranked work list use lekta_fix_plan; for the current state of a page use lekta_audit. COST AND BEHAVIOUR: free and idempotent — reads storage only, no fetch, no quota; it never triggers an audit, so no diff exists until you have run lekta_audit twice yourself. Runs that could not be scored (grade U) and runs where a rule crashed server-side are excluded from the comparison entirely, so a failed re-audit is never reported as a regression — it simply is not there. When the engine version changed between the two runs the output says so, because part of the delta is then ours rather than yours.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"url":{"type":"string","description":"Required. An absolute http(s) URL with at least two stored scorable audits, e.g. \"https://example.com/pricing\". Same normalisation and the same keying rule as lekta_fix_plan: history is stored under the URL passed to lekta_audit, not the post-redirect final URL. One URL only — this compares a page with its own past, never with another page."}},"required":["url"]}},{"name":"lekta_fix_plan","description":"Turns the most recent STORED audit of a URL into an ordered remediation plan: every failing or warned check as a numbered step, biggest point recovery first, each with its severity, the points that fixing it is expected to regain, and the full fix text. Reads storage only and never fetches, so the plan is exactly as fresh as the last audit of that URL — and any audit of it counts, whether it was started over MCP or from the lekta.dev panel. USE THIS between lekta_audit and the code change, to decide what to fix and in what order, or to hand a developer or another agent a prioritised AEO/GEO work list. It keeps working when the daily fresh-audit quota is exhausted. DO NOT use it to measure or re-measure a page (lekta_audit does that), and do not call it for a URL that was never audited — it returns an error telling you to run lekta_audit first, not an empty plan. For what changed between two runs use lekta_diff; for the raw structured data use lekta_report. COST AND BEHAVIOUR: free and idempotent — no fetch, no quota, no rate limit; it never starts an audit under any circumstance, and repeat calls return the same plan until a newer audit lands. When the stored audit came from an older engine version the output says so and marks the point estimates unreliable. When it has no failing or warned checks, the tool reports that instead of inventing work.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"url":{"type":"string","description":"Required. An absolute http(s) URL that already has a stored audit, e.g. \"https://example.com/pricing\". Normalised like the lekta_audit url (https assumed when the scheme is missing, #fragment dropped, hostname lower-cased, query string significant). History is keyed on the URL that was PASSED to lekta_audit, never the final URL after a redirect — so if the audit reported a redirect, still pass the address you originally sent."}},"required":["url"]}},{"name":"lekta_my_sites","description":"Lists the sites saved on the authenticated Lekta account: URL, latest authoritative grade and score, when it was last audited, and the recheck interval where a schedule is on. This is account inventory, not a measurement. PARAMETERS: none — this tool takes no arguments; call it with an empty arguments object. USE THIS first in a session to see which URLs this account already tracks before picking one to pass to lekta_audit, lekta_fix_plan or lekta_diff, or to answer \"which of my pages has the worst grade\" and \"which pages are on a schedule\". DO NOT expect a fresh measurement (lekta_audit does that), sites belonging to other accounts, or arbitrary URLs — and do not expect to change anything here: sites are added and removed on the web panel at lekta.dev/en/panel, not over MCP. An account with no saved sites gets an explicit empty-list message, not an error. COST AND BEHAVIOUR: free and idempotent — no fetch to any site, no quota. Each grade shown is the last AUTHORITATIVE (scorable) run for that URL, the same definition the web panel and the badge use; when a newer attempt existed but could not be scored, that is stated on its own line, so the grade is neither hidden nor silently presented as current.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{}}},{"name":"lekta_report","description":"Runs the same page audit as lekta_audit and returns the whole report as one JSON document instead of Markdown — for programs, not people. Top-level fields: engineVersion, url (as requested), finalUrl, fetchedAt, durationMs, targetState, robotsDisallowsLektaBot, score (0-100, null when the target could not be measured), grade, coverage, coverageNote, appliedCaps, movers, warningCount, failCount, and fetchMeta (HTTP status, redirect chain, content type, bytes). layers[] carries each layer definition (name, weight) with its score, and layers[].checks[] every check with id, title, status (pass / fail / warn / info / not_applicable / unmeasured), severity, evidence values and full fix text. Scoring internals are stripped by design — rule source names, reference URLs and threshold rationale are absent; each check keeps only its dated evidence-class tag (SPEC, VENDOR, MEASUREMENT, PEER-REVIEWED or PROVISIONAL). USE THIS when code consumes the result, or when you need a field the Markdown verdict never prints: check ids, per-layer scores, raw evidence values, the redirect chain. DO NOT use it to show a person a verdict (lekta_audit is shorter and ranked by point impact), do not call it after lekta_audit for the same URL expecting new data (it is the same measurement in another shape), and do not reach for it to learn WHY a rule exists — that material is deliberately not in the payload. COST AND BEHAVIOUR: the same fetch, 15-minute cache, quota and limits as lekta_audit, with two differences — the JSON carries no quota line, so call lekta_audit when you need the count used, and nothing here is ranked: checks arrive in layer order, not by point impact.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"url":{"type":"string","description":"Required. One absolute http(s) page URL, e.g. \"https://example.com/pricing\". Handled exactly like the lekta_audit url: a missing scheme becomes https, the #fragment is dropped, the hostname is lower-cased, the query string is significant, and it is one page per call — no domain lists or sitemaps. A URL already audited within the last 15 minutes returns the cached run and spends no quota."}},"required":["url"]}}],"scan":{"score":57,"grade":"C","scanned_at":"2026-09-19T20:53:28.484Z","report":{"scannerVersion":"0.1.7","scannedAt":"2026-09-19T20:53:28.449Z","components":{"code":{"score":-1,"max":25,"notes":["remote-only server, no package to scan"]},"reliability":{"score":17,"max":20,"notes":["remote reachable in 2264ms"]},"poisoning":{"score":13,"max":15,"notes":["5 tool descriptions checked"]},"auth":{"score":8,"max":15,"notes":["API key sent as a header"]},"maintenance":{"score":3,"max":15,"notes":["no repository listed"]},"identity":{"score":2,"max":10,"notes":["no repository or website to verify"]}},"findings":[{"id":"poison.long-description","severity":"low","component":"poisoning","title":"Unusually long tool description (over 2,000 characters)","evidence":"tool lekta_audit: …Audits ONE live page for AEO (Answer Engine Optimization), also called GEO (Generative Engine Optimization): whether ChatGPT, Claude, Perplexity, Google AI Overviews and Bing can reach, read, quote and cite it. Fetches the page the way those engines do — a plain HTTP GET as LektaBot, then a headless-Chromium render pass — and grades it A+ to F across four weighted layers: Access 25% (robots.txt permission for 36 published AI crawler tokens: GPTBot, OAI-SearchBot, ClaudeBot, Claude-SearchBot, PerplexityBot, Googlebot, bingbot, CCBot and more), Indexability 25% (noindex / nosnippet / canonical controls, and how much main content survives with JavaScript off), Answerability 30% (concrete data density, external evidence, semantic section structure, hedging), Recency 20% (a machine-readable and visible last-updated date). Returns Markdown under fixed headings: \"## Verdict\" (grade, score, per-layer scores, and the URL actually measured after redirects), \"## Top issues\" (failing and warned checks ranked by points lost, tagged critical/serious/moderate/minor, with evidence), \"## Fixes\" (the full remediation text for each). Unmeasured layers cap the grade at B and say so. USE THIS for \"run an AEO audit\", \"run a GEO audit\", \"why is my page not cited in AI answers\", \"will ChatGPT / Claude / Perplexity quote this page\", \"check my robots.txt for AI crawlers\" — and again after every deploy to re-measure. DO NOT use it when code will parse the result (lekta_report is the same run as JSON), when an audit already exists and you only want the ranked work list (lekta_fix_plan, which never fetches), or to compare two runs (lekta_diff). It scores one page, not a site: no crawling, no sitemap expansion. COST AND BEHAVIOUR: read-only — the audited site is never modified. It READS AND GRADES robots.txt rather than obeying it as a fetch gate: the audit runs even where LektaBot is disallowed, and the report flags that. A blocking call — a live fetch plus a render pass, cut off at a 75 s hard limit. NOT idempotent: a URL not audited in the last 15 minutes starts a fresh run and spends one slot of the daily MCP quota (free plan default 10 fresh audits per UTC day across 1 hostname; every result prints the count used and the host slot in use), while a repeat inside that window replays the cached measurement for free. An unreachable, blocked or HTTP-error target still returns a report, graded U for \"unknown\" — never F. Only these return an error instead of a grade: a timeout or a server-side engine failure, an exhausted daily quota or host slot, 2 audits already in flight for this account, or the per-target ceiling of 1 audit per minute and 5 per hour.…"},{"id":"maint.no-repo","severity":"low","component":"maintenance","title":"No source repository listed"}],"inputs":{"probes":[{"url":"https://lekta.dev/mcp","reachable":true,"authRequired":false,"latencyMs":2264,"serverInfo":{"name":"lekta","version":"lekta-score/2026.7"}}],"packages":[],"repo":{"found":false},"icon":{"url":"https://lekta.dev/favicon.svg","source":"site"},"presence":{"stars":null,"forks":null,"downloadsWeek":null,"license":null,"lastPushAt":null,"score":5}}}},"grade_history":[],"reviews":[]}