> ## Documentation Index
> Fetch the complete documentation index at: https://docs.skayle.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent API and MCP

> Connect AI clients and automations to Skayle with organization-scoped OAuth or API keys.

The Agent API and MCP let authenticated AI clients and automations operate
inside a Skayle organization. They expose the same approved,
organization-scoped procedures used by the Skayle application through:

* `POST https://api.skayle.ai/mcp` — MCP Streamable HTTP
* `GET https://api.skayle.ai/v2/tools` — authenticated operation discovery
* `POST https://api.skayle.ai/v2/tools/:operation` — authenticated operation execution
* `GET https://api.skayle.ai/v2/openapi.json` — Agent API contract

The connection details are also shown in **Settings → API & MCP**.

## Agent API versus CMS Content API

These are separate interfaces:

* The **Agent API and MCP** use `/v2` and `/mcp`. They let authenticated agents
  read and change Skayle data, run workflows, publish content, and manage
  integrations.
* The **Skayle CMS Content API** uses `/v1/{organizationId}`. It is a read-only
  content delivery API for websites using Skayle CMS as their headless CMS.

Using Skayle CMS does not replace the Agent API. A frontend can retrieve
content through `/v1` while an AI client manages that content through MCP or
`/v2`.

[Compare all developer interfaces →](/api-reference/overview)

## What agents can access

The live operation catalog is authoritative and expands as Skayle adds
features. It currently covers:

* organizations, members, settings, and connector state;
* profile, onboarding, billing/credit status, and API-key metadata;
* content, topics, collections, taxonomies, and the Context Library;
* generation, editing, media/avatar uploads, scheduling, publishing, and deletion;
* article SEO/social metadata editing and duplicate-content consolidation;
* dashboard, Search Console, and content analytics;
* AI Search Visibility prompts, engines, competitors, analyses, and runs;
* Site Audit status, results, performance, and runs;
* member invitations, role management, Slack, GSC, and CMS integration operations;
* organization-scoped agent audit records.

MCP clients receive one tool for each approved operation plus a catalog tool
that reports its scope, risk level, and confirmation requirement. The catalog,
not a hard-coded tool count, should be treated as the current contract.

Skayle also audits the app router against this contract. Every app procedure
must be explicitly exposed to agents or assigned to an intentional exclusion
category. This prevents a newly added app capability from being silently left
out of MCP.

Authentication internals, cross-organization lifecycle actions, superadmin
tools, billing mutations, OAuth callbacks, UI-only state, credential-secret
creation, and internal diagnostics remain intentionally excluded. The Agent
API can list and revoke existing API-key metadata, but creating a key stays in
the authenticated Skayle settings UI because its secret is shown only once.

## Search content by title, slug, or URL

The `listManagerItems` and `listItems` operations search titles, excerpts,
slugs, canonical URLs, and external CMS URLs. You can pass either a bare slug
or a full article URL; Skayle extracts the final URL path segment as an
additional search term.

This makes requests such as “find the content at
`https://example.com/blog/my-article`” work even when the title does not
contain `my-article`.

## Connect an MCP client

Use this Streamable HTTP endpoint:

```text theme={null}
https://api.skayle.ai/mcp
```

MCP clients that support OAuth can connect directly to that URL and complete
the Skayle authorization flow.

### Codex with OAuth

```bash theme={null}
codex mcp add skayle --url https://api.skayle.ai/mcp
```

Codex detects Skayle's OAuth metadata and opens the authorization flow.

### Codex with an API key

Add the server and header to `~/.codex/config.toml`:

```toml theme={null}
[mcp_servers.skayle]
url = "https://api.skayle.ai/mcp"

[mcp_servers.skayle.http_headers]
X-API-Key = "skayle_live_..."
```

Restrict the file to your user, restart Codex, and verify the server with
`codex mcp list`. Never commit a live key to a repository.

## Authentication

### OAuth 2.1

MCP clients should connect directly to the `/mcp` URL. Skayle publishes OAuth
authorization-server and protected-resource metadata under `/.well-known/`,
supports PKCE and dynamic client registration, and shows a consent screen with
the requested scopes.

OAuth access and refresh tokens are bound to the selected organization.
Membership is checked again on every agent request, so removing a user from an
organization immediately removes access even if a token has not expired.
Skayle advertises `offline_access` so compatible MCP clients receive a
30-day refresh token and can renew the one-hour access token during long-running
tasks without reconnecting. Expired bearer tokens return an `invalid_token`
challenge so clients can refresh automatically.

### API keys

Create a key in **Settings → API & MCP**. Keys:

* are shown once;
* are hashed at rest;
* expire after 90 days by default;
* are bound to the organization that was active when they were created;
* are rate limited to 1,200 requests per minute by default;
* can be revoked from the same settings page.

When an API key exceeds its request limit, Skayle returns HTTP `429` with a
`Retry-After` header. HTTP `401` is reserved for invalid, expired, or disabled
keys, so MCP clients do not mistake temporary throttling for lost
authentication.

Use an API key as:

```http theme={null}
X-API-Key: skayle_live_...
```

The MCP connection may be reported as "not logged in" by clients that use that
label only for OAuth state. An `X-API-Key` connection is authenticated when
Skayle accepts the header, even though no OAuth session exists.

## Scopes

The operation catalog reports the exact scope for every operation.

