内容
# Ghost 样式定制 MCP
一个 [MCP](https://modelcontextprotocol.io) 服务器,根据您现有的主题和网站数据,为您的 Ghost 博客构建自定义主题。
大多数 Ghost 集成管理内容;这个集成管理博客的外观。<br>
它为模型提供您的实际数据以进行设计:从您的实时网站提取的品牌(颜色、字体、徽标)、该页面的渲染 HTML 和 CSS、您当前的主题以及您的网站设置。<br>
您获得一个完整的、自定义的主题,可以在本地预览并在准备好时上传。
样式和视觉效果优先。下面的身份验证客户端是通用的,因此 Ghost 管理 API(帖子、成员、标签和其他资源)的其余部分作为薄工具包装出现,从而将这些功能扩展为一个完整的管理服务器。
## 状态
正在开发:身份验证、视觉效果、主题生成/预览/上传、网站设置以及内容 + 受众管理(帖子、标签、成员、新闻通讯)。路线图:
- [x] 身份验证的 Admin API 客户端(通用浏览/读取/添加/编辑/删除)
- [x] **视觉效果**:`extract_brand` 提炼实时网站的品牌 + 导航;`get_theme_structure` 获取其标记 + CSS;`check_contrast` 根据 WCAG 对颜色对进行评分
- [x] **主题**:生成、预览本地、上传、重新设计、列出、下载和(有保护)激活主题
- [x] **网站设置**:读取/更新品牌 + SEO 元数据(标题、描述、强调色、元/OG/Twitter)和导航菜单
- [x] **管理**:帖子、标签、成员和新闻通讯作为 CRUD 工具
- [x] **引导流程**:`theme-a-site` 提示和服务器指令块编码品牌优先的工作流程
- [ ] **管理**:需要时新增层级、优惠和用户(下一个)
## 工具
服务器向模型公开这些工具:
**视觉效果**
- `extract_brand`:将实时网站提炼成干净的品牌令牌(颜色调色板、标题/正文字体、徽标、按钮样式)以及其导航菜单(头部/页脚内容链接,登录/注册/账户链接单独标记)以进行设计。
- `get_theme_structure`:获取实时页面的 HTML 骨架和链接的 CSS,以便样式目标选择器实际存在。
- `check_contrast`:两个颜色之间的 WCAG 对比度(以及 AA/AAA 通过级别),以便文本在强调色上保持可读。
**主题**
- `create_theme`:从 CSS 设计(和可选的 `index`/`post`/`page`/`default` 模板覆盖)生成一个完整、有效、可预览的主题。
- `preview_theme`:在本地渲染主题并在 localhost 上提供服务,以便在发布前审查。
- `upload_theme`:打包并上传主题;它安装 **inactive**,因此实时网站不受影响。
- `restyle_theme`:编辑已安装主题的样式表(追加或替换)并重新上传,以便迭代主题而不需重新生成。
- `list_themes`:列出已安装的主题和哪个是活动的。
- `download_theme`:下载已安装主题的源代码作为 zip。
- `activate_theme`:使已安装的主题成为实时主题 — **外向**;仅在明确的用户指令下,而不是自动遵循上传/重新设计。
**图片**
- `upload_image`:上传本地图像文件;返回用于帖子的 `feature_image`、网站徽标/图标或新闻通讯标题的托管 URL。
- `upload_image_from_url`:从公共 URL 获取图像(在与视觉效果相同的 SSRF 防护下)并在博客上重新托管。
**网站设置**
- `get_site_settings`:读取品牌和 SEO 设置。
- `update_site_metadata`:网站标题/描述以及 SEO 和社交元数据(`meta_*`、Open Graph、Twitter 卡片)。
- `update_branding`:品牌强调色。
- `update_navigation`:设置主要(头部)和次要(页脚)导航菜单。
**帖子**
- `list_posts` / `get_post`:浏览帖子或读取一个(带有渲染的 HTML 和草稿 `preview_url`)。
- `create_post` / `update_post` / `delete_post`:从 HTML 编写帖子;默认为草稿。
- `publish_post`:发布帖子 **并将其发送** 给新闻通讯的成员(外向;故意、明确的发送,而不是编辑的副作用)。
**页面**
- `list_pages` / `get_page`:浏览独立页面(关于、联系、...)或读取一个(带有渲染的 HTML 和 `preview_url`)。
- `create_page` / `update_page` / `delete_page`:从 HTML 编写页面;默认为草稿。页面共享帖子字段,但没有标签或 feed 位置。
**标签**
- `list_tags` / `get_tag`:浏览标签(带有帖子计数)或读取一个。
- `create_tag` / `update_tag` / `delete_tag`:管理标签。
**成员**
- `list_members` / `get_member`:浏览成员(按 `status:paid`、 `label:vip` 等筛选)或读取一个,带有标签和订阅的新闻通讯。
- `create_member` / `update_member`:从电子邮件添加成员;设置姓名、备注、标签和新闻通讯订阅。
**新闻通讯**
- `list_newsletters` / `get_newsletter`:浏览新闻通讯或读取一个。
- `create_newsletter` / `update_newsletter`:创建和配置新闻通讯;通过 `status: archived` 退休一个(API 没有删除)。
**层级**
- `list_tiers` / `get_tier`:浏览付费计划(带有价格和权益)或读取一个。
- `create_tier` / `update_tier`:创建和配置层级;没有删除(通过 `active: false` 退休)。
**优惠**
- `list_offers` / `get_offer`:浏览折扣优惠(每个都有链接的层级)或读取一个。
- `create_offer` / `update_offer`:针对层级创建优惠;没有删除(Ghost 只允许在创建后编辑名称/代码/显示字段)。
**标签**
- `list_labels` / `get_label`:浏览成员标签或读取一个。
- `create_label` / `update_label` / `delete_label`:管理成员分段标签。
**用户**
- `list_users` / `get_user`:浏览作者/工作人员或读取一个。 **只读** — 管理 API 禁止集成写入用户。
激活主题故意 **不是** 一个工具:它更改实时网站,因此它仍然是一个手动步骤。Admin API 没有删除成员、新闻通讯、层级或优惠,因此该服务器也没有;用户是只读的。
### 引导工作流程
服务器附带一个 `instructions` 块(始终在模型的上下文中)编码推荐的顺序(提取品牌、确认方向、构建、预览,然后上传不活动),以及用户可以调用的 **`theme-a-site` 提示** 以启动该引导流程。因为这些指令在每次连接时发送到模型,因此任何安装服务器的人都可以简单地问他们的助手 *"如何使用它?"* 并获得最佳实践的演练。
- **[docs/theming-guide.md](docs/theming-guide.md)** — 面向用户的最佳实践指南:如何使用它、端到端的主题路径以及设计/颜色/SEO 最佳实践。从这里开始。
- **[docs/theme-conventions.md](docs/theme-conventions.md)** — 完整的模板和 CSS 合同,用于手写模板。
## 需求
- 一个 **MCP 客户端** 来运行它,例如 [Claude Desktop](https://claude.ai/download)、Cline 或 Claude Code。此服务器是一个 MCP 服务器;在其自己的服务器上运行。
- Python 3.13+
- [uv](https://docs.astral.sh/uv/)
- 一个 Ghost 网站和一个 **工作人员访问令牌**(来自 Ghost Admin 中的用户配置文件页面)。网站范围的样式和管理员需要具有 **所有者或管理员** 角色的令牌。
## 安装
```bash
git clone https://github.com/stemcreations/ghost-mcp.git && cd ghost-mcp
uv sync # 创建 .venv 并安装所有内容
```
服务器从环境变量中读取其配置:
| 变量 | 必需 | 示例 |
|----------|----------|---------|
| `GHOST_ADMIN_URL` | 是 | `https://yourblog.example.com` |
| `GHOST_STAFF_ACCESS_TOKEN` | 是 | `<id>:<secret>` (来自 Ghost 用户配置文件) |
| `GHOST_API_VERSION` | 否 | `v6.0` (默认;匹配您的 Ghost 主版本号) |
您可以 **任选** 以下方式之一:
- **在您的 MCP 客户端**:将它们放在服务器的 `env` 块中(参见 [运行](#运行))。不需要 `.env` 文件;这是 Claude Desktop 的通常设置。
- **在本地 `.env` 中**:适用于开发和连接检查:`cp .env.example .env` 并填写。 (如果两者都已设置,客户端的 `env` 值将获胜。)
确认凭证到达您的网站:
```bash
uv run python scripts/check_connection.py
```
## 运行
与 MCP 检查器交互:
```bash
uv run fastmcp dev src/ghost_mcp/server.py
```
### 连接到 Claude Desktop
将服务器添加到下面的配置文件中,然后 **完全重启 Claude Desktop** (它只在启动时读取配置文件)。
| 操作系统 | 配置文件 |
|----|-------------|
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
使用 `uv` 的 **完整路径** 作为 `command`;客户端通常不在他们的 PATH 中。找到它使用 `(Get-Command uv).Source` (Windows PowerShell)或 `which uv` (macOS/Linux)。 `--directory` 指向 `uv` 到项目,因此自动加载项目的 `.env` (或通过 `env` 块传递凭证,参见下文)。
**Windows:**
```json
{
"mcpServers": {
"ghost": {
"command": "C:\\Users\\you\\.local\\bin\\uv.exe",
"args": ["run", "--directory", "C:\\path\\to\\ghost-mcp", "ghost-mcp"]
}
}
}
```
**macOS / Linux:**
```json
{
"mcpServers": {
"ghost": {
"command": "/home/you/.local/bin/uv",
"args": ["run", "--directory", "/home/you/ghost-mcp", "ghost-mcp"]
}
}
}
```
与任何 MCP 客户端(Cline、Claude Code、...)相同的 `command`/`args`;唯一的区别是配置文件位置。要通过客户端传递凭证而不是 `.env`,请在服务器条目中添加 `env` 块:
```json
"env": {
"GHOST_ADMIN_URL": "https://yourblog.example.com",
"GHOST_STAFF_ACCESS_TOKEN": "<id>:<secret>",
"GHOST_API_VERSION": "v6.0"
}
```
### 无需克隆即可运行
要跳过 `git clone`,请使用 `uvx` 从仓库安装并运行服务器。将以下内容添加到同一个配置文件中(使用 `uvx` 的完整路径,如果您的客户端不在 PATH 中):
```json
{
"mcpServers": {
"ghost": {
"command": "uvx",
"args": ["--from", "git+https://github.com/stemcreations/ghost-mcp.git", "ghost-mcp"],
"env": {
"GHOST_ADMIN_URL": "https://yourblog.example.com",
"GHOST_STAFF_ACCESS_TOKEN": "<id>:<secret>",
"GHOST_API_VERSION": "v6.0"
}
}
}
}
```
`uvx` 在首次启动时获取并构建包(必须安装 git)。如果没有本地 `.env`,凭证来自上面的 `env` 块。
## 简要身份验证
Ghost 的 Admin API 从不直接获取令牌。每个请求都带有从工作人员令牌(`id:secret`)签名的 JWT:用冒号分隔,十六进制解码秘密,HS256 签名并带有五分钟的过期时间。 `ghost_mcp.admin.auth` 为您处理此操作。
网站范围的样式(通过 `/settings/` 进行代码注入)需要 **所有者或管理员** 角色;标准的集成密钥无法访问这些端点。
## 架构
该包分层以便每个部分都有一个工作:
| 层 | 模块 | 责任 |
|--------|--------------------|-------------------------------------------------------|
| 配置 | `ghost_mcp.config` | 加载和验证环境配置。 |
| 错误 | `ghost_mcp.errors` | 共享的 `GhostError` 异常层次结构。 |
| Admin | `ghost_mcp.admin` | 身份验证的 Admin API:令牌签名、通用客户端、主题 + 设置助手。 |
| 视觉效果 | `ghost_mcp.vision` | 获取公共渲染页面 + CSS(无身份验证)。 |
| 主题 | `ghost_mcp.theme` | 生成、本地预览和打包主题。 |
| 工具 | `ghost_mcp.tools` | 上述层的薄 MCP 包装器。 |
| 服务器 | `ghost_mcp.server` | 将层组装成一个可运行的服务器。 |
Admin API 是统一的:每个资源都共享相同的浏览/读取/添加/编辑/删除形状,因此 `GhostAdminClient` 以通用方式实现这些操作。新的资源是一个薄工具模块,而不是新的子系统。
该服务器是 **纯 Python**。Ghost 自己的工具是 JavaScript,但这里不需要:样式处理 CSS 字符串和主题 zip,帖子内容可以通过 Admin API 的 `?source=html` 转换发送为 HTML,而不是在客户端转换为 Lexical。
## 贡献
最重要的约定:**将逻辑放在服务模块(`admin/`、`vision/`、`theme/`)中作为普通、有类型、可测试的函数,然后通过 `tools/` 中的薄包装器公开它。** 工具适配和塑造数据;它们不包含业务逻辑。
要添加一组工具:
1. 用普通函数在相关服务模块中编写逻辑并测试它。
2. 添加 `tools/<name>.py` 并包含一个 `register(mcp)` 函数来包装它。
3. 从 `tools/__init__.py` 中的 `register_all` 调用您的 `register`。
约定:
- 为所有内容添加类型提示。
- 文档字符串放在函数 **内部** (FastMCP 读取它们以向模型描述工具)。保持简洁;将较长的上下文放在模块文档字符串中。
- 为阅读源代码的人员编写文档字符串:清晰,无实现噪音。
在打开 PR 之前:
```bash
uv run ruff format # 格式化
uv run ruff check # 检查
uv run pytest # 测试
```
或者安装 git 钩子以在每次提交前自动运行所有三个:
```bash
uv run pre-commit install
```
## 安全
Ghost MCP 在本地运行,从不通过任何工具公开您的员工令牌。参见 [SECURITY.md](SECURITY.md) 以了解安全模型、提示注入信任边界以及如何报告漏洞。
## 许可证
MIT。参见 [LICENSE](LICENSE)。