@zyzy-org/blog-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -0
- package/LICENSE +21 -0
- package/PROJECT_STRUCTURE.md +67 -0
- package/PUBLISH_GUIDE.md +70 -0
- package/README.md +147 -0
- package/SETUP.md +96 -0
- package/USAGE.md +89 -0
- package/dist/blog-client.d.ts +9 -0
- package/dist/blog-client.d.ts.map +1 -0
- package/dist/blog-client.js +63 -0
- package/dist/blog-client.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +10 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +106 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/tools.d.ts +3 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +106 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/example-config.md +34 -0
- package/package.json +45 -0
- package/src/blog-client.ts +66 -0
- package/src/config.ts +56 -0
- package/src/index.ts +25 -0
- package/src/mcp-server.ts +113 -0
- package/src/tools.ts +104 -0
- package/src/types.ts +50 -0
- package/test-config.js +27 -0
- package/tsconfig.json +19 -0
package/.env.example
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Blog MCP Server 配置模板
|
|
2
|
+
# 复制此文件为 .env 并填入你的实际配置
|
|
3
|
+
|
|
4
|
+
# 博客配置
|
|
5
|
+
BLOG_URL=https://your-blog.com
|
|
6
|
+
BLOG_LOCAL_URL=http://localhost:3000
|
|
7
|
+
|
|
8
|
+
# MCP 认证配置
|
|
9
|
+
MCP_SECRET=your-mcp-secret-here
|
|
10
|
+
MCP_CLIENT_ID=your-client-id
|
|
11
|
+
MCP_SIGNATURE_SECRET=your-signature-secret
|
|
12
|
+
|
|
13
|
+
# 环境配置
|
|
14
|
+
NODE_ENV=production
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ziyouzhiyi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# 项目结构
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
yy-blog-generate-post-mcp-server/
|
|
5
|
+
├── src/ # TypeScript 源代码
|
|
6
|
+
│ ├── index.ts # 主入口文件
|
|
7
|
+
│ ├── types.ts # 类型定义
|
|
8
|
+
│ ├── config.ts # 配置解析
|
|
9
|
+
│ ├── blog-client.ts # 博客 API 客户端
|
|
10
|
+
│ ├── mcp-server.ts # MCP 服务器实现
|
|
11
|
+
│ └── tools.ts # MCP 工具定义
|
|
12
|
+
├── dist/ # 编译后的 JavaScript 文件
|
|
13
|
+
├── package.json # 项目配置和依赖
|
|
14
|
+
├── tsconfig.json # TypeScript 配置
|
|
15
|
+
├── README.md # 项目说明文档
|
|
16
|
+
├── LICENSE # MIT 许可证
|
|
17
|
+
├── PUBLISH.md # 发布指南
|
|
18
|
+
├── example-config.md # 配置示例
|
|
19
|
+
├── test-mcp.js # 测试脚本
|
|
20
|
+
└── .gitignore # Git 忽略文件
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 核心文件说明
|
|
24
|
+
|
|
25
|
+
### src/index.ts
|
|
26
|
+
主入口文件,负责启动 MCP 服务器。
|
|
27
|
+
|
|
28
|
+
### src/config.ts
|
|
29
|
+
解析命令行参数,验证必需配置。
|
|
30
|
+
|
|
31
|
+
### src/blog-client.ts
|
|
32
|
+
博客 API 客户端,处理与你的博客后端的通信。
|
|
33
|
+
|
|
34
|
+
### src/mcp-server.ts
|
|
35
|
+
MCP 协议服务器实现,处理 AI 助手的请求。
|
|
36
|
+
|
|
37
|
+
### src/tools.ts
|
|
38
|
+
定义可用的 MCP 工具(create_blog_post, create_multiple_blog_posts)。
|
|
39
|
+
|
|
40
|
+
### src/types.ts
|
|
41
|
+
TypeScript 类型定义,确保类型安全。
|
|
42
|
+
|
|
43
|
+
## 构建和运行
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# 安装依赖
|
|
47
|
+
npm install
|
|
48
|
+
|
|
49
|
+
# 构建项目
|
|
50
|
+
npm run build
|
|
51
|
+
|
|
52
|
+
# 测试配置
|
|
53
|
+
npm test
|
|
54
|
+
|
|
55
|
+
# 启动服务器
|
|
56
|
+
npm start
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 发布和使用
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# 发布到 npm
|
|
63
|
+
npm run publish-package
|
|
64
|
+
|
|
65
|
+
# 在 Cursor 中使用
|
|
66
|
+
npx -y @zyzy-org/blog-mcp-server@latest
|
|
67
|
+
```
|
package/PUBLISH_GUIDE.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# 发布指南
|
|
2
|
+
|
|
3
|
+
## 🚀 发布到 npm
|
|
4
|
+
|
|
5
|
+
### 1. 准备发布
|
|
6
|
+
|
|
7
|
+
确保你已经完成了以下步骤:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 构建项目
|
|
11
|
+
npm run build
|
|
12
|
+
|
|
13
|
+
# 测试配置
|
|
14
|
+
npm test
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. 登录 npm
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# 确保使用官方 npm 源
|
|
21
|
+
npm config set registry https://registry.npmjs.org/
|
|
22
|
+
|
|
23
|
+
# 登录到 npm
|
|
24
|
+
npm login
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. 发布包
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# 发布包
|
|
31
|
+
npm run publish-package
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 📦 包信息
|
|
35
|
+
|
|
36
|
+
- **包名**: `@zyzy-org/blog-mcp-server`
|
|
37
|
+
- **版本**: 1.0.0
|
|
38
|
+
- **访问权限**: public
|
|
39
|
+
- **描述**: 私人博客 MCP 服务器
|
|
40
|
+
|
|
41
|
+
## 🔒 安全注意事项
|
|
42
|
+
|
|
43
|
+
- ✅ `.env` 文件不会被发布(已在 `.gitignore` 中)
|
|
44
|
+
- ✅ 敏感信息只存储在本地环境变量中
|
|
45
|
+
- ✅ 包中只包含必要的源代码和文档
|
|
46
|
+
|
|
47
|
+
## 🎯 发布后使用
|
|
48
|
+
|
|
49
|
+
发布成功后,你可以在 Cursor 中使用:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx -y @zyzy-org/blog-mcp-server@latest
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 🚨 故障排除
|
|
56
|
+
|
|
57
|
+
### npm 认证问题
|
|
58
|
+
如果遇到认证问题,请检查:
|
|
59
|
+
1. 是否使用了正确的 npm 源
|
|
60
|
+
2. 是否已正确登录
|
|
61
|
+
3. 是否有发布权限
|
|
62
|
+
|
|
63
|
+
### 版本更新
|
|
64
|
+
更新版本时:
|
|
65
|
+
```bash
|
|
66
|
+
npm version patch # 小版本更新
|
|
67
|
+
npm version minor # 次版本更新
|
|
68
|
+
npm version major # 主版本更新
|
|
69
|
+
npm run publish-package
|
|
70
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Blog MCP Server
|
|
2
|
+
|
|
3
|
+
> 自动在你的技术博客中创建文章的 MCP 服务器
|
|
4
|
+
|
|
5
|
+
这个 MCP (Model Context Protocol) 服务器允许 AI 助手(如 Cursor、Claude 等)直接在你的技术博客中创建文章,无需手动编辑。
|
|
6
|
+
|
|
7
|
+
## 🎯 项目目标
|
|
8
|
+
|
|
9
|
+
参考 [Supabase MCP](https://github.com/supabase-community/supabase-mcp) 的项目结构,创建一个完整的、可发布的 MCP 服务包,让 AI 助手能够直接在你的博客中创建文章。
|
|
10
|
+
|
|
11
|
+
## ✨ 功能特性
|
|
12
|
+
|
|
13
|
+
- 🚀 **自动创建文章**: AI 可以直接创建完整的博客文章
|
|
14
|
+
- 📝 **Markdown 支持**: 支持完整的 Markdown 格式
|
|
15
|
+
- 🏷️ **标签管理**: 自动创建和管理文章标签
|
|
16
|
+
- 🔒 **安全认证**: 支持签名验证和客户端白名单
|
|
17
|
+
- 📦 **批量操作**: 支持批量创建多篇文章
|
|
18
|
+
- ⚡ **实时发布**: 文章创建后立即可见
|
|
19
|
+
- 🔧 **TypeScript**: 完整的类型安全支持
|
|
20
|
+
- 📦 **npm 包**: 可直接通过 npx 安装使用
|
|
21
|
+
|
|
22
|
+
## 🚀 快速开始
|
|
23
|
+
|
|
24
|
+
### 1. 配置环境变量
|
|
25
|
+
|
|
26
|
+
复制 `.env.example` 为 `.env` 并填入你的配置:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cp .env.example .env
|
|
30
|
+
# 编辑 .env 文件,填入你的实际配置
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. 在 Cursor 中配置
|
|
34
|
+
|
|
35
|
+
在你的 Cursor 设置中添加以下 MCP 服务器:
|
|
36
|
+
|
|
37
|
+
#### 生产环境
|
|
38
|
+
```bash
|
|
39
|
+
npx -y @zyzy-org/blog-mcp-server@latest
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### 本地开发
|
|
43
|
+
```bash
|
|
44
|
+
npx -y @zyzy-org/blog-mcp-server@latest --local
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## ⚙️ 配置参数
|
|
48
|
+
|
|
49
|
+
### 环境变量配置(推荐)
|
|
50
|
+
在 `.env` 文件中配置:
|
|
51
|
+
|
|
52
|
+
- `BLOG_URL`: 你的博客 API 地址(必需)
|
|
53
|
+
- `MCP_SECRET`: MCP 共享密钥(必需)
|
|
54
|
+
- `MCP_CLIENT_ID`: 客户端标识(可选,默认为 'blog-mcp-client')
|
|
55
|
+
- `MCP_SIGNATURE_SECRET`: 签名密钥(可选,用于额外安全验证)
|
|
56
|
+
- `BLOG_LOCAL_URL`: 本地开发地址(可选)
|
|
57
|
+
|
|
58
|
+
### 命令行参数(可选)
|
|
59
|
+
- `--blog-url`: 覆盖环境变量中的博客地址
|
|
60
|
+
- `--secret`: 覆盖环境变量中的密钥
|
|
61
|
+
- `--client-id`: 覆盖环境变量中的客户端ID
|
|
62
|
+
- `--signature-secret`: 覆盖环境变量中的签名密钥
|
|
63
|
+
- `--local`: 使用本地开发环境
|
|
64
|
+
|
|
65
|
+
## 🛠️ 可用工具
|
|
66
|
+
|
|
67
|
+
### create_blog_post
|
|
68
|
+
创建单篇博客文章
|
|
69
|
+
|
|
70
|
+
**参数:**
|
|
71
|
+
- `title` (string): 文章标题
|
|
72
|
+
- `content` (string): 文章内容(Markdown 格式)
|
|
73
|
+
- `tags` (array): 文章标签
|
|
74
|
+
- `author` (string): 作者名称
|
|
75
|
+
- `readTime` (number): 预计阅读时间(分钟)
|
|
76
|
+
- `date` (string): 发布日期(ISO 8601 格式)
|
|
77
|
+
- `github_url` (string): 相关的 GitHub 链接
|
|
78
|
+
- `slug` (string): 自定义文章 slug
|
|
79
|
+
|
|
80
|
+
### create_multiple_blog_posts
|
|
81
|
+
批量创建多篇博客文章
|
|
82
|
+
|
|
83
|
+
**参数:**
|
|
84
|
+
- `articles` (array): 要创建的文章数组
|
|
85
|
+
|
|
86
|
+
## 🔒 安全特性
|
|
87
|
+
|
|
88
|
+
- 使用共享密钥进行基础认证
|
|
89
|
+
- 支持时间戳验证防止重放攻击
|
|
90
|
+
- 可选的签名验证提供额外安全层
|
|
91
|
+
- 支持客户端白名单限制访问
|
|
92
|
+
- 完整的错误处理和日志记录
|
|
93
|
+
|
|
94
|
+
## 🧪 测试
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 构建项目
|
|
98
|
+
npm run build
|
|
99
|
+
|
|
100
|
+
# 启动 MCP 服务器
|
|
101
|
+
npm start
|
|
102
|
+
|
|
103
|
+
# 或者直接运行
|
|
104
|
+
node dist/index.js
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 🛠️ 开发
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# 安装依赖
|
|
111
|
+
npm install
|
|
112
|
+
|
|
113
|
+
# 构建
|
|
114
|
+
npm run build
|
|
115
|
+
|
|
116
|
+
# 开发模式
|
|
117
|
+
npm run dev
|
|
118
|
+
|
|
119
|
+
# 本地测试
|
|
120
|
+
npm run test
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 📁 项目结构
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
src/
|
|
127
|
+
├── index.ts # 主入口文件
|
|
128
|
+
├── types.ts # 类型定义
|
|
129
|
+
├── config.ts # 配置解析
|
|
130
|
+
├── blog-client.ts # 博客 API 客户端
|
|
131
|
+
├── mcp-server.ts # MCP 服务器实现
|
|
132
|
+
└── tools.ts # MCP 工具定义
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 📚 相关文档
|
|
136
|
+
|
|
137
|
+
- [USAGE.md](./USAGE.md) - 详细使用指南
|
|
138
|
+
- [PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md) - 项目结构说明
|
|
139
|
+
- [example-config.md](./example-config.md) - 配置示例
|
|
140
|
+
|
|
141
|
+
## 🤝 贡献
|
|
142
|
+
|
|
143
|
+
欢迎提交 Issue 和 Pull Request!
|
|
144
|
+
|
|
145
|
+
## 📄 许可证
|
|
146
|
+
|
|
147
|
+
MIT License - 详见 [LICENSE](./LICENSE) 文件
|
package/SETUP.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# 私人 MCP 服务器设置指南
|
|
2
|
+
|
|
3
|
+
## 🎯 项目说明
|
|
4
|
+
|
|
5
|
+
这是一个专为你的博客定制的私人 MCP 服务器,所有敏感信息都存储在 `.env` 文件中,确保安全性。
|
|
6
|
+
|
|
7
|
+
## 🚀 快速设置
|
|
8
|
+
|
|
9
|
+
### 1. 环境配置
|
|
10
|
+
|
|
11
|
+
项目已经为你配置好了 `.env` 文件,包含所有必要的密钥:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 博客配置
|
|
15
|
+
BLOG_URL=https://zyzy.info
|
|
16
|
+
BLOG_LOCAL_URL=http://localhost:3000
|
|
17
|
+
|
|
18
|
+
# MCP 认证配置
|
|
19
|
+
MCP_SECRET=660649959a92f12949618a919413e83c8aad09afbb39bcc172725583037e6beb
|
|
20
|
+
MCP_CLIENT_ID=my-mcp-client
|
|
21
|
+
MCP_SIGNATURE_SECRET=c20f0c7bd9128d05c53ffc7743f483c21169f1562542c30ea6e6bf127b488e5f
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. 在 Cursor 中配置
|
|
25
|
+
|
|
26
|
+
在你的 Cursor 设置中添加以下 MCP 服务器:
|
|
27
|
+
|
|
28
|
+
#### 生产环境(推荐)
|
|
29
|
+
```bash
|
|
30
|
+
npx -y @zyzy-org/blog-mcp-server@latest
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
#### 本地开发
|
|
34
|
+
```bash
|
|
35
|
+
npx -y @zyzy-org/blog-mcp-server@latest --local
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 🛠️ 使用方法
|
|
39
|
+
|
|
40
|
+
### 创建单篇文章
|
|
41
|
+
```
|
|
42
|
+
请在我的博客中创建一篇关于 React 的文章,标题为"React Hooks 详解"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 批量创建文章
|
|
46
|
+
```
|
|
47
|
+
请在我的博客中创建三篇关于 TypeScript 的文章:
|
|
48
|
+
1. TypeScript 基础语法
|
|
49
|
+
2. TypeScript 高级特性
|
|
50
|
+
3. TypeScript 最佳实践
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 🔒 安全特性
|
|
54
|
+
|
|
55
|
+
- ✅ 所有敏感信息存储在 `.env` 文件中
|
|
56
|
+
- ✅ `.env` 文件已添加到 `.gitignore`
|
|
57
|
+
- ✅ 支持签名验证防止篡改
|
|
58
|
+
- ✅ 时间戳验证防止重放攻击
|
|
59
|
+
- ✅ 客户端白名单限制访问
|
|
60
|
+
|
|
61
|
+
## 🧪 测试
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# 测试配置是否正确
|
|
65
|
+
npm test
|
|
66
|
+
|
|
67
|
+
# 构建项目
|
|
68
|
+
npm run build
|
|
69
|
+
|
|
70
|
+
# 启动服务器
|
|
71
|
+
npm start
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 📁 项目结构
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
├── src/ # TypeScript 源代码
|
|
78
|
+
├── dist/ # 编译后的文件
|
|
79
|
+
├── .env # 环境变量配置(包含敏感信息)
|
|
80
|
+
├── .env.example # 环境变量模板
|
|
81
|
+
├── package.json # 项目配置
|
|
82
|
+
├── README.md # 项目说明
|
|
83
|
+
├── USAGE.md # 使用指南
|
|
84
|
+
└── test-config.js # 配置测试脚本
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 🚨 重要提醒
|
|
88
|
+
|
|
89
|
+
1. **不要提交 `.env` 文件** - 它包含敏感信息
|
|
90
|
+
2. **这是私人服务** - 仅适用于你的博客
|
|
91
|
+
3. **定期更新密钥** - 建议定期更换签名密钥
|
|
92
|
+
4. **本地测试** - 建议先在本地环境测试
|
|
93
|
+
|
|
94
|
+
## 🎉 完成
|
|
95
|
+
|
|
96
|
+
配置完成后,你就可以在 Cursor 中直接使用 AI 助手创建博客文章了!
|
package/USAGE.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# 使用指南
|
|
2
|
+
|
|
3
|
+
## 快速开始
|
|
4
|
+
|
|
5
|
+
### 1. 配置环境变量
|
|
6
|
+
|
|
7
|
+
复制 `.env.example` 为 `.env` 并填入你的配置:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cp .env.example .env
|
|
11
|
+
# 编辑 .env 文件,填入你的实际配置
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### 2. 在 Cursor 中配置
|
|
15
|
+
|
|
16
|
+
在你的 Cursor 设置中添加以下 MCP 服务器:
|
|
17
|
+
|
|
18
|
+
#### 生产环境配置
|
|
19
|
+
```bash
|
|
20
|
+
npx -y @zyzy-org/blog-mcp-server@latest
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
#### 本地开发配置
|
|
24
|
+
```bash
|
|
25
|
+
npx -y @zyzy-org/blog-mcp-server@latest --local
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 可用工具
|
|
29
|
+
|
|
30
|
+
### create_blog_post
|
|
31
|
+
创建单篇博客文章
|
|
32
|
+
|
|
33
|
+
**示例用法:**
|
|
34
|
+
```
|
|
35
|
+
请在我的博客中创建一篇关于 TypeScript 的文章,标题为"TypeScript 最佳实践",包含以下内容:
|
|
36
|
+
- TypeScript 基础语法
|
|
37
|
+
- 类型系统详解
|
|
38
|
+
- 最佳实践建议
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### create_multiple_blog_posts
|
|
42
|
+
批量创建多篇博客文章
|
|
43
|
+
|
|
44
|
+
**示例用法:**
|
|
45
|
+
```
|
|
46
|
+
请在我的博客中创建三篇关于 React 的文章:
|
|
47
|
+
1. React Hooks 详解
|
|
48
|
+
2. React 性能优化
|
|
49
|
+
3. React 状态管理
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 故障排除
|
|
53
|
+
|
|
54
|
+
### 1. API 连接问题
|
|
55
|
+
|
|
56
|
+
如果遇到 API 连接问题,请检查:
|
|
57
|
+
|
|
58
|
+
- 博客是否正在运行
|
|
59
|
+
- API 端点是否正确配置
|
|
60
|
+
- 认证密钥是否正确
|
|
61
|
+
- `.env` 文件配置是否正确
|
|
62
|
+
|
|
63
|
+
### 2. 生产环境问题
|
|
64
|
+
|
|
65
|
+
如果生产环境 API 返回登录页面,可能需要:
|
|
66
|
+
|
|
67
|
+
1. 检查中间件配置
|
|
68
|
+
2. 确保 API 路由正确部署
|
|
69
|
+
3. 验证认证逻辑
|
|
70
|
+
|
|
71
|
+
### 3. 本地测试
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# 构建项目
|
|
75
|
+
npm run build
|
|
76
|
+
|
|
77
|
+
# 启动 MCP 服务器
|
|
78
|
+
npm start
|
|
79
|
+
|
|
80
|
+
# 或者直接运行
|
|
81
|
+
node dist/index.js
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 安全注意事项
|
|
85
|
+
|
|
86
|
+
- 不要在公开代码中暴露密钥
|
|
87
|
+
- 定期轮换签名密钥
|
|
88
|
+
- 使用客户端白名单限制访问
|
|
89
|
+
- 监控 API 使用情况
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BlogPostData, MCPConfig } from './types';
|
|
2
|
+
export declare class BlogClient {
|
|
3
|
+
private config;
|
|
4
|
+
constructor(config: MCPConfig);
|
|
5
|
+
private generateSignature;
|
|
6
|
+
createBlogPost(postData: BlogPostData): Promise<any>;
|
|
7
|
+
createMultipleBlogPosts(articles: BlogPostData[]): Promise<any[]>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=blog-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-client.d.ts","sourceRoot":"","sources":["../src/blog-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAsB,SAAS,EAAE,MAAM,SAAS,CAAC;AAEtE,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,EAAE,SAAS;IAI7B,OAAO,CAAC,iBAAiB;IAWnB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC;IA4BpD,uBAAuB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;CAexE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BlogClient = void 0;
|
|
7
|
+
// 使用原生 fetch API
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
class BlogClient {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
generateSignature(data) {
|
|
14
|
+
if (!this.config.signatureSecret) {
|
|
15
|
+
throw new Error('签名密钥未配置');
|
|
16
|
+
}
|
|
17
|
+
return crypto_1.default
|
|
18
|
+
.createHmac('sha256', this.config.signatureSecret)
|
|
19
|
+
.update(JSON.stringify({ ...data, signature: undefined }))
|
|
20
|
+
.digest('hex');
|
|
21
|
+
}
|
|
22
|
+
async createBlogPost(postData) {
|
|
23
|
+
const secureData = {
|
|
24
|
+
...postData,
|
|
25
|
+
client_id: this.config.clientId,
|
|
26
|
+
timestamp: Date.now(),
|
|
27
|
+
};
|
|
28
|
+
if (this.config.signatureSecret) {
|
|
29
|
+
secureData.signature = this.generateSignature(secureData);
|
|
30
|
+
}
|
|
31
|
+
const response = await fetch(`${this.config.blogUrl}/api/mcp/posts`, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: {
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
'x-mcp-secret': this.config.secret,
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify(secureData)
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const errorText = await response.text();
|
|
41
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
42
|
+
}
|
|
43
|
+
return await response.json();
|
|
44
|
+
}
|
|
45
|
+
async createMultipleBlogPosts(articles) {
|
|
46
|
+
const results = [];
|
|
47
|
+
for (const article of articles) {
|
|
48
|
+
try {
|
|
49
|
+
const result = await this.createBlogPost(article);
|
|
50
|
+
results.push({ success: true, ...result });
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
results.push({
|
|
54
|
+
success: false,
|
|
55
|
+
error: error instanceof Error ? error.message : String(error)
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return results;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.BlogClient = BlogClient;
|
|
63
|
+
//# sourceMappingURL=blog-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-client.js","sourceRoot":"","sources":["../src/blog-client.ts"],"names":[],"mappings":";;;;;;AAAA,iBAAiB;AACjB,oDAA4B;AAG5B,MAAa,UAAU;IAGrB,YAAY,MAAiB;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,iBAAiB,CAAC,IAAwB;QAChD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,gBAAM;aACV,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;aACjD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;aACzD,MAAM,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,QAAsB;QACzC,MAAM,UAAU,GAAuB;YACrC,GAAG,QAAQ;YACX,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YAChC,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,gBAAgB,EAAE;YACnE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;SACjC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,QAAwB;QACpD,MAAM,OAAO,GAAG,EAAE,CAAC;QACnB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBAClD,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC;oBACX,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;iBAC9D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AA7DD,gCA6DC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAMpC,wBAAgB,WAAW,IAAI,SAAS,CAiDvC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseConfig = parseConfig;
|
|
7
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
+
// 加载环境变量
|
|
9
|
+
dotenv_1.default.config();
|
|
10
|
+
function parseConfig() {
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
// 从环境变量获取默认配置
|
|
13
|
+
const config = {
|
|
14
|
+
blogUrl: process.env.BLOG_URL,
|
|
15
|
+
secret: process.env.MCP_SECRET,
|
|
16
|
+
clientId: process.env.MCP_CLIENT_ID || 'blog-mcp-client',
|
|
17
|
+
signatureSecret: process.env.MCP_SIGNATURE_SECRET
|
|
18
|
+
};
|
|
19
|
+
// 命令行参数覆盖环境变量
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
if (arg.startsWith('--')) {
|
|
23
|
+
const key = arg.slice(2);
|
|
24
|
+
const value = args[i + 1];
|
|
25
|
+
switch (key) {
|
|
26
|
+
case 'blog-url':
|
|
27
|
+
config.blogUrl = value;
|
|
28
|
+
break;
|
|
29
|
+
case 'secret':
|
|
30
|
+
config.secret = value;
|
|
31
|
+
break;
|
|
32
|
+
case 'client-id':
|
|
33
|
+
config.clientId = value;
|
|
34
|
+
break;
|
|
35
|
+
case 'signature-secret':
|
|
36
|
+
config.signatureSecret = value;
|
|
37
|
+
break;
|
|
38
|
+
case 'local':
|
|
39
|
+
// 使用本地开发环境
|
|
40
|
+
config.blogUrl = process.env.BLOG_LOCAL_URL || 'http://localhost:3000';
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// 验证必需参数
|
|
46
|
+
if (!config.blogUrl) {
|
|
47
|
+
throw new Error('BLOG_URL 环境变量或 --blog-url 参数是必需的');
|
|
48
|
+
}
|
|
49
|
+
if (!config.secret) {
|
|
50
|
+
throw new Error('MCP_SECRET 环境变量或 --secret 参数是必需的');
|
|
51
|
+
}
|
|
52
|
+
return config;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;AAMA,kCAiDC;AAtDD,oDAA4B;AAE5B,SAAS;AACT,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,SAAgB,WAAW;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,cAAc;IACd,MAAM,MAAM,GAAuB;QACjC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;QAC7B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,iBAAiB;QACxD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;KAClD,CAAC;IAEF,cAAc;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAE1B,QAAQ,GAAG,EAAE,CAAC;gBACZ,KAAK,UAAU;oBACb,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;oBACvB,MAAM;gBACR,KAAK,QAAQ;oBACX,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;oBACtB,MAAM;gBACR,KAAK,WAAW;oBACd,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;oBACxB,MAAM;gBACR,KAAK,kBAAkB;oBACrB,MAAM,CAAC,eAAe,GAAG,KAAK,CAAC;oBAC/B,MAAM;gBACR,KAAK,OAAO;oBACV,WAAW;oBACX,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,uBAAuB,CAAC;oBACvE,MAAM;YACV,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS;IACT,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,MAAmB,CAAC;AAC7B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
const blog_client_1 = require("./blog-client");
|
|
6
|
+
const mcp_server_1 = require("./mcp-server");
|
|
7
|
+
async function main() {
|
|
8
|
+
try {
|
|
9
|
+
// 解析配置
|
|
10
|
+
const config = (0, config_1.parseConfig)();
|
|
11
|
+
// 创建博客客户端
|
|
12
|
+
const blogClient = new blog_client_1.BlogClient(config);
|
|
13
|
+
// 创建并启动 MCP 服务器
|
|
14
|
+
const server = new mcp_server_1.MCPServer(blogClient);
|
|
15
|
+
server.start();
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.error('启动失败:', error instanceof Error ? error.message : String(error));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
main();
|
|
23
|
+
//# sourceMappingURL=index.js.map
|