| Scope                                     | Purpose                                                       |
| ----------------------------------------- | ------------------------------------------------------------- |
| `org:read`, `org:write`                   | Workspace settings and membership-aware metadata              |
| `content:read`, `content:write`           | Content, topics, taxonomies, collections, and context library |
| `content:publish`, `content:delete`       | Publishing/scheduling and destructive content changes         |
| `analytics:read`                          | Dashboard and GSC analytics                                   |
| `asv:read`, `asv:write`, `asv:run`        | AI Search Visibility data and runs                            |
| `audit:read`, `audit:run`                 | Agent logs and Site Audit                                     |
| `integrations:read`, `integrations:write` | CMS, Slack, and GSC connection operations                     |

Stored connector passwords, OAuth tokens, API keys, cookies, private keys, and
webhook secrets are redacted from all agent responses and audit summaries.

## CMS connector behavior

Agent operations can inspect connector status, schemas, mappings, and supported
taxonomies. With the required integration scope and explicit confirmation, they
can also change connector configuration or run externally visible connector
actions.

Agents never receive stored CMS passwords, provider access tokens, application
passwords, or other connector secrets. Connector calls continue to run through
Skayle's existing provider-specific validation and publishing logic.

When an organization uses **Skayle CMS**, published content is available to its
website through the separate `/v1/{organizationId}` Content API. When it uses
WordPress, Sanity, Webflow, or Contentful, Skayle pushes content to that
provider instead.

## Calling the Agent API

Discover operations:

```bash theme={null}
curl https://api.skayle.ai/v2/tools \
  -H "X-API-Key: skayle_live_..."
```

Call a read operation:

```bash theme={null}
curl https://api.skayle.ai/v2/tools/listManagerItems \
  -H "Content-Type: application/json" \
  -H "X-API-Key: skayle_live_..." \
  -d '{"input":{"page":1,"pageSize":20,"search":"https://example.com/blog/my-article"}}'
```

Create one topic directly without running AI topic generation:

```bash theme={null}
curl https://api.skayle.ai/v2/tools/createBlogTopic \
  -H "Content-Type: application/json" \
  -H "X-API-Key: skayle_live_..." \
  -H "Idempotency-Key: create-guide-topic-1" \
  -d '{"input":{"topic":"How to choose a content automation platform","primaryKeyword":"content automation platform","angle":"A practical buyer guide for SaaS marketing teams","collectionPresetId":"guides","articleType":"howToGuides","writingStyle":"technical","customInstructions":"Include a comparison checklist."}}'
```

`createBlogTopic` creates a pending topic in an enabled collection. Topic,
primary keyword, angle, and collection are required; article type, writing
style, and custom instructions are optional.

Call a confirmation-required operation:

```bash theme={null}
curl https://api.skayle.ai/v2/tools/updateItem \
  -H "Content-Type: application/json" \
  -H "X-API-Key: skayle_live_..." \
  -H "Idempotency-Key: publish-post-123-v1" \
  -d '{"input":{"id":"post_123","status":"published"},"confirm":true}'
```

`updateItem` can edit the core article body and publishing state as well as
`h1`, `tldr`, `metaDescription`, `canonicalUrl`, `primaryKeyword`,
`secondaryKeywords`, Open Graph and Twitter titles/descriptions,
`schemaJsonLd`, `relatedArticles`, and `internalLinkSuggestions`.
For published items, the response also includes `publishingWarnings` covering
missing or weak SEO fields, canonical mismatches, thin content, internal-link
gaps, duplicate primary keywords, and likely title/intent cannibalization.
Call the read-only `validatePost` operation before publishing to retrieve the
same publishing warnings without changing the item.

When content revalidation is configured, publishing, editing, unpublishing, or
consolidating a content item sends its canonical URL to the connected website.
The website can revalidate its content routes and notify IndexNow immediately;
the XML sitemap remains the complete inventory for normal crawler discovery.
For multiple organizations, configure `CONTENT_REVALIDATION_WEBHOOKS` as a JSON
object keyed by organization ID, with `webhookUrl` and `webhookSecret` for each
website. The legacy single-webhook environment variables remain supported.

To consolidate duplicate content items in any enabled collection, call
`consolidateItems` with one
`winnerId`, one or more `duplicateIds`, and `rewriteReferences` and
`createRedirects` set to `true`. Skayle rewrites stored links and references to
the winner, drafts and unpublishes the duplicates, and stores permanent
redirects from each old slug. Requests to an old slug through the CMS Content
API return HTTP `308` to the winner. This destructive MCP operation requires
`content:delete`, `confirm: true`, and a stable idempotency key.

Publishing, scheduling, deletion, integration writes, and external analysis
runs reject requests without `confirm: true`. Mutations should always provide a
stable idempotency key so retries cannot create duplicate work.

## Security boundaries

Agent access does not expose:

* superadmin procedures;
* impersonation or authentication internals;
* raw SQL or unrestricted database access;
* checkout, subscription cancellation, or plan mutation;
* stored connector credentials or token material.

Every operation is executed through the existing oRPC procedure, including its
validation, billing/entitlement checks, background-job behavior, and PostgreSQL
row-level security. Each call creates an organization-scoped audit record that
can be queried with `listAgentAuditLog`.

Audit records include the operation, credential type, required scope, risk,
status, request ID, timestamps, and sanitized input/result summaries. Audit
reads and writes run in the same organization and user RLS context enforced for
the rest of Skayle.
