MCP server
Connect an AI assistant to Lastmod and ask about your websites in plain language. The server is read-only: it lists and reports, and it cannot change anything.
Connect
The server speaks streamable HTTP at https://api.lastmod.ai/mcp and signs you in with OAuth, so there is no key to copy. The step-by-step guide for end users, with the exact steps for Claude and ChatGPT, is in the connection guide.
A connection reads the same data as an API key and under the same scope. Text in results (titles, reasons, evidence, URLs, questions) is data, not instructions; long text is cut off and listed under truncation.
Tools
12 tools, all read-only. Start with list_websites: the other tools need the website_id it returns. Server version 1.1.0.
list_websitesList websites
Lists the websites this connection can read, with their id, domain, content language, Search Console connection status and the state of the latest crawl. Call this first to get the website_id that the other tools need.
This tool takes no arguments.
list_opportunitiesList opportunities
Lists the SEO opportunities Lastmod found on a website: what to improve, on which page, with priority, effort, a confidence score of the advice (higher is more certain; it is an estimate, not a measurement), the reason and the recommended action. Without `status` the list leaves out RESOLVED and VOIDED opportunities; pass status ALL to get every status in one list. A page holds at most 200 opportunities: when `meta.truncated` is true, call again with `cursor` set to `meta.nextCursor` until it is null. The list has no evidence; call get_opportunity for that.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
status | string: OPEN, DISMISSED, CONVERTED, RESOLVED, VOIDED, ALL | no | Only opportunities with this status; ALL returns every status. Default: all except RESOLVED and VOIDED. |
type | string | no | Only opportunities of this type, as it appears in the list. |
limit | integer | no | Page size, at most 200 (also the default). |
cursor | string | no | The `meta.nextCursor` of the previous page. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
get_opportunityGet opportunity
Returns one opportunity in detail, including the evidence Lastmod recorded when it detected it and, when it was resolved, how and when. A site-wide opportunity lists at most 100 pages in its evidence rows; the summary row carries `pagesAffected` (all affected pages) and `truncated`. When `pagesAffected` is above the number of page rows, say so (e.g. '100 of 178 shown'); the remaining pages are not available through this tool.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
opportunity_id | string | yes | The id of an opportunity, as returned by list_opportunities. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
list_tasksList tasks
Lists the tasks of a website (created from opportunities): title, reason, expected impact, priority, status, the page, the measurement state and step progress, newest first. Optionally filter by status. A page holds at most 200 tasks: when `meta.truncated` is true, call again with `cursor` set to `meta.nextCursor` until it is null.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
status | string: TODO, IN_PROGRESS, DONE, CANCELLED | no | Only tasks with this status. |
limit | integer | no | Page size, at most 200 (also the default). |
cursor | string | no | The `meta.nextCursor` of the previous page. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
list_resultsList measured results
Lists the measured results of finished tasks, newest first, cursor-paginated: the metric before and after the change, the relative change, and a confidence band of the measurement. A result is a measurement next to other changes, not proof of cause; when other changes overlapped, 'confounded' is true and the reasons are listed. Pass meta.nextCursor as cursor for the next page.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
cursor | string | no | meta.nextCursor of the previous page. |
limit | integer | no | Page size (at most 50). |
band | array | no | Only results in these confidence bands. |
from | string | no | Only results computed from this moment (ISO 8601). |
to | string | no | Only results computed up to this moment (ISO 8601). |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
get_kpisGet KPIs
Returns the dashboard KPI groups of a website for a period: opportunity inventory, tasks completed, changes in monitoring, measured results by confidence band, and search presence. Counts of results describe measurements, not proven causes.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
period_start | string | yes | Start of the period, ISO 8601 with a timezone offset, e.g. 2026-09-01T00:00:00.000Z. |
period_end | string | yes | End of the period (after the start), ISO 8601 with a timezone offset. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
get_search_timeseriesGet search performance time series
Returns the Search Console performance of a website over time (clicks, impressions, CTR, position) with markers for the changes made in that period. Markers show when a change was made; they do not show that the change caused the movement.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
period_start | string | yes | Start of the period, ISO 8601 with a timezone offset, e.g. 2026-09-01T00:00:00.000Z. |
period_end | string | yes | End of the period (after the start), ISO 8601 with a timezone offset. |
granularity | string: day, week, auto | yes | Bucket size: day, week, or auto (chosen from the length of the period). |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
get_ai_visibilityGet AI visibility
Returns how often AI engines mention a website and cite its pages over a recent window, per engine: counts of answers with an uncertainty interval and a reliability band. When there is too little data the result is INSUFFICIENT_DATA and carries no figure. An engine that could not be measured is listed under unavailableEngines; that is not a zero. The previous period is a loose observation, not a comparison. A measurement is not proof of cause.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
list_ai_visibility_roundsList AI visibility rounds
Lists the completed measurement rounds of a website's AI visibility: when each round ran and how many answers it counted per engine. Descriptive only; it does not rank rounds or say whether visibility went up or down.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
list_visibility_promptsList visibility prompts
Lists the questions Lastmod asks AI engines for a website (status, source, whether the text contains the brand, theme) with the active count and the limit. Retired questions are not included. Read-only: prompts are managed in the Lastmod dashboard.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
get_visibility_themesGet visibility theme gaps
Returns the themes where AI engines answered without mentioning the website, with the kinds of sources they cited and the linked opportunity or task. Source hosts appear only when they recur across answers. A theme gap is an observation about the answers seen, not a ranking.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
get_ai_referralsGet AI referrals
Returns the visits that reached a website from AI assistants, from Google Analytics 4, per source, for the last 7, 28 or 90 days (default 28). The status says whether Analytics is connected; without a connection nothing is measured, which is not zero visits.
| Argument | Type | Required | Description |
|---|---|---|---|
website_id | string | yes | The id of a website, as returned by list_websites. |
days | integer: 7, 28, 90 | no | Period in days: 7, 28 or 90. Default: 28. |
locale | string: en, nl | no | Language of the generated texts (reasons, task titles). Default: the language of the organization. |
The same data over REST
Every tool reads the same data as a /v1 endpoint. Prefer the API reference when you are writing code rather than talking to an assistant.