yescms-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/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # YESCMS MCP Server
2
+
3
+ `YESCMS.McpServer` 是给 AI 工具使用的 MCP Server。
4
+
5
+ 它把 YESCMS 的文章发布能力暴露给 Codex、Claude Code、Cursor、opencode 等 MCP 宿主,让 AI 可以读取文章类目、上传文章图片、发布 Markdown 文章。
6
+
7
+ ## 提供的工具
8
+
9
+ | 工具名 | 作用 |
10
+ |---|---|
11
+ | `yescms_list_categories` | 读取 YESCMS 文章档案类目 |
12
+ | `yescms_upload_article_image` | 上传本地图片到 YESCMS |
13
+ | `yescms_publish_article` | 发布 Markdown 文章到 YESCMS |
14
+
15
+ ## 环境要求
16
+
17
+ - Node.js 24.16.0
18
+ - npm
19
+ - 可访问的 YESCMS 站点
20
+ - 可用的 AI API Token
21
+
22
+ 进入目录后先切换 Node 版本:
23
+
24
+ ```powershell
25
+ fnm use 24.16.0
26
+ ```
27
+
28
+ ## 安装和构建
29
+
30
+ ```powershell
31
+ cd _AITools\YESCMS.McpServer
32
+ fnm use 24.16.0
33
+ npm install
34
+ npm run build
35
+ ```
36
+
37
+ 构建结果在:
38
+
39
+ ```text
40
+ _AITools/YESCMS.McpServer/dist/index.js
41
+ _AITools/YESCMS.McpServer/dist/start_fnm.cmd
42
+ ```
43
+
44
+ ## npm 打包分发
45
+
46
+ 这个项目可以按 npm 包分发,不需要把源码目录发给使用者。
47
+
48
+ 生成本地安装包:
49
+
50
+ ```powershell
51
+ cd _AITools\YESCMS.McpServer
52
+ fnm use 24.16.0
53
+ npm pack
54
+ ```
55
+
56
+ 生成的文件类似:
57
+
58
+ ```text
59
+ yescms-mcp-server-1.0.0.tgz
60
+ ```
61
+
62
+ 使用者安装本地包:
63
+
64
+ ```powershell
65
+ npm install -g .\yescms-mcp-server-1.0.0.tgz
66
+ ```
67
+
68
+ 如果发布到 npm registry,使用者可以直接运行:
69
+
70
+ ```powershell
71
+ npx -y yescms-mcp-server
72
+ ```
73
+
74
+ 包内只包含 `dist` 和 `README.md`。运行依赖会由 npm 自动安装,不需要复制源码,也不需要手动复制 `node_modules`。
75
+
76
+ ## 本地验证
77
+
78
+ ```powershell
79
+ npm run smoke
80
+ ```
81
+
82
+ 这个命令只验证 MCP 初始化和工具列表,不会访问 YESCMS,也不会发布文章。
83
+
84
+ ## MCP 宿主配置
85
+
86
+ ### Codex TOML
87
+
88
+ ```toml
89
+ [mcp_servers.yescms]
90
+ command = "npx"
91
+ args = ["-y", "yescms-mcp-server"]
92
+
93
+ [mcp_servers.yescms.env]
94
+ YESCMS_BASE_URL = "https://www.example.com"
95
+ YESCMS_AI_TOKEN = "yescms_ai_xxx"
96
+ ```
97
+
98
+ 如果使用本地 `.tgz` 包,先全局安装,再配置:
99
+
100
+ ```toml
101
+ [mcp_servers.yescms]
102
+ command = "yescms-mcp"
103
+
104
+ [mcp_servers.yescms.env]
105
+ YESCMS_BASE_URL = "https://www.example.com"
106
+ YESCMS_AI_TOKEN = "yescms_ai_xxx"
107
+ ```
108
+
109
+ ### 通用 JSON
110
+
111
+ ```json
112
+ {
113
+ "mcpServers": {
114
+ "yescms": {
115
+ "command": "npx",
116
+ "args": ["-y", "yescms-mcp-server"],
117
+ "env": {
118
+ "YESCMS_BASE_URL": "https://www.example.com",
119
+ "YESCMS_AI_TOKEN": "yescms_ai_xxx"
120
+ }
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## 配置项
127
+
128
+ | 变量名 | 必填 | 说明 |
129
+ |---|---|---|
130
+ | `YESCMS_BASE_URL` | 是 | YESCMS 网站地址,例如 `https://www.example.com` |
131
+ | `YESCMS_AI_TOKEN` | 否 | 直接传入 Token,最简单 |
132
+ | `YESCMS_AI_TOKEN_FILE` | 否 | 从文件读取 Token |
133
+ | `YESCMS_AI_TOKEN_COMMAND` | 否 | 通过命令读取 Token,值必须是 JSON 字符串数组 |
134
+ | `YESCMS_CREDENTIAL_TARGET` | 否 | Windows Credential Manager 里的凭据名 |
135
+
136
+ Token 读取顺序:
137
+
138
+ 1. 配置文件里的 Token。
139
+ 2. `YESCMS_AI_TOKEN`。
140
+ 3. `YESCMS_AI_TOKEN_FILE`。
141
+ 4. `YESCMS_AI_TOKEN_COMMAND`。
142
+ 5. Windows Credential Manager。
143
+
144
+ ## 配置文件位置
145
+
146
+ 如果没有通过环境变量传入配置,Server 会读取:
147
+
148
+ ```text
149
+ %APPDATA%\YESCMS-MCP\config.json
150
+ ```
151
+
152
+ 配置示例:
153
+
154
+ ```json
155
+ {
156
+ "baseUrl": "https://www.example.com",
157
+ "credentialTarget": "YESCMS-MCP:AI-API-Token"
158
+ }
159
+ ```
160
+
161
+ ## Token 命令格式
162
+
163
+ `YESCMS_AI_TOKEN_COMMAND` 必须是 JSON 字符串数组:
164
+
165
+ ```powershell
166
+ $env:YESCMS_AI_TOKEN_COMMAND='["powershell.exe","-NoProfile","-Command","Get-Content D:\\token.txt"]'
167
+ ```
168
+
169
+ ## 注意事项
170
+
171
+ - `yescms_publish_article` 会真实发布文章。
172
+ - `yescms_upload_article_image` 会真实上传图片。
173
+ - Windows Credential Manager 只适用于 Windows;Linux/macOS 建议使用 `YESCMS_AI_TOKEN_FILE` 或 `YESCMS_AI_TOKEN_COMMAND`。
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { registerYescmsTools } from "./tools/yescmsTools.js";
5
+ const server = new McpServer({
6
+ name: "yescms-mcp",
7
+ version: "1.0.0"
8
+ });
9
+ registerYescmsTools(server);
10
+ await server.connect(new StdioServerTransport());
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAE5B,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ export const defaultCredentialTarget = "YESCMS-MCP:AI-API-Token";
4
+ export function getAppDataDirectory() {
5
+ if (process.env.APPDATA) {
6
+ return path.join(process.env.APPDATA, "YESCMS-MCP");
7
+ }
8
+ if (process.env.XDG_CONFIG_HOME) {
9
+ return path.join(process.env.XDG_CONFIG_HOME, "YESCMS-MCP");
10
+ }
11
+ return path.join(os.homedir(), ".config", "YESCMS-MCP");
12
+ }
13
+ export function getConfigPath() {
14
+ return path.join(getAppDataDirectory(), "config.json");
15
+ }
16
+ //# sourceMappingURL=appPaths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appPaths.js","sourceRoot":"","sources":["../../src/shared/appPaths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE,MAAM,UAAU,mBAAmB;IACjC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,aAAa,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { defaultCredentialTarget, getAppDataDirectory, getConfigPath } from "./appPaths.js";
3
+ export function createDefaultConfig() {
4
+ return {
5
+ baseUrl: "",
6
+ credentialTarget: defaultCredentialTarget
7
+ };
8
+ }
9
+ export async function loadConfig() {
10
+ try {
11
+ const json = await readFile(getConfigPath(), "utf8");
12
+ const parsed = JSON.parse(json);
13
+ return {
14
+ ...createDefaultConfig(),
15
+ ...parsed
16
+ };
17
+ }
18
+ catch (error) {
19
+ if (isNodeError(error) && error.code === "ENOENT") {
20
+ return createDefaultConfig();
21
+ }
22
+ throw error;
23
+ }
24
+ }
25
+ export async function saveConfig(config) {
26
+ await mkdir(getAppDataDirectory(), { recursive: true });
27
+ await writeFile(getConfigPath(), `${JSON.stringify(config, null, 2)}\n`, "utf8");
28
+ }
29
+ function isNodeError(error) {
30
+ return error instanceof Error && "code" in error;
31
+ }
32
+ //# sourceMappingURL=configStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configStore.js","sourceRoot":"","sources":["../../src/shared/configStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG5F,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,OAAO,EAAE,EAAE;QACX,gBAAgB,EAAE,uBAAuB;KAC1C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA0B,CAAC;QACzD,OAAO;YACL,GAAG,mBAAmB,EAAE;YACxB,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClD,OAAO,mBAAmB,EAAE,CAAC;QAC/B,CAAC;QAED,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAoB;IACnD,MAAM,KAAK,CAAC,mBAAmB,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,SAAS,CAAC,aAAa,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC;AACnD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/shared/models.ts"],"names":[],"mappings":""}
@@ -0,0 +1,138 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ export async function getToken(config) {
4
+ if (config.accessToken?.trim()) {
5
+ return config.accessToken.trim();
6
+ }
7
+ if (config.tokenFile?.trim()) {
8
+ return (await readFile(config.tokenFile.trim(), "utf8")).trim();
9
+ }
10
+ if (config.tokenCommand?.trim()) {
11
+ return readFromCommand(config.tokenCommand.trim());
12
+ }
13
+ if (process.env.YESCMS_AI_TOKEN?.trim()) {
14
+ return process.env.YESCMS_AI_TOKEN.trim();
15
+ }
16
+ if (process.env.YESCMS_AI_TOKEN_FILE?.trim()) {
17
+ return (await readFile(process.env.YESCMS_AI_TOKEN_FILE.trim(), "utf8")).trim();
18
+ }
19
+ if (process.env.YESCMS_AI_TOKEN_COMMAND?.trim()) {
20
+ return readFromCommand(process.env.YESCMS_AI_TOKEN_COMMAND.trim());
21
+ }
22
+ const credentialToken = await readWindowsCredential(config.credentialTarget);
23
+ if (credentialToken?.trim()) {
24
+ return credentialToken.trim();
25
+ }
26
+ throw new Error("未找到 AI API Token。请设置 YESCMS_AI_TOKEN、YESCMS_AI_TOKEN_FILE 或 YESCMS_AI_TOKEN_COMMAND;Windows 下也可以设置 YESCMS_CREDENTIAL_TARGET。");
27
+ }
28
+ async function readFromCommand(commandJson) {
29
+ const command = JSON.parse(commandJson);
30
+ if (!Array.isArray(command) || command.length === 0 || command.some((item) => typeof item !== "string" || item.trim() === "")) {
31
+ throw new Error("YESCMS_AI_TOKEN_COMMAND 必须是 JSON 字符串数组。");
32
+ }
33
+ return runProcess(command[0], command.slice(1));
34
+ }
35
+ async function readWindowsCredential(target) {
36
+ if (process.platform !== "win32" || !target.trim()) {
37
+ return null;
38
+ }
39
+ const script = `
40
+ param([string]$Target)
41
+ Add-Type -TypeDefinition @"
42
+ using System;
43
+ using System.Runtime.InteropServices;
44
+ using System.Text;
45
+
46
+ public static class CredentialReader
47
+ {
48
+ private const uint CredTypeGeneric = 1;
49
+
50
+ [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
51
+ private static extern bool CredRead(string target, uint type, uint reservedFlag, out IntPtr credential);
52
+
53
+ [DllImport("advapi32.dll", SetLastError = true)]
54
+ private static extern void CredFree(IntPtr buffer);
55
+
56
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
57
+ private struct NativeCredential
58
+ {
59
+ public uint Flags;
60
+ public uint Type;
61
+ public string TargetName;
62
+ public string Comment;
63
+ public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
64
+ public uint CredentialBlobSize;
65
+ public IntPtr CredentialBlob;
66
+ public uint Persist;
67
+ public uint AttributeCount;
68
+ public IntPtr Attributes;
69
+ public string TargetAlias;
70
+ public string UserName;
71
+ }
72
+
73
+ public static string Read(string target)
74
+ {
75
+ if (!CredRead(target, CredTypeGeneric, 0, out var pointer))
76
+ {
77
+ return "";
78
+ }
79
+
80
+ try
81
+ {
82
+ var credential = Marshal.PtrToStructure<NativeCredential>(pointer);
83
+ if (credential.CredentialBlob == IntPtr.Zero || credential.CredentialBlobSize == 0)
84
+ {
85
+ return "";
86
+ }
87
+
88
+ var bytes = new byte[credential.CredentialBlobSize];
89
+ Marshal.Copy(credential.CredentialBlob, bytes, 0, bytes.Length);
90
+ return Encoding.Unicode.GetString(bytes).TrimEnd('\\0');
91
+ }
92
+ finally
93
+ {
94
+ CredFree(pointer);
95
+ }
96
+ }
97
+ }
98
+ "@
99
+ [CredentialReader]::Read($Target)
100
+ `;
101
+ const stdout = await runProcess("powershell.exe", [
102
+ "-NoProfile",
103
+ "-NonInteractive",
104
+ "-ExecutionPolicy",
105
+ "Bypass",
106
+ "-Command",
107
+ script,
108
+ target
109
+ ]);
110
+ return stdout.trim() || null;
111
+ }
112
+ async function runProcess(fileName, args) {
113
+ return new Promise((resolve, reject) => {
114
+ const child = spawn(fileName, args, {
115
+ windowsHide: true,
116
+ stdio: ["ignore", "pipe", "pipe"]
117
+ });
118
+ let stdout = "";
119
+ let stderr = "";
120
+ child.stdout.setEncoding("utf8");
121
+ child.stderr.setEncoding("utf8");
122
+ child.stdout.on("data", (chunk) => {
123
+ stdout += chunk;
124
+ });
125
+ child.stderr.on("data", (chunk) => {
126
+ stderr += chunk;
127
+ });
128
+ child.on("error", reject);
129
+ child.on("close", (code) => {
130
+ if (code === 0) {
131
+ resolve(stdout.trim());
132
+ return;
133
+ }
134
+ reject(new Error(`读取 Token 命令失败:${stderr.trim()}`));
135
+ });
136
+ });
137
+ }
138
+ //# sourceMappingURL=tokenProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenProvider.js","sourceRoot":"","sources":["../../src/shared/tokenProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAoB;IACjD,IAAI,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClE,CAAC;IAED,IAAI,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC;QAChC,OAAO,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC;QACxC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,IAAI,EAAE,EAAE,CAAC;QAC7C,OAAO,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClF,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,IAAI,EAAE,EAAE,CAAC;QAChD,OAAO,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC7E,IAAI,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC;QAC5B,OAAO,eAAe,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,8HAA8H,CAAC,CAAC;AAClJ,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,WAAmB;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAY,CAAC;IACnD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC9H,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,MAAc;IACjD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DhB,CAAC;IAEA,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,gBAAgB,EAAE;QAChD,YAAY;QACZ,iBAAiB;QACjB,kBAAkB;QAClB,QAAQ;QACR,UAAU;QACV,MAAM;QACN,MAAM;KACP,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;AAC/B,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,IAAc;IACxD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE;YAClC,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC;QAClB,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC;QAClB,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { getToken } from "./tokenProvider.js";
4
+ export class YescmsApiClient {
5
+ async publishArticle(config, request) {
6
+ validateConfig(config);
7
+ const token = await getToken(config);
8
+ const response = await fetch(buildUrl(config.baseUrl, "/api/Article/PublishFromAI"), {
9
+ method: "POST",
10
+ headers: {
11
+ "Authorization": `Bearer ${token}`,
12
+ "Content-Type": "application/json"
13
+ },
14
+ body: JSON.stringify(request)
15
+ });
16
+ return readResponse(response);
17
+ }
18
+ async getArchiveCategories(config) {
19
+ validateConfig(config);
20
+ const token = await getToken(config);
21
+ const response = await fetch(buildUrl(config.baseUrl, "/api/Article/ArchiveCategories"), {
22
+ headers: {
23
+ "Authorization": `Bearer ${token}`
24
+ }
25
+ });
26
+ const text = await readResponse(response);
27
+ const root = JSON.parse(text);
28
+ const status = readProperty(root, "status") ?? -1;
29
+ if (status !== 0) {
30
+ throw new Error(readProperty(root, "message") ?? "档案类目接口请求失败。");
31
+ }
32
+ return readProperty(root, "data") ?? {
33
+ defaultCategory: "",
34
+ categories: []
35
+ };
36
+ }
37
+ async uploadArticleImage(config, filePath, category, compression) {
38
+ validateConfig(config);
39
+ const token = await getToken(config);
40
+ const query = new URLSearchParams();
41
+ if (category?.trim()) {
42
+ query.set("category", category.trim());
43
+ }
44
+ if (typeof compression === "boolean") {
45
+ query.set("compression", String(compression));
46
+ }
47
+ const fileBytes = await readFile(filePath);
48
+ const form = new FormData();
49
+ form.set("file", new Blob([fileBytes], { type: "application/octet-stream" }), path.basename(filePath));
50
+ const apiPath = query.size === 0
51
+ ? "/api/UpLoad/ArticleImage"
52
+ : `/api/UpLoad/ArticleImage?${query.toString()}`;
53
+ const response = await fetch(buildUrl(config.baseUrl, apiPath), {
54
+ method: "POST",
55
+ headers: {
56
+ "Authorization": `Bearer ${token}`
57
+ },
58
+ body: form
59
+ });
60
+ return readResponse(response);
61
+ }
62
+ }
63
+ function validateConfig(config) {
64
+ if (!config.baseUrl.trim()) {
65
+ throw new Error("请先配置 YESCMS 网站地址。");
66
+ }
67
+ try {
68
+ new URL(config.baseUrl);
69
+ }
70
+ catch {
71
+ throw new Error("YESCMS 网站地址格式不正确。");
72
+ }
73
+ }
74
+ async function readResponse(response) {
75
+ const text = await response.text();
76
+ if (!response.ok) {
77
+ throw new Error(`YESCMS 请求失败(${response.status}):${text}`);
78
+ }
79
+ return text;
80
+ }
81
+ function buildUrl(baseUrl, apiPath) {
82
+ return new URL(apiPath.replace(/^\/+/, ""), baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).toString();
83
+ }
84
+ function readProperty(source, name) {
85
+ const value = source[name] ?? source[toPascalCase(name)];
86
+ return value;
87
+ }
88
+ function toPascalCase(value) {
89
+ return value.length === 0 ? value : `${value[0].toUpperCase()}${value.slice(1)}`;
90
+ }
91
+ //# sourceMappingURL=yescmsApiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yescmsApiClient.js","sourceRoot":"","sources":["../../src/shared/yescmsApiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,OAAO,eAAe;IAC1B,KAAK,CAAC,cAAc,CAAC,MAAoB,EAAE,OAAgC;QACzE,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,4BAA4B,CAAC,EAAE;YACnF,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,KAAK,EAAE;gBAClC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QAEH,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,MAAoB;QAC7C,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,gCAAgC,CAAC,EAAE;YACvF,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,KAAK,EAAE;aACnC;SACF,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;QACzD,MAAM,MAAM,GAAG,YAAY,CAAS,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,YAAY,CAAS,IAAI,EAAE,SAAS,CAAC,IAAI,aAAa,CAAC,CAAC;QAC1E,CAAC;QAED,OAAO,YAAY,CAAwB,IAAI,EAAE,MAAM,CAAC,IAAI;YAC1D,eAAe,EAAE,EAAE;YACnB,UAAU,EAAE,EAAE;SACf,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,MAAoB,EAAE,QAAgB,EAAE,QAAiB,EAAE,WAAqB;QACvG,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;QACpC,IAAI,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;YACrB,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,OAAO,WAAW,KAAK,SAAS,EAAE,CAAC;YACrC,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEvG,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC;YAC9B,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,4BAA4B,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;YAC9D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,KAAK,EAAE;aACnC;YACD,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QAEH,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;CACF;AAED,SAAS,cAAc,CAAC,MAAoB;IAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,QAAkB;IAC5C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe,EAAE,OAAe;IAChD,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC1G,CAAC;AAED,SAAS,YAAY,CAAI,MAA+B,EAAE,IAAY;IACpE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,OAAO,KAAsB,CAAC;AAChC,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACnF,CAAC"}
@@ -0,0 +1,7 @@
1
+ @echo off
2
+ cd /d "%~dp0"
3
+ if exist "%~dp0index.js" (
4
+ fnm exec --using 24.16.0 node "%~dp0index.js"
5
+ ) else (
6
+ fnm exec --using 24.16.0 node "%~dp0dist\index.js"
7
+ )
@@ -0,0 +1,79 @@
1
+ import path from "node:path";
2
+ import { z } from "zod";
3
+ import { loadConfig } from "../shared/configStore.js";
4
+ import { YescmsApiClient } from "../shared/yescmsApiClient.js";
5
+ const apiClient = new YescmsApiClient();
6
+ const uploadImageSchema = z.object({
7
+ filePath: z.string().min(1).describe("Absolute or workspace-relative local image path."),
8
+ category: z.string().optional().describe("Optional YESCMS archive category."),
9
+ compression: z.boolean().optional().describe("Whether the YESCMS upload endpoint should compress the image.")
10
+ });
11
+ const publishArticleSchema = z.object({
12
+ category: z.string().min(1),
13
+ title: z.string().min(1),
14
+ markdown: z.string().min(1),
15
+ summary: z.string().optional(),
16
+ seoKeywords: z.array(z.string()).optional(),
17
+ tagList: z.array(z.string()).optional(),
18
+ coverImageUrl: z.string().optional(),
19
+ isPublished: z.boolean().optional(),
20
+ isTop: z.boolean().optional(),
21
+ groupID: z.string().optional(),
22
+ shortTitle: z.string().optional(),
23
+ linkTitle: z.string().optional(),
24
+ originUrl: z.string().optional(),
25
+ imageUrls: z.array(z.string()).optional()
26
+ }).passthrough();
27
+ export function registerYescmsTools(server) {
28
+ server.registerTool("yescms_list_categories", {
29
+ description: "List YESCMS CMS article archive categories from /api/Article/ArchiveCategories.",
30
+ inputSchema: z.object({})
31
+ }, async () => textResult(await readCategoriesJson()));
32
+ server.registerTool("yescms_upload_article_image", {
33
+ description: "Upload a local image file to YESCMS /api/UpLoad/ArticleImage and return the image URL.",
34
+ inputSchema: uploadImageSchema
35
+ }, async ({ filePath, category, compression }) => {
36
+ const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
37
+ return textResult(prettyJsonOrText(await apiClient.uploadArticleImage(await loadEffectiveConfig(), absolutePath, category, compression)));
38
+ });
39
+ server.registerTool("yescms_publish_article", {
40
+ description: "Publish an AI generated Markdown article through YESCMS /api/Article/PublishFromAI.",
41
+ inputSchema: publishArticleSchema
42
+ }, async (request) => textResult(prettyJsonOrText(await apiClient.publishArticle(await loadEffectiveConfig(), request))));
43
+ }
44
+ async function readCategoriesJson() {
45
+ const categoryConfig = await apiClient.getArchiveCategories(await loadEffectiveConfig());
46
+ return JSON.stringify({
47
+ defaultCategory: categoryConfig.defaultCategory,
48
+ categories: categoryConfig.categories
49
+ }, null, 2);
50
+ }
51
+ async function loadEffectiveConfig() {
52
+ const config = await loadConfig();
53
+ if (process.env.YESCMS_BASE_URL?.trim()) {
54
+ config.baseUrl = process.env.YESCMS_BASE_URL.trim();
55
+ }
56
+ if (process.env.YESCMS_CREDENTIAL_TARGET?.trim()) {
57
+ config.credentialTarget = process.env.YESCMS_CREDENTIAL_TARGET.trim();
58
+ }
59
+ return config;
60
+ }
61
+ function textResult(text) {
62
+ return {
63
+ content: [
64
+ {
65
+ type: "text",
66
+ text
67
+ }
68
+ ]
69
+ };
70
+ }
71
+ function prettyJsonOrText(text) {
72
+ try {
73
+ return JSON.stringify(JSON.parse(text), null, 2);
74
+ }
75
+ catch {
76
+ return text;
77
+ }
78
+ }
79
+ //# sourceMappingURL=yescmsTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yescmsTools.js","sourceRoot":"","sources":["../../src/tools/yescmsTools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "yescms-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "YESCMS MCP Server for listing categories, uploading article images, and publishing Markdown articles.",
5
+ "private": false,
6
+ "type": "module",
7
+ "bin": {
8
+ "yescms-mcp": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=24.16.0"
16
+ },
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json && node ./scripts/copy-start-script.mjs",
19
+ "prepack": "npm run build",
20
+ "pack:local": "npm pack",
21
+ "start": "node ./dist/index.js",
22
+ "smoke": "node ./smoke-test.mjs"
23
+ },
24
+ "dependencies": {
25
+ "@modelcontextprotocol/sdk": "^1.29.0",
26
+ "zod": "^3.25.67"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^24.0.0",
30
+ "typescript": "^5.8.3"
31
+ }
32
+ }