# AI Tools

> Connect Claude, ChatGPT, and other AI assistants to your EmDash site.

Source: https://emdashcmseverything.com/official-docs/guides/ai-tools/

EmDash has a built-in [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that lets AI assistants work directly with your site's content. You can ask Claude, ChatGPT, or other tools to draft posts, update pages, manage media, search your content, and more -- all through natural conversation.

> **Note**
>
> This guide covers your **site's** MCP server -- for managing the content of an EmDash site. If you want to give an AI coding assistant access to the EmDash documentation itself (so it can answer questions about EmDash as you build), see [Docs MCP for AI Tools](https://emdashcmseverything.com/official-docs/docs-mcp/) instead. You can connect either server or both, depending on whether the assistant needs documentation, site content, or both.

## Your site's MCP server

The MCP server is enabled by default. EmDash mounts `/_emdash/api/mcp` unless you turn it off. The endpoint accepts OAuth or personal access bearer tokens; an admin browser session by itself does not authenticate an MCP request. OAuth lets the person connecting the client choose scopes before EmDash issues the token.

To disable it, set `mcp: false` in your Astro configuration:

```js title="astro.config.mjs"
emdash({
	mcp: false,
});
```

## Connect an AI client

Your site's MCP server URL is:

```
https://example.com/_emdash/api/mcp
```

Replace `example.com` with your domain. For local development, use `http://localhost:4321/_emdash/api/mcp`.

#### Claude

Add the URL as a remote custom connector. Claude opens the EmDash OAuth flow so you can sign in and choose permissions. Anthropic changes the connector screens independently of EmDash, so follow its [current custom connector instructions](https://support.claude.com/en/articles/11175166-getting-started-with-custom-connectors-using-remote-mcp) for the exact controls and plan requirements.

#### ChatGPT

ChatGPT developer mode can connect a remote MCP server and supports OAuth-authenticated tools. Eligibility and the settings screens can change, so follow the [official ChatGPT developer mode guide](https://developers.openai.com/api/docs/guides/developer-mode) and use your site's MCP URL when creating the app. Review each write call before approving it.

#### Codex

Add the remote server from the Codex CLI, then start its OAuth login:

```bash
codex mcp add emdash-site --url https://example.com/_emdash/api/mcp
codex mcp login emdash-site
```

The ChatGPT desktop app, Codex CLI, and IDE extension share MCP configuration for the same Codex host. See the [official Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp) for configuration files, OAuth, and supported transports.

> **Note**
>
> Using a coding tool like VS Code, Cursor, or Windsurf? See the [MCP Server Reference](https://emdashcmseverything.com/official-docs/reference/mcp-server/) for configuration details.

## Work with site content

Once connected, you can ask the AI assistant to perform any of these operations in natural language. You don't need to know the tool names -- just describe what you want.

### Content

- **Browse content** -- "Show me the latest 10 blog posts" or "Find all draft pages"
- **Read content** -- "Get the post called 'hello-world' and summarize it"
- **Create content** -- "Write a new blog post about our summer sale" or "Create a draft page for the About section"
- **Edit content** -- "Update the pricing page to mention the new plan" or "Fix the typo in the FAQ post"
- **Publish and schedule** -- "Publish the summer sale post", "Schedule the announcement for June 1st at 9am", or "Cancel the schedule on the launch post"
- **Compare versions** -- "Show me what changed in the homepage since it was last published"
- **Manage drafts** -- "Discard the draft changes on the about page" or "Duplicate the newsletter template"
- **Translations** -- "What translations exist for the welcome post?" or "Create a French draft linked to this English post" (when i18n is enabled)

### Bylines

- **Browse bylines** -- "List the guest contributors whose names contain 'Lee'"
- **Credit content** -- "Add Priya Shah as the primary byline on this post"
- **Manage bylines** -- "Create a guest byline for Sam Rivera" or "Update this contributor's bio"
- **Translate bylines** -- "Show the locale variants of this byline"

Creating, updating, deleting, and translating bylines requires the Editor role. Content write tools accept existing byline IDs when the caller has permission to create or edit that content.

### Media

- **Browse media** -- "List all uploaded images" or "Show me PDFs in the media library"
- **Check details** -- "Get the details for this media item"
- **Upload files** -- "Upload this base64 image as `banner.png`"
- **Confirm signed uploads** -- "Confirm the upload with this storage key"
- **Update metadata** -- "Set the alt text on the hero image to 'Mountain sunset'"
- **Remove files** -- "Delete the old banner image"

`media_upload` accepts base64-encoded bytes, stores the file, registers the media item, and returns the ID and URL. It enforces the site's MIME-type and upload-size limits.

`media_create` completes a pending upload created through `POST /_emdash/api/media/upload-url`. Upload the file with the returned signed URL, then pass its `storageKey` to `media_create` from the same user account. Confirmation checks that the stored file exists and matches the size supplied when the upload URL was requested. This workflow requires Author or a higher role; Contributors can use `media_upload`.

### Search

- **Find content** -- "Search for posts mentioning 'accessibility'" or "Find anything about TypeScript across all collections"

### Taxonomies

- **Browse** -- "List all categories" or "Show me the tags"
- **Create terms** -- "Add a 'tutorials' tag" or "Create a 'Frontend' subcategory under 'Engineering'"
- **Rename terms** -- "Rename the 'frontend' category to 'Web Frontend'"
- **Move terms** -- "Move the 'tutorials' tag under the 'guides' category" or "Detach 'react' from its parent"
- **Delete terms** -- "Delete the unused 'archive' tag"

### Menus

- **View menus** -- "Show me the main navigation menu" or "What's in the footer menu?"
- **Create menus** -- "Create a new 'sidebar' menu"
- **Edit menus** -- "Rename the 'main' menu to 'Primary navigation'"
- **Set items** -- "Replace the items in the main menu with Home, Blog, About, and Contact"
- **Delete menus** -- "Delete the unused 'mobile' menu"

### Site settings

- **Inspect** -- "What's the current site title?" or "Show me the social links"
- **Update identity** -- "Set the site title to 'Acme Blog' and tagline to 'Stories from the team'"
- **Set logo / favicon** -- "Use this image as the site logo" (after uploading it with `media_upload`)
- **SEO defaults** -- "Set the default OG image to the new banner" or "Update the title separator to a vertical bar"
- **Social handles** -- "Add our GitHub and YouTube links to the social settings"

> **Note**
>
> Reading site settings requires the Editor role; updating them requires Admin.

### Schema (Admin only)

- **Inspect** -- "What collections exist?" or "Show me the fields on the posts collection"
- **Create collections** -- "Create a new 'testimonials' collection with name and quote fields"
- **Modify schema** -- "Add a 'featured' boolean field to posts"

> **Caution**
>
> Schema changes modify the database structure and can delete stored field data. They require Admin
> permissions, and EmDash rejects the tool call when the connected user or token lacks them.

### Revisions

- **View history** -- "Show the revision history for this post"
- **Restore** -- "Restore the post to its previous version"

## Permissions

When an MCP client opens the OAuth consent page, every permission it requested is selected by default. Clear any permission the client does not need before approving access. The resulting token is limited to the permissions you keep selected and the permissions allowed by your EmDash role, so granting fewer permissions never increases what the client can do.

| Role | What the AI can do |
| --- | --- |
| **Admin** | Everything, including schema changes and updating site settings |
| **Editor** | Manage all content, media, bylines, taxonomies, and menus. View schema and read settings. |
| **Author** | Create content; edit and publish owned content; upload media and manage owned media. |
| **Contributor** | Create draft content, edit owned drafts, and upload media, without publishing. |

EmDash rejects a tool call when either the token scope or the user's role is insufficient. A client may explain that error, but EmDash remains the authority that enforces it.

## Tips

- **Be specific about collections.** Say "create a blog post" rather than "create a post" if you have multiple collections.
- **Ask for the schema first.** If you're unsure what fields a collection has, ask "What fields does the posts collection have?" before creating or editing content.
- **Review before publishing.** Ask the AI to create content as a draft, review it in the admin panel, then ask the AI to publish it -- or publish it yourself.
- **Use compare for review.** Before publishing, ask "Compare the live and draft versions of this post" to see exactly what will change.
- **Rich text fields use Portable Text.** The AI can write content for rich text fields, but complex formatting is best done in the admin editor.

## Let browser agents search your public site

The MCP server above is for people who manage the site. To help AI agents that run in a visitor's browser, add the `WebMcpSearch` component to your layout. In browsers that support [WebMCP](https://webmachinelearning.github.io/webmcp/), it registers a read-only `search_site` tool that the agent can call instead of scraping your pages:

```astro title="src/layouts/Base.astro"
---
import WebMcpSearch from "emdash/ui/webmcp-search";
---

<WebMcpSearch collections={["posts", "pages"]} routeMap={{ posts: "/blog/:slug" }} />
```

The tool uses the same public search API as [`LiveSearch`](https://emdashcmseverything.com/official-docs/themes/creating-themes/#add-search), so it only returns published content from collections with search enabled. It accepts `collections`, `locale`, `limit`, and `routeMap` props with the same meaning as `LiveSearch` (`limit` is capped at 100), and returns each result's title, absolute URL, collection, and a plain-text excerpt.

The component adds no database queries to page renders. The search API runs only when an agent calls the tool. In browsers without WebMCP support the component does nothing.

> **Caution**
>
> WebMCP is an experimental browser API and its shape may still change. The tool sets WebMCP's `untrustedContentHint`, which tells agents that results contain site content to treat as data rather than instructions.

## For developers

The MCP server endpoint, authentication methods, OAuth discovery, tool parameters, and error handling are documented in the [MCP Server Reference](https://emdashcmseverything.com/official-docs/reference/mcp-server/).
