@templmf/temp-solf-lmf 0.0.140 → 0.0.141

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@templmf/temp-solf-lmf",
3
- "version": "0.0.140",
3
+ "version": "0.0.141",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/pic.png ADDED
Binary file
package/confMCP.js DELETED
@@ -1,551 +0,0 @@
1
- import axios from "axios";
2
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
- import { z } from "zod";
4
- import LRUCache from "lru-cache";
5
- import { htmlToText } from "html-to-text";
6
- import BM25 from "wink-bm25-text-search";
7
-
8
- const server = new Server({
9
- name: "confluence-7.4.7",
10
- version: "1.0.0"
11
- });
12
-
13
- const baseURL = process.env.CONFLUENCE_BASE_URL;
14
- const authorization = process.env.CONFLUENCE_AUTHORIZATION;
15
-
16
- if (!baseURL || !authorization) {
17
- throw new Error(
18
- "CONFLUENCE_BASE_URL and CONFLUENCE_AUTHORIZATION are required"
19
- );
20
- }
21
-
22
- const client = axios.create({
23
- baseURL,
24
- timeout: 30000,
25
- headers: {
26
- Authorization: authorization,
27
- Accept: "application/json"
28
- }
29
- });
30
-
31
- const pageCache = new LRUCache({
32
- max: 100,
33
- ttl: 1000 * 60 * 10
34
- });
35
-
36
- function stripHtml(html = "") {
37
- return html
38
- .replace(/<[^>]+>/g, " ")
39
- .replace(/\s+/g, " ")
40
- .trim();
41
- }
42
-
43
- function buildCql({
44
- keywords = [],
45
- spaces = [],
46
- contributors = []
47
- }) {
48
- const clauses = [];
49
-
50
- if (spaces.length) {
51
- clauses.push(
52
- "(" +
53
- spaces
54
- .map((v) => `space="${v}"`)
55
- .join(" OR ") +
56
- ")"
57
- );
58
- }
59
-
60
- if (contributors.length) {
61
- clauses.push(
62
- "(" +
63
- contributors
64
- .map((v) => `contributor="${v}"`)
65
- .join(" OR ") +
66
- ")"
67
- );
68
- }
69
-
70
- if (keywords.length) {
71
- clauses.push(
72
- "(" +
73
- keywords
74
- .map((v) => `text~"${v}"`)
75
- .join(" OR ") +
76
- ")"
77
- );
78
- }
79
-
80
- return clauses.join(" AND ");
81
- }
82
-
83
- async function getPageById(pageId) {
84
- const cached = pageCache.get(pageId);
85
-
86
- if (cached) {
87
- return cached;
88
- }
89
-
90
- const { data } = await client.get(
91
- `/rest/api/content/${pageId}`,
92
- {
93
- params: {
94
- expand: "body.storage,version,space"
95
- }
96
- }
97
- );
98
-
99
- const result = {
100
- id: data.id,
101
- title: data.title,
102
- space: data.space?.key,
103
- version: data.version?.number,
104
- url: `${baseURL}${data._links?.webui}`,
105
- content: data.body?.storage?.value || ""
106
- };
107
-
108
- pageCache.set(pageId, result);
109
-
110
- return result;
111
- }
112
-
113
- async function getPageByTitle(
114
- title,
115
- space
116
- ) {
117
- const params = {
118
- title,
119
- expand: "body.storage"
120
- };
121
-
122
- if (space) {
123
- params.spaceKey = space;
124
- }
125
-
126
- const { data } = await client.get(
127
- "/rest/api/content",
128
- {
129
- params
130
- }
131
- );
132
-
133
- const page = data.results?.[0];
134
-
135
- if (!page) {
136
- return null;
137
- }
138
-
139
- return {
140
- id: page.id,
141
- title: page.title,
142
- url: `${baseURL}${page._links?.webui}`
143
- };
144
- }
145
-
146
- async function getSpaces() {
147
- const { data } = await client.get(
148
- "/rest/api/space"
149
- );
150
-
151
- return data.results.map((v) => ({
152
- key: v.key,
153
- name: v.name
154
- }));
155
- }
156
-
157
- async function searchPages({
158
- keywords,
159
- spaces = [],
160
- contributors = [],
161
- limit = 10
162
- }) {
163
- const cql = buildCql({
164
- keywords,
165
- spaces,
166
- contributors
167
- });
168
-
169
- const { data } = await client.get(
170
- "/rest/api/search",
171
- {
172
- params: {
173
- cql,
174
- limit
175
- }
176
- }
177
- );
178
-
179
- return data.results.map((item) => ({
180
- pageId: item.content?.id,
181
- title: item.title,
182
- url: `${baseURL}${item.url}`
183
- }));
184
- }
185
-
186
- server.registerTool(
187
- "get_page_by_id",
188
- {
189
- title: "Get Page By Id",
190
- description:
191
- "Get Confluence page content by page id",
192
- inputSchema: {
193
- pageId: z.string()
194
- }
195
- },
196
- async ({ pageId }) => {
197
- return await getPageById(pageId);
198
- }
199
- );
200
-
201
- server.registerTool(
202
- "get_page_by_title",
203
- {
204
- title: "Get Page By Title",
205
- description:
206
- "Find page by title",
207
- inputSchema: {
208
- title: z.string(),
209
- space: z.string().optional()
210
- }
211
- },
212
- async ({ title, space }) => {
213
- return await getPageByTitle(
214
- title,
215
- space
216
- );
217
- }
218
- );
219
-
220
- server.registerTool(
221
- "get_spaces",
222
- {
223
- title: "Get Spaces",
224
- description:
225
- "List all spaces"
226
- },
227
- async () => {
228
- return await getSpaces();
229
- }
230
- );
231
-
232
- server.registerTool(
233
- "search_pages",
234
- {
235
- title: "Search Pages",
236
- description:
237
- "Search pages by keywords, spaces and contributors",
238
- inputSchema: {
239
- keywords: z
240
- .array(z.string())
241
- .min(1),
242
-
243
- spaces: z
244
- .array(z.string())
245
- .optional(),
246
-
247
- contributors: z
248
- .array(z.string())
249
- .optional(),
250
-
251
- limit: z.number().default(10)
252
- }
253
- },
254
- async (args) => {
255
- return await searchPages(args);
256
- }
257
- );
258
-
259
- async function getChildren(pageId) {
260
- const { data } = await client.get(
261
- `/rest/api/content/${pageId}/child/page`
262
- );
263
-
264
- return data.results.map((v) => ({
265
- id: v.id,
266
- title: v.title
267
- }));
268
- }
269
-
270
- async function buildTree(pageId, depth) {
271
- const page = await getPageById(pageId);
272
-
273
- if (depth <= 0) {
274
- return {
275
- id: page.id,
276
- title: page.title
277
- };
278
- }
279
-
280
- const children = await getChildren(pageId);
281
-
282
- return {
283
- id: page.id,
284
- title: page.title,
285
- children: await Promise.all(
286
- children.map((v) =>
287
- buildTree(v.id, depth - 1)
288
- )
289
- )
290
- };
291
- }
292
-
293
- function chunkText(
294
- text,
295
- size = 1200,
296
- overlap = 200
297
- ) {
298
- const chunks = [];
299
-
300
- let start = 0;
301
-
302
- while (start < text.length) {
303
- chunks.push(
304
- text.slice(start, start + size)
305
- );
306
-
307
- start += size - overlap;
308
- }
309
-
310
- return chunks;
311
- }
312
-
313
- function buildQueries(question) {
314
- const queries = [question];
315
-
316
- queries.push(
317
- ...question
318
- .split(/[ ,,、]/)
319
- .map((v) => v.trim())
320
- .filter(Boolean)
321
- );
322
-
323
- return [...new Set(queries)];
324
- }
325
-
326
- async function hybridSearch({
327
- question,
328
- spaces,
329
- contributors,
330
- maxPages = 10
331
- }) {
332
- const queries = buildQueries(question);
333
-
334
- const weights = [
335
- 1,
336
- 0.8,
337
- 0.6,
338
- 0.4,
339
- 0.2
340
- ];
341
-
342
- const scoreMap = new Map();
343
-
344
- for (let i = 0; i < queries.length; i++) {
345
- const pages = await searchPages({
346
- keywords: [queries[i]],
347
- spaces,
348
- contributors,
349
- limit: 20
350
- });
351
-
352
- for (const page of pages) {
353
- const old =
354
- scoreMap.get(page.pageId) || {
355
- ...page,
356
- score: 0
357
- };
358
-
359
- old.score += weights[i] || 0.1;
360
-
361
- scoreMap.set(page.pageId, old);
362
- }
363
- }
364
-
365
- return [...scoreMap.values()]
366
- .sort((a, b) => b.score - a.score)
367
- .slice(0, maxPages);
368
- }
369
-
370
- async function askConfluence({
371
- question,
372
- spaces,
373
- contributors,
374
- maxPages = 10,
375
- maxChunks = 15
376
- }) {
377
- const pages = await hybridSearch({
378
- question,
379
- spaces,
380
- contributors,
381
- maxPages
382
- });
383
-
384
- const documents = [];
385
-
386
- for (const page of pages) {
387
- const detail = await getPageById(
388
- page.pageId
389
- );
390
-
391
- const text = htmlToText(
392
- detail.content,
393
- {
394
- wordwrap: false
395
- }
396
- );
397
-
398
- const chunks = chunkText(text);
399
-
400
- chunks.forEach((chunk) => {
401
- documents.push({
402
- pageId: detail.id,
403
- title: detail.title,
404
- url: detail.url,
405
- chunk
406
- });
407
- });
408
- }
409
-
410
- const engine = BM25();
411
-
412
- engine.defineConfig({
413
- fldWeights: {
414
- chunk: 1
415
- }
416
- });
417
-
418
- engine.definePrepTasks([]);
419
-
420
- engine.defineField("chunk");
421
-
422
- engine.defineRef("id");
423
-
424
- engine.configure();
425
-
426
- documents.forEach((doc, index) => {
427
- engine.addDoc(index, {
428
- chunk: doc.chunk
429
- });
430
- });
431
-
432
- engine.consolidate();
433
-
434
- const results = engine.search(
435
- question,
436
- maxChunks
437
- );
438
-
439
- return results.map((v) => {
440
- const doc = documents[v[0]];
441
-
442
- return {
443
- title: doc.title,
444
- url: doc.url,
445
- score: v[1],
446
- content: doc.chunk
447
- };
448
- });
449
- }
450
-
451
- async function exploreConfluence(
452
- topic
453
- ) {
454
- const pages = await searchPages({
455
- keywords: [topic],
456
- limit: 5
457
- });
458
-
459
- const result = [];
460
-
461
- for (const page of pages) {
462
- const children = await getChildren(
463
- page.pageId
464
- );
465
-
466
- result.push({
467
- page,
468
- children
469
- });
470
- }
471
-
472
- return result;
473
- }
474
-
475
- server.registerTool(
476
- "get_children",
477
- {
478
- title: "Get Children",
479
- description:
480
- "Get child pages",
481
- inputSchema: {
482
- pageId: z.string()
483
- }
484
- },
485
- async ({ pageId }) =>
486
- getChildren(pageId)
487
- );
488
-
489
- server.registerTool(
490
- "get_page_tree",
491
- {
492
- title: "Get Page Tree",
493
- description:
494
- "Get page tree recursively",
495
- inputSchema: {
496
- rootPageId: z.string(),
497
- depth: z.number().default(2)
498
- }
499
- },
500
- async ({
501
- rootPageId,
502
- depth
503
- }) =>
504
- buildTree(rootPageId, depth)
505
- );
506
-
507
- server.registerTool(
508
- "ask_confluence",
509
- {
510
- title: "Ask Confluence",
511
- description:
512
- "Retrieve relevant contexts from Confluence",
513
-
514
- inputSchema: {
515
- question: z.string(),
516
-
517
- spaces: z
518
- .array(z.string())
519
- .optional(),
520
-
521
- contributors: z
522
- .array(z.string())
523
- .optional(),
524
-
525
- maxPages: z
526
- .number()
527
- .default(10),
528
-
529
- maxChunks: z
530
- .number()
531
- .default(15)
532
- }
533
- },
534
- async (args) =>
535
- askConfluence(args)
536
- );
537
-
538
- server.registerTool(
539
- "explore_confluence",
540
- {
541
- title: "Explore Topic",
542
- description:
543
- "Explore topic related pages",
544
-
545
- inputSchema: {
546
- topic: z.string()
547
- }
548
- },
549
- async ({ topic }) =>
550
- exploreConfluence(topic)
551
- );