@uni-helper/mcp 0.0.2-beta.1 → 0.0.4
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 +21 -12
- package/dist/index.mjs +15 -365
- package/package.json +15 -12
- package/scripts/{download-model.cjs → download-model.mjs} +9 -5
- package/scripts/link-global.mjs +38 -0
- package/dist/index.d.mts +0 -79
package/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# UniAPP MCP
|
|
2
|
+
|
|
3
|
+
> 访问[uni-helper/skills](https://github.com/uni-helper/skills)获取`skills`。
|
|
4
|
+
|
|
5
|
+
使用 `MCP + RAG` 方案来查询 uniapp 文档。
|
|
2
6
|
|
|
3
7
|
## 安装
|
|
4
8
|
|
|
@@ -6,16 +10,21 @@
|
|
|
6
10
|
pnpm add @uni-helper/mcp -D
|
|
7
11
|
```
|
|
8
12
|
|
|
9
|
-
## 配置
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
## 配置 MCP 服务器
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"mcpServers": {
|
|
17
|
+
"uni-doc": {
|
|
18
|
+
"command": "uni-mcp"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
## 注意如果使用pnpm,请在`pnpm-workspace.yaml`中添加如下配置:
|
|
25
|
+
确保能正确构建`@uni-helper/mcp`插件
|
|
26
|
+
```yaml
|
|
27
|
+
onlyBuiltDependencies:
|
|
28
|
+
- hnswlib-node
|
|
29
|
+
- '@uni-helper/mcp'
|
|
21
30
|
```
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
4
|
-
import { Hono } from "hono";
|
|
5
|
-
import { cors } from "hono/cors";
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
4
|
import { z } from "zod";
|
|
8
5
|
import { dirname, join } from "node:path";
|
|
@@ -10,190 +7,17 @@ import { fileURLToPath } from "node:url";
|
|
|
10
7
|
import { env } from "@huggingface/transformers";
|
|
11
8
|
import { HuggingFaceTransformersEmbeddings } from "@langchain/community/embeddings/huggingface_transformers";
|
|
12
9
|
import { HNSWLib } from "@langchain/community/vectorstores/hnswlib";
|
|
13
|
-
import fs from "fs-extra";
|
|
14
|
-
import { existsSync } from "node:fs";
|
|
15
|
-
import { homedir } from "node:os";
|
|
16
|
-
import consola from "consola";
|
|
17
|
-
import { Buffer as Buffer$1 } from "node:buffer";
|
|
18
|
-
import open from "open";
|
|
19
10
|
|
|
20
|
-
//#region
|
|
21
|
-
var
|
|
22
|
-
var __defProp = Object.defineProperty;
|
|
23
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
24
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
25
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
26
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
27
|
-
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
28
|
-
var __copyProps = (to, from, except, desc) => {
|
|
29
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
30
|
-
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
31
|
-
key = keys[i];
|
|
32
|
-
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
33
|
-
__defProp(to, key, {
|
|
34
|
-
get: ((k) => from[k]).bind(null, key),
|
|
35
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return to;
|
|
41
|
-
};
|
|
42
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
43
|
-
value: mod,
|
|
44
|
-
enumerable: true
|
|
45
|
-
}) : target, mod));
|
|
46
|
-
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region node_modules/.pnpm/ansis@4.2.0/node_modules/ansis/index.cjs
|
|
49
|
-
var require_ansis = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
50
|
-
let e, t, r, { defineProperty: l, setPrototypeOf: n, create: o, keys: s } = Object, i = "", { round: c, max: a } = Math, p = (e) => {
|
|
51
|
-
let t = /([a-f\d]{3,6})/i.exec(e)?.[1], r = t?.length, l = parseInt(6 ^ r ? 3 ^ r ? "0" : t[0] + t[0] + t[1] + t[1] + t[2] + t[2] : t, 16);
|
|
52
|
-
return [
|
|
53
|
-
l >> 16 & 255,
|
|
54
|
-
l >> 8 & 255,
|
|
55
|
-
255 & l
|
|
56
|
-
];
|
|
57
|
-
}, u = (e, t, r) => e ^ t || t ^ r ? 16 + 36 * c(e / 51) + 6 * c(t / 51) + c(r / 51) : 8 > e ? 16 : e > 248 ? 231 : c(24 * (e - 8) / 247) + 232, d = (e) => {
|
|
58
|
-
let t, r, l, n, o;
|
|
59
|
-
return 8 > e ? 30 + e : 16 > e ? e - 8 + 90 : (232 > e ? (o = (e -= 16) % 36, t = (e / 36 | 0) / 5, r = (o / 6 | 0) / 5, l = o % 6 / 5) : t = r = l = (10 * (e - 232) + 8) / 255, n = 2 * a(t, r, l), n ? 30 + (c(l) << 2 | c(r) << 1 | c(t)) + (2 ^ n ? 0 : 60) : 30);
|
|
60
|
-
}, f = (() => {
|
|
61
|
-
let r = (e) => o.some(((t) => e.test(t))), l = globalThis, n = l.process ?? {}, o = n.argv ?? [], i = n.env ?? {}, c = -1;
|
|
62
|
-
try {
|
|
63
|
-
e = "," + s(i).join(",");
|
|
64
|
-
} catch (e) {
|
|
65
|
-
i = {}, c = 0;
|
|
66
|
-
}
|
|
67
|
-
let a$1 = "FORCE_COLOR", p = {
|
|
68
|
-
false: 0,
|
|
69
|
-
0: 0,
|
|
70
|
-
1: 1,
|
|
71
|
-
2: 2,
|
|
72
|
-
3: 3
|
|
73
|
-
}[i[a$1]] ?? -1, u = a$1 in i && p || r(/^--color=?(true|always)?$/);
|
|
74
|
-
return u && (c = p), ~c || (c = ((r$1, l$1, n$1) => (t = r$1.TERM, {
|
|
75
|
-
"24bit": 3,
|
|
76
|
-
truecolor: 3,
|
|
77
|
-
ansi256: 2,
|
|
78
|
-
ansi: 1
|
|
79
|
-
}[r$1.COLORTERM] || (r$1.CI ? /,GITHUB/.test(e) ? 3 : 1 : l$1 && "dumb" !== t ? n$1 ? 3 : /-256/.test(t) ? 2 : 1 : 0)))(i, !!i.PM2_HOME || i.NEXT_RUNTIME?.includes("edge") || !!n.stdout?.isTTY, "win32" === n.platform)), !p || i.NO_COLOR || r(/^--(no-color|color=(false|never))$/) ? 0 : l.window?.chrome || u && !c ? 3 : c;
|
|
80
|
-
})(), g = {
|
|
81
|
-
open: i,
|
|
82
|
-
close: i
|
|
83
|
-
}, h = 39, b = 49, O = {}, m = ({ p: e }, { open: t, close: l }) => {
|
|
84
|
-
let o = (e$1, ...r) => {
|
|
85
|
-
if (!e$1) {
|
|
86
|
-
if (t && t === l) return t;
|
|
87
|
-
if ((e$1 ?? i) === i) return i;
|
|
88
|
-
}
|
|
89
|
-
let n, s$1 = e$1.raw ? String.raw({ raw: e$1 }, ...r) : i + e$1, c$1 = o.p, a$1 = c$1.o, p = c$1.c;
|
|
90
|
-
if (s$1.includes("\x1B")) for (; c$1; c$1 = c$1.p) {
|
|
91
|
-
let { open: e$2, close: t$1 } = c$1, r$1 = t$1.length, l$1 = i, o$1 = 0;
|
|
92
|
-
if (r$1) for (; ~(n = s$1.indexOf(t$1, o$1)); o$1 = n + r$1) l$1 += s$1.slice(o$1, n) + e$2;
|
|
93
|
-
s$1 = l$1 + s$1.slice(o$1);
|
|
94
|
-
}
|
|
95
|
-
return a$1 + (s$1.includes("\n") ? s$1.replace(/(\r?\n)/g, p + "$1" + a$1) : s$1) + p;
|
|
96
|
-
}, s = t, c = l;
|
|
97
|
-
return e && (s = e.o + t, c = l + e.c), n(o, r), o.p = {
|
|
98
|
-
open: t,
|
|
99
|
-
close: l,
|
|
100
|
-
o: s,
|
|
101
|
-
c,
|
|
102
|
-
p: e
|
|
103
|
-
}, o.open = s, o.close = c, o;
|
|
104
|
-
};
|
|
105
|
-
const w = new function e(t = f) {
|
|
106
|
-
let s = {
|
|
107
|
-
Ansis: e,
|
|
108
|
-
level: t,
|
|
109
|
-
isSupported: () => a$1,
|
|
110
|
-
strip: (e$1) => e$1.replace(/[][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, i),
|
|
111
|
-
extend(e$1) {
|
|
112
|
-
for (let t$1 in e$1) {
|
|
113
|
-
let r = e$1[t$1], l = (typeof r)[0];
|
|
114
|
-
"s" === l ? (c(t$1, T(...p(r))), c(_(t$1), v(...p(r)))) : c(t$1, r, "f" === l);
|
|
115
|
-
}
|
|
116
|
-
return r = o({}, O), n(s, r), s;
|
|
117
|
-
}
|
|
118
|
-
}, c = (e$1, t$1, r) => {
|
|
119
|
-
O[e$1] = { get() {
|
|
120
|
-
let n = r ? (...e$2) => m(this, t$1(...e$2)) : m(this, t$1);
|
|
121
|
-
return l(this, e$1, { value: n }), n;
|
|
122
|
-
} };
|
|
123
|
-
}, a$1 = t > 0, w = (e$1, t$1) => a$1 ? {
|
|
124
|
-
open: `[${e$1}m`,
|
|
125
|
-
close: `[${t$1}m`
|
|
126
|
-
} : g, y = (e$1) => (t$1) => e$1(...p(t$1)), R = (e$1, t$1) => (r, l, n) => w(`${e$1}8;2;${r};${l};${n}`, t$1), $ = (e$1, t$1) => (r, l, n) => w(((e$2, t$2, r$1) => d(u(e$2, t$2, r$1)))(r, l, n) + e$1, t$1), x = (e$1) => (t$1, r, l) => e$1(u(t$1, r, l)), T = R(3, h), v = R(4, b), C = (e$1) => w("38;5;" + e$1, h), E = (e$1) => w("48;5;" + e$1, b);
|
|
127
|
-
2 === t ? (T = x(C), v = x(E)) : 1 === t && (T = $(0, h), v = $(10, b), C = (e$1) => w(d(e$1), h), E = (e$1) => w(d(e$1) + 10, b));
|
|
128
|
-
let M, I = {
|
|
129
|
-
fg: C,
|
|
130
|
-
bg: E,
|
|
131
|
-
rgb: T,
|
|
132
|
-
bgRgb: v,
|
|
133
|
-
hex: y(T),
|
|
134
|
-
bgHex: y(v),
|
|
135
|
-
visible: g,
|
|
136
|
-
reset: w(0, 0),
|
|
137
|
-
bold: w(1, 22),
|
|
138
|
-
dim: w(2, 22),
|
|
139
|
-
italic: w(3, 23),
|
|
140
|
-
underline: w(4, 24),
|
|
141
|
-
inverse: w(7, 27),
|
|
142
|
-
hidden: w(8, 28),
|
|
143
|
-
strikethrough: w(9, 29)
|
|
144
|
-
}, _ = (e$1) => "bg" + e$1[0].toUpperCase() + e$1.slice(1), k = "Bright";
|
|
145
|
-
return "black,red,green,yellow,blue,magenta,cyan,white,gray".split(",").map(((e$1, t$1) => {
|
|
146
|
-
M = _(e$1), 8 > t$1 ? (I[e$1 + k] = w(90 + t$1, h), I[M + k] = w(100 + t$1, b)) : t$1 = 60, I[e$1] = w(30 + t$1, h), I[M] = w(40 + t$1, b);
|
|
147
|
-
})), s.extend(I);
|
|
148
|
-
}();
|
|
149
|
-
module.exports = w, w.default = w;
|
|
150
|
-
}));
|
|
151
|
-
|
|
152
|
-
//#endregion
|
|
153
|
-
//#region node_modules/.pnpm/ansis@4.2.0/node_modules/ansis/index.mjs
|
|
154
|
-
var import_ansis = /* @__PURE__ */ __toESM(require_ansis(), 1);
|
|
155
|
-
var ansis_default = import_ansis.default;
|
|
156
|
-
const { Ansis, fg, bg, rgb, bgRgb, hex, bgHex, reset, inverse, hidden, visible, bold, dim, italic, underline, strikethrough, black, red, green, yellow, blue, magenta, cyan, white, gray, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, whiteBright, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bgGray, bgRedBright, bgGreenBright, bgYellowBright, bgBlueBright, bgMagentaBright, bgCyanBright, bgWhiteBright } = import_ansis.default;
|
|
157
|
-
|
|
158
|
-
//#endregion
|
|
159
|
-
//#region src/mcpServer/connect.ts
|
|
160
|
-
function connectServer(server, options) {
|
|
161
|
-
const { port = 2515, printUrl = true } = options;
|
|
162
|
-
const transport = new WebStandardStreamableHTTPServerTransport();
|
|
163
|
-
const app = new Hono();
|
|
164
|
-
app.use("*", cors({
|
|
165
|
-
origin: "*",
|
|
166
|
-
allowMethods: [
|
|
167
|
-
"GET",
|
|
168
|
-
"POST",
|
|
169
|
-
"DELETE",
|
|
170
|
-
"OPTIONS"
|
|
171
|
-
],
|
|
172
|
-
allowHeaders: [
|
|
173
|
-
"Content-Type",
|
|
174
|
-
"mcp-session-id",
|
|
175
|
-
"Last-Event-ID",
|
|
176
|
-
"mcp-protocol-version"
|
|
177
|
-
],
|
|
178
|
-
exposeHeaders: ["mcp-session-id", "mcp-protocol-version"]
|
|
179
|
-
}));
|
|
180
|
-
app.all("/mcp", (c) => transport.handleRequest(c.req.raw));
|
|
181
|
-
server.connect(transport).then(() => {
|
|
182
|
-
if (printUrl) console.log(`${ansis_default.cyan` ➜ MCP: `}${ansis_default.gray(`server is running at ${ansis_default.green(`http://localhost:${port}/mcp`)}`)}`);
|
|
183
|
-
serve({
|
|
184
|
-
fetch: app.fetch,
|
|
185
|
-
port
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
return `http://localhost:${port}/mcp`;
|
|
189
|
-
}
|
|
11
|
+
//#region package.json
|
|
12
|
+
var version = "0.0.4";
|
|
190
13
|
|
|
191
14
|
//#endregion
|
|
192
15
|
//#region src/docs/index.ts
|
|
193
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
194
17
|
async function loadVectorStore(vectorName, _embeddings) {
|
|
195
18
|
const vectorDirMap = { uniapp: join(__dirname, "../", "vectorStore", "uniapp") };
|
|
196
|
-
env.
|
|
19
|
+
env.version = "master";
|
|
20
|
+
env.remoteHost = "https://www.modelscope.cn/models";
|
|
197
21
|
const embeddings = _embeddings ?? new HuggingFaceTransformersEmbeddings({
|
|
198
22
|
model: "onnx-community/Qwen3-Embedding-0.6B-ONNX",
|
|
199
23
|
pretrainedOptions: {
|
|
@@ -205,207 +29,33 @@ async function loadVectorStore(vectorName, _embeddings) {
|
|
|
205
29
|
}
|
|
206
30
|
|
|
207
31
|
//#endregion
|
|
208
|
-
//#region
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
//#endregion
|
|
212
|
-
//#region src/mcpServer/projectAnalyzer.ts
|
|
213
|
-
async function readFileIfExists(path) {
|
|
214
|
-
const content = await fs.readFile(path, "utf-8").catch(() => void 0);
|
|
215
|
-
return {
|
|
216
|
-
exists: !!content,
|
|
217
|
-
path,
|
|
218
|
-
content
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
async function analyzeProject(rootPath) {
|
|
222
|
-
const [pagesJson, manifestJson] = await Promise.all([readFileIfExists(join(rootPath, "src/pages.json")), readFileIfExists(join(rootPath, "src/manifest.json"))]);
|
|
223
|
-
return {
|
|
224
|
-
pagesJson,
|
|
225
|
-
manifestJson
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
//#endregion
|
|
230
|
-
//#region src/mcpServer/server.ts
|
|
231
|
-
async function createMcpServer(config, options) {
|
|
32
|
+
//#region src/server/index.ts
|
|
33
|
+
async function createMcpServer() {
|
|
232
34
|
const server = new McpServer({
|
|
233
35
|
name: "uni",
|
|
234
36
|
version
|
|
235
37
|
});
|
|
236
|
-
server.registerTool("get-vite-config", {
|
|
237
|
-
title: "获取 Vite 配置",
|
|
238
|
-
description: "获取 Vite 配置摘要,包括根目录、解析配置、插件和环境名称。"
|
|
239
|
-
}, () => ({ content: [{
|
|
240
|
-
type: "text",
|
|
241
|
-
text: JSON.stringify({
|
|
242
|
-
root: config.root,
|
|
243
|
-
resolve: config.resolve,
|
|
244
|
-
plugins: config.plugins.map((p) => p.name).filter(Boolean),
|
|
245
|
-
environmentNames: Object.keys(config.environments)
|
|
246
|
-
})
|
|
247
|
-
}] }));
|
|
248
38
|
server.registerTool("search-docs-by-Uniapp-official", {
|
|
249
39
|
title: "搜索 Uniapp 官方文档",
|
|
250
40
|
description: "在 Uniapp 文档知识库中进行搜索,可查找相关信息、代码示例、API参考文档和操作指南。当您需要解答关于Uniapp文档的问题、查找特定文档内容、了解功能运作原理或定位实现细节时,可使用此工具。搜索结果将返回带有标题的上下文相关内容,并附有直达文档页面的链接。",
|
|
251
41
|
inputSchema: { query: z.string().describe("用于搜索内容的查询语句") }
|
|
252
42
|
}, async ({ query }) => {
|
|
253
|
-
return { content: (await (await loadVectorStore("uniapp"
|
|
43
|
+
return { content: (await (await loadVectorStore("uniapp")).similaritySearch(query, 3)).map((doc) => ({
|
|
254
44
|
type: "text",
|
|
255
45
|
text: JSON.stringify(doc)
|
|
256
46
|
})) };
|
|
257
47
|
});
|
|
258
|
-
server.registerTool("get-project-overview", {
|
|
259
|
-
title: "获取项目概览",
|
|
260
|
-
description: "返回 Uniapp 项目的 pages.json 和 manifest.json 配置文件。"
|
|
261
|
-
}, async () => {
|
|
262
|
-
const overview = await analyzeProject(config.root);
|
|
263
|
-
return { content: [{
|
|
264
|
-
type: "text",
|
|
265
|
-
text: JSON.stringify(overview, null, 2)
|
|
266
|
-
}] };
|
|
267
|
-
});
|
|
268
48
|
return server;
|
|
269
49
|
}
|
|
270
50
|
|
|
271
|
-
//#endregion
|
|
272
|
-
//#region src/updateConfigs/claude.ts
|
|
273
|
-
async function updateClaudeConfig(root, sseUrl, _options) {
|
|
274
|
-
const mcp = existsSync(join(root, ".mcp.json")) ? JSON.parse(await fs.readFile(join(root, ".mcp.json"), "utf-8") || "{}") : {};
|
|
275
|
-
mcp.mcpServers ||= {};
|
|
276
|
-
mcp.mcpServers.uni = {
|
|
277
|
-
type: "http",
|
|
278
|
-
url: sseUrl
|
|
279
|
-
};
|
|
280
|
-
await fs.writeFile(join(root, ".mcp.json"), `${JSON.stringify(mcp, null, 2)}\n`);
|
|
281
|
-
consola.log(`${CONSOLE_LOG_PREFIX}${ansis_default.gray(`Updated config file ${join(root, ".mcp.json")}`)}`);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
//#endregion
|
|
285
|
-
//#region src/updateConfigs/cursor.ts
|
|
286
|
-
async function updateCursorConfig(root, sseUrl, _options) {
|
|
287
|
-
await fs.mkdir(join(root, ".cursor"), { recursive: true });
|
|
288
|
-
const mcp = existsSync(join(root, ".cursor/mcp.json")) ? JSON.parse(await fs.readFile(join(root, ".cursor/mcp.json"), "utf-8") || "{}") : {};
|
|
289
|
-
mcp.mcpServers ||= {};
|
|
290
|
-
mcp.mcpServers.uni = { url: sseUrl };
|
|
291
|
-
await fs.writeFile(join(root, ".cursor/mcp.json"), `${JSON.stringify(mcp, null, 2)}\n`);
|
|
292
|
-
consola.log(`${CONSOLE_LOG_PREFIX}${ansis_default.gray(`Updated config file ${join(root, ".cursor/mcp.json")}`)}`);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
//#endregion
|
|
296
|
-
//#region src/updateConfigs/print.ts
|
|
297
|
-
function mcpServersConfig(sseUrl) {
|
|
298
|
-
const code = ansis_default.rgb(206, 145, 120);
|
|
299
|
-
const purple = ansis_default.rgb(218, 112, 214);
|
|
300
|
-
return `
|
|
301
|
-
${ansis_default.yellow`{`}
|
|
302
|
-
${code`"mcpServers"`}${ansis_default.white`:`} ${purple`{`}
|
|
303
|
-
${code`"uni"`}${ansis_default.white`:`} ${ansis_default.blue`{`}
|
|
304
|
-
${code`"url"`}${ansis_default.white`:`} ${code`"${sseUrl}"`}
|
|
305
|
-
${ansis_default.blue`}`}
|
|
306
|
-
${purple`}`}
|
|
307
|
-
${ansis_default.yellow`}`}
|
|
308
|
-
`;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
//#endregion
|
|
312
|
-
//#region src/updateConfigs/trae.ts
|
|
313
|
-
async function updateTraeConfig(sseUrl, _options) {
|
|
314
|
-
await open(`trae://trae.ai-ide/mcp-import?type=http&name=uni&config=${Buffer$1.from(JSON.stringify({ url: sseUrl })).toString("base64")}`);
|
|
315
|
-
consola.log(`${CONSOLE_LOG_PREFIX}${ansis_default.gray(`自动配置了trae链接,请在trae中确认`)}`);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
//#endregion
|
|
319
|
-
//#region src/updateConfigs/trae-cn.ts
|
|
320
|
-
async function updateTraeCNConfig(sseUrl, _options) {
|
|
321
|
-
await open(`trae-cn://trae.ai-ide/mcp-import?type=http&name=uni&config=${Buffer$1.from(JSON.stringify({ url: sseUrl })).toString("base64")}`);
|
|
322
|
-
consola.log(`${CONSOLE_LOG_PREFIX}${ansis_default.gray(`自动配置了trae-cn链接,请在trae-cn中确认`)}`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
//#endregion
|
|
326
|
-
//#region src/updateConfigs/vscode.ts
|
|
327
|
-
async function updateVSCodeConfig(root, sseUrl, _options) {
|
|
328
|
-
await fs.mkdir(join(root, ".vscode"), { recursive: true });
|
|
329
|
-
const mcp = existsSync(join(root, ".vscode/mcp.json")) ? JSON.parse(await fs.readFile(join(root, ".vscode/mcp.json"), "utf-8") || "{}") : {};
|
|
330
|
-
mcp.servers ||= {};
|
|
331
|
-
mcp.servers.uni = {
|
|
332
|
-
type: "http",
|
|
333
|
-
url: sseUrl
|
|
334
|
-
};
|
|
335
|
-
await fs.writeFile(join(root, ".vscode/mcp.json"), `${JSON.stringify(mcp, null, 2)}\n`);
|
|
336
|
-
consola.log(`${CONSOLE_LOG_PREFIX}${ansis_default.gray(`Updated config file ${join(root, ".vscode/mcp.json")}`)}`);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
//#endregion
|
|
340
|
-
//#region src/updateConfigs/windsurf.ts
|
|
341
|
-
async function updateWindsurfConfig(sseUrl, _options) {
|
|
342
|
-
const windsurfDir = join(homedir(), ".codeium", "windsurf");
|
|
343
|
-
const windsurfConfigPath = join(windsurfDir, "mcp_config.json");
|
|
344
|
-
try {
|
|
345
|
-
await fs.mkdir(windsurfDir, { recursive: true });
|
|
346
|
-
const config = existsSync(windsurfConfigPath) ? JSON.parse(await fs.readFile(windsurfConfigPath, "utf-8").catch(() => "{}") || "{}") : {};
|
|
347
|
-
config.mcpServers ||= {};
|
|
348
|
-
config.mcpServers.uni = { serverUrl: sseUrl };
|
|
349
|
-
await fs.writeFile(windsurfConfigPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
350
|
-
consola.log(`${CONSOLE_LOG_PREFIX}${ansis_default.gray(`Updated config file ${windsurfConfigPath}`)}`);
|
|
351
|
-
} catch (e) {
|
|
352
|
-
consola.error(`${CONSOLE_LOG_PREFIX}${ansis_default.red(`Failed to update ${windsurfConfigPath}`)}${e}`);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
//#endregion
|
|
357
|
-
//#region src/updateConfigs/index.ts
|
|
358
|
-
const CONSOLE_LOG_PREFIX = ansis_default.cyan.bold`[MCP] `;
|
|
359
|
-
async function updateConfigs(root, sseUrl, options) {
|
|
360
|
-
const { updateConfig = false } = options;
|
|
361
|
-
if (updateConfig === false) {
|
|
362
|
-
consola.log(`${CONSOLE_LOG_PREFIX}请手动配置mcpServers`);
|
|
363
|
-
consola.box(mcpServersConfig(sseUrl));
|
|
364
|
-
}
|
|
365
|
-
const configPromises = (updateConfig === "auto" ? [
|
|
366
|
-
existsSync(join(root, ".cursor")) ? "cursor" : null,
|
|
367
|
-
existsSync(join(root, ".vscode")) ? "vscode" : null,
|
|
368
|
-
existsSync(join(homedir(), ".codeium", "windsurf")) ? "windsurf" : null,
|
|
369
|
-
existsSync(join(root, ".mcp.json")) ? "claude-code" : null,
|
|
370
|
-
existsSync(join(homedir(), ".trae-cn")) ? "trae-cn" : null,
|
|
371
|
-
existsSync(join(homedir(), ".trae")) ? "trae" : null
|
|
372
|
-
].filter((x) => x !== null) : Array.isArray(updateConfig) ? updateConfig : []).map(async (config) => {
|
|
373
|
-
switch (config) {
|
|
374
|
-
case "cursor":
|
|
375
|
-
await updateCursorConfig(root, sseUrl, options);
|
|
376
|
-
break;
|
|
377
|
-
case "vscode":
|
|
378
|
-
await updateVSCodeConfig(root, sseUrl, options);
|
|
379
|
-
break;
|
|
380
|
-
case "windsurf":
|
|
381
|
-
await updateWindsurfConfig(sseUrl, options);
|
|
382
|
-
break;
|
|
383
|
-
case "claude-code":
|
|
384
|
-
await updateClaudeConfig(root, sseUrl, options);
|
|
385
|
-
break;
|
|
386
|
-
case "trae-cn":
|
|
387
|
-
await updateTraeCNConfig(sseUrl, options);
|
|
388
|
-
break;
|
|
389
|
-
case "trae":
|
|
390
|
-
await updateTraeConfig(sseUrl, options);
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
await Promise.all(configPromises);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
51
|
//#endregion
|
|
398
52
|
//#region src/index.ts
|
|
399
|
-
function
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
async configResolved(config) {
|
|
404
|
-
const url = connectServer(await createMcpServer(config, options), options);
|
|
405
|
-
await updateConfigs(searchForWorkspaceRoot(config.root), url, options);
|
|
406
|
-
}
|
|
407
|
-
};
|
|
53
|
+
async function main() {
|
|
54
|
+
const server = await createMcpServer();
|
|
55
|
+
const transport = new StdioServerTransport();
|
|
56
|
+
await server.connect(transport);
|
|
408
57
|
}
|
|
58
|
+
main().catch(console.error);
|
|
409
59
|
|
|
410
60
|
//#endregion
|
|
411
|
-
export {
|
|
61
|
+
export { };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uni-helper/mcp",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
5
|
-
"description": "
|
|
4
|
+
"version": "0.0.4",
|
|
5
|
+
"description": "为uniapp提供ai开发体验",
|
|
6
6
|
"author": "FliPPeDround <flippedround@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://afdian.com/a/flippedround",
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
"uni-app",
|
|
18
18
|
"uni-helper",
|
|
19
19
|
"mcp",
|
|
20
|
+
"ai",
|
|
21
|
+
"agent",
|
|
20
22
|
"miniapp"
|
|
21
23
|
],
|
|
22
24
|
"sideEffects": false,
|
|
@@ -28,29 +30,29 @@
|
|
|
28
30
|
},
|
|
29
31
|
"main": "./dist/index.mjs",
|
|
30
32
|
"module": "./dist/index.mjs",
|
|
31
|
-
"
|
|
33
|
+
"bin": {
|
|
34
|
+
"uni-mcp": "./dist/index.mjs"
|
|
35
|
+
},
|
|
32
36
|
"files": [
|
|
33
37
|
"dist",
|
|
34
38
|
"scripts",
|
|
35
39
|
"vectorStore"
|
|
36
40
|
],
|
|
37
|
-
"peerDependencies": {
|
|
38
|
-
"uniapp": "*",
|
|
39
|
-
"vite": ">=3.1.0"
|
|
40
|
-
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@hono/node-server": "^1.19.9",
|
|
43
42
|
"@huggingface/transformers": "^3.8.1",
|
|
44
43
|
"@langchain/community": "^1.1.4",
|
|
45
44
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
45
|
+
"cac": "^6.7.14",
|
|
46
|
+
"commander": "^14.0.2",
|
|
46
47
|
"consola": "^3.2.3",
|
|
47
48
|
"fs-extra": "^11.3.3",
|
|
48
49
|
"hnswlib-node": "^3.0.0",
|
|
49
|
-
"hono": "^4.11.4",
|
|
50
50
|
"langchain": "^1.2.8",
|
|
51
51
|
"local-pkg": "^1.1.2",
|
|
52
|
+
"minimist": "^1.2.8",
|
|
52
53
|
"open": "^11.0.0",
|
|
53
54
|
"pathe": "^2.0.3",
|
|
55
|
+
"which": "^6.0.0",
|
|
54
56
|
"zod": "^4.3.5"
|
|
55
57
|
},
|
|
56
58
|
"devDependencies": {
|
|
@@ -62,6 +64,7 @@
|
|
|
62
64
|
"@modelcontextprotocol/inspector": "^0.18.0",
|
|
63
65
|
"@types/debug": "^4.1.12",
|
|
64
66
|
"@types/fs-extra": "^11.0.4",
|
|
67
|
+
"@types/minimist": "^1.2.5",
|
|
65
68
|
"@types/node": "^25.0.8",
|
|
66
69
|
"@types/turndown": "^5.0.6",
|
|
67
70
|
"ansis": "^4.2.0",
|
|
@@ -76,7 +79,6 @@
|
|
|
76
79
|
"tsx": "^4.21.0",
|
|
77
80
|
"turndown": "^7.2.2",
|
|
78
81
|
"typescript": "^5.9.3",
|
|
79
|
-
"vite": "^7.3.1",
|
|
80
82
|
"vitest": "^4.0.17",
|
|
81
83
|
"vitest-package-exports": "^1.1.2"
|
|
82
84
|
},
|
|
@@ -90,12 +92,13 @@
|
|
|
90
92
|
"build": "tsdown",
|
|
91
93
|
"dev": "tsdown --watch ./src",
|
|
92
94
|
"lint": "eslint",
|
|
93
|
-
"task": "
|
|
95
|
+
"task": "node ./tasks/uniappDocs/index.ts",
|
|
94
96
|
"play": "cd playground && pnpm dev",
|
|
95
97
|
"lint:fix": "eslint --fix",
|
|
96
98
|
"inspect": "mcp-inspector",
|
|
97
99
|
"release": "bumpp",
|
|
100
|
+
"pull:repo": "node scripts/cli.ts",
|
|
98
101
|
"test": "vitest",
|
|
99
|
-
"postinstall": "node scripts/download-model.
|
|
102
|
+
"postinstall": "node scripts/download-model.mjs && node scripts/link-global.mjs"
|
|
100
103
|
}
|
|
101
104
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import { env } from '@huggingface/transformers'
|
|
3
|
+
import { HuggingFaceTransformersEmbeddings } from '@langchain/community/embeddings/huggingface_transformers'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
if (process.env.CI) {
|
|
6
|
+
process.exit(0)
|
|
7
|
+
}
|
|
7
8
|
|
|
9
|
+
async function downloadModel() {
|
|
10
|
+
env.version = 'master'
|
|
11
|
+
env.remoteHost = 'https://www.modelscope.cn/models'
|
|
8
12
|
const embeddings = new HuggingFaceTransformersEmbeddings({
|
|
9
13
|
model: 'onnx-community/Qwen3-Embedding-0.6B-ONNX',
|
|
10
14
|
pretrainedOptions: {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import which from 'which'
|
|
6
|
+
|
|
7
|
+
if (process.env.CI) {
|
|
8
|
+
process.exit(0)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
12
|
+
const __dirname = dirname(__filename)
|
|
13
|
+
|
|
14
|
+
async function linkGlobal() {
|
|
15
|
+
const resolvedOrNull = await which('uni-mcp', { nothrow: true })
|
|
16
|
+
if (resolvedOrNull) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const rootDir = join(__dirname, '..')
|
|
21
|
+
|
|
22
|
+
console.log('🔧 正在将 uni-mcp 链接到全局...')
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
execSync('npm link -y', {
|
|
26
|
+
cwd: rootDir,
|
|
27
|
+
stdio: 'inherit',
|
|
28
|
+
shell: true,
|
|
29
|
+
})
|
|
30
|
+
console.log('✅ uni-mcp 已成功链接到全局')
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
console.error('❌ 全局链接失败:', err.message)
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
linkGlobal()
|
package/dist/index.d.mts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { Plugin } from "vite";
|
|
2
|
-
|
|
3
|
-
//#region node_modules/.pnpm/@langchain+core@1.1.15_openai@6.16.0_ws@8.19.0_zod@4.3.5_/node_modules/@langchain/core/dist/embeddings.d.cts
|
|
4
|
-
interface EmbeddingsInterface<TOutput = number[]> {
|
|
5
|
-
/**
|
|
6
|
-
* An abstract method that takes an array of documents as input and
|
|
7
|
-
* returns a promise that resolves to an array of vectors for each
|
|
8
|
-
* document.
|
|
9
|
-
* @param documents An array of documents to be embedded.
|
|
10
|
-
* @returns A promise that resolves to an array of vectors for each document.
|
|
11
|
-
*/
|
|
12
|
-
embedDocuments(documents: string[]): Promise<TOutput[]>;
|
|
13
|
-
/**
|
|
14
|
-
* An abstract method that takes a single document as input and returns a
|
|
15
|
-
* promise that resolves to a vector for the query document.
|
|
16
|
-
* @param document A single document to be embedded.
|
|
17
|
-
* @returns A promise that resolves to a vector for the query document.
|
|
18
|
-
*/
|
|
19
|
-
embedQuery(document: string): Promise<TOutput>;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* An abstract class that provides methods for embedding documents and
|
|
23
|
-
* queries using LangChain.
|
|
24
|
-
*/
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region src/types.d.ts
|
|
27
|
-
type SupportedUpdateConfigType = 'cursor' | 'vscode' | 'windsurf' | 'claude-code' | 'trae-cn' | 'trae';
|
|
28
|
-
type MaybeArray<T> = T | T[];
|
|
29
|
-
interface UniMcpOptions {
|
|
30
|
-
/**
|
|
31
|
-
* 监听的端口,默认为 Vite 开发服务器的端口
|
|
32
|
-
*/
|
|
33
|
-
port?: number;
|
|
34
|
-
/**
|
|
35
|
-
* 在控制台打印 MCP 服务器 URL
|
|
36
|
-
*
|
|
37
|
-
* @default true
|
|
38
|
-
*/
|
|
39
|
-
printUrl?: boolean;
|
|
40
|
-
/**
|
|
41
|
-
* 自定义的 Embeddings 模型
|
|
42
|
-
*
|
|
43
|
-
* 内置模型为 Qwen3-Embedding-0.6B-ONNX
|
|
44
|
-
*
|
|
45
|
-
* 如果本地运行效率低,可自定义模型
|
|
46
|
-
* - 确保模型支持 1024 维
|
|
47
|
-
* - 支持 langchain 的 Embeddings 格式
|
|
48
|
-
* @default
|
|
49
|
-
* ```ts
|
|
50
|
-
* new HuggingFaceTransformersEmbeddings({
|
|
51
|
-
* model: 'onnx-community/Qwen3-Embedding-0.6B-ONNX',
|
|
52
|
-
* pretrainedOptions: {
|
|
53
|
-
* dtype: 'int8',
|
|
54
|
-
* device: 'cpu',
|
|
55
|
-
* },
|
|
56
|
-
* })
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
embeddings?: EmbeddingsInterface;
|
|
60
|
-
/**
|
|
61
|
-
* 要更新的配置类型
|
|
62
|
-
*
|
|
63
|
-
* - `auto` - 如果配置文件存在则自动更新
|
|
64
|
-
* - `cursor` - 更新 Cursor 配置文件 `.cursor/mcp.json`
|
|
65
|
-
* - `vscode` - 更新 VSCode 配置文件 `.vscode/settings.json`
|
|
66
|
-
* - `windsurf` - 更新 Windsurf 配置文件 `~/.codeium/windsurf/mcp_config.json`
|
|
67
|
-
* - `claude-code` - 更新 Claude Code 配置文件 `.mcp.json`
|
|
68
|
-
* - `trae-cn` - 更新 Trae 配置文件 `~/trae CN/mcp.json`
|
|
69
|
-
* - `trae` - 更新 Trae 配置文件 `.trae/mcp.json`
|
|
70
|
-
*
|
|
71
|
-
* @default false
|
|
72
|
-
*/
|
|
73
|
-
updateConfig?: 'auto' | false | MaybeArray<SupportedUpdateConfigType>;
|
|
74
|
-
}
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region src/index.d.ts
|
|
77
|
-
declare function uniMcp(options?: UniMcpOptions): Plugin;
|
|
78
|
-
//#endregion
|
|
79
|
-
export { uniMcp as default };
|