@contiva/sapbtp-docs-mcp 1.0.1
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/LICENSE +395 -0
- package/README.md +386 -0
- package/build/cache/embedding-cache.d.ts +39 -0
- package/build/cache/embedding-cache.d.ts.map +1 -0
- package/build/cache/embedding-cache.js +105 -0
- package/build/cache/embedding-cache.js.map +1 -0
- package/build/cache/file-cache.d.ts +40 -0
- package/build/cache/file-cache.d.ts.map +1 -0
- package/build/cache/file-cache.js +124 -0
- package/build/cache/file-cache.js.map +1 -0
- package/build/cache/search-cache.d.ts +39 -0
- package/build/cache/search-cache.d.ts.map +1 -0
- package/build/cache/search-cache.js +97 -0
- package/build/cache/search-cache.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +17 -0
- package/build/index.js.map +1 -0
- package/build/indexing/file-registry.d.ts +47 -0
- package/build/indexing/file-registry.d.ts.map +1 -0
- package/build/indexing/file-registry.js +130 -0
- package/build/indexing/file-registry.js.map +1 -0
- package/build/indexing/topic-index.d.ts +57 -0
- package/build/indexing/topic-index.d.ts.map +1 -0
- package/build/indexing/topic-index.js +181 -0
- package/build/indexing/topic-index.js.map +1 -0
- package/build/parsers/links.d.ts +14 -0
- package/build/parsers/links.d.ts.map +1 -0
- package/build/parsers/links.js +80 -0
- package/build/parsers/links.js.map +1 -0
- package/build/parsers/markdown.d.ts +10 -0
- package/build/parsers/markdown.d.ts.map +1 -0
- package/build/parsers/markdown.js +120 -0
- package/build/parsers/markdown.js.map +1 -0
- package/build/parsers/metadata.d.ts +19 -0
- package/build/parsers/metadata.d.ts.map +1 -0
- package/build/parsers/metadata.js +63 -0
- package/build/parsers/metadata.js.map +1 -0
- package/build/search/fulltext.d.ts +20 -0
- package/build/search/fulltext.d.ts.map +1 -0
- package/build/search/fulltext.js +117 -0
- package/build/search/fulltext.js.map +1 -0
- package/build/search/ranking.d.ts +27 -0
- package/build/search/ranking.d.ts.map +1 -0
- package/build/search/ranking.js +119 -0
- package/build/search/ranking.js.map +1 -0
- package/build/search/semantic.d.ts +53 -0
- package/build/search/semantic.d.ts.map +1 -0
- package/build/search/semantic.js +260 -0
- package/build/search/semantic.js.map +1 -0
- package/build/search/title.d.ts +18 -0
- package/build/search/title.d.ts.map +1 -0
- package/build/search/title.js +95 -0
- package/build/search/title.js.map +1 -0
- package/build/server.d.ts +32 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +183 -0
- package/build/server.js.map +1 -0
- package/build/tools/get-related.d.ts +64 -0
- package/build/tools/get-related.d.ts.map +1 -0
- package/build/tools/get-related.js +203 -0
- package/build/tools/get-related.js.map +1 -0
- package/build/tools/list-topics.d.ts +43 -0
- package/build/tools/list-topics.d.ts.map +1 -0
- package/build/tools/list-topics.js +63 -0
- package/build/tools/list-topics.js.map +1 -0
- package/build/tools/read-article.d.ts +42 -0
- package/build/tools/read-article.d.ts.map +1 -0
- package/build/tools/read-article.js +89 -0
- package/build/tools/read-article.js.map +1 -0
- package/build/tools/search.d.ts +57 -0
- package/build/tools/search.d.ts.map +1 -0
- package/build/tools/search.js +109 -0
- package/build/tools/search.js.map +1 -0
- package/build/types/index.d.ts +179 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/build/utils/docs-downloader.d.ts +9 -0
- package/build/utils/docs-downloader.d.ts.map +1 -0
- package/build/utils/docs-downloader.js +82 -0
- package/build/utils/docs-downloader.js.map +1 -0
- package/build/utils/paths.d.ts +67 -0
- package/build/utils/paths.d.ts.map +1 -0
- package/build/utils/paths.js +132 -0
- package/build/utils/paths.js.map +1 -0
- package/build/utils/text-processing.d.ts +62 -0
- package/build/utils/text-processing.d.ts.map +1 -0
- package/build/utils/text-processing.js +214 -0
- package/build/utils/text-processing.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { normalizeText, fuzzyMatchScore, containsAllWords, tokenize } from '../utils/text-processing.js';
|
|
2
|
+
/**
|
|
3
|
+
* Title-based search implementation
|
|
4
|
+
*/
|
|
5
|
+
export class TitleSearch {
|
|
6
|
+
registry;
|
|
7
|
+
constructor(registry) {
|
|
8
|
+
this.registry = registry;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Performs title-based search
|
|
12
|
+
*/
|
|
13
|
+
async search(options) {
|
|
14
|
+
const { query, area = 'all', limit = 15 } = options;
|
|
15
|
+
// Get files to search
|
|
16
|
+
const files = area === 'all'
|
|
17
|
+
? this.registry.getAllFiles()
|
|
18
|
+
: this.registry.getByArea(area);
|
|
19
|
+
// Score each file by title
|
|
20
|
+
const scoredResults = files.map(file => {
|
|
21
|
+
const score = this.scoreTitle(file.title, query);
|
|
22
|
+
if (score > 0) {
|
|
23
|
+
return {
|
|
24
|
+
result: {
|
|
25
|
+
filePath: file.filePath,
|
|
26
|
+
relativePath: file.relativePath,
|
|
27
|
+
title: file.title,
|
|
28
|
+
loioId: file.loioId,
|
|
29
|
+
snippet: file.title, // Use title as snippet for title search
|
|
30
|
+
score,
|
|
31
|
+
matchType: 'title',
|
|
32
|
+
area: file.area,
|
|
33
|
+
},
|
|
34
|
+
score,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}).filter((r) => r !== null);
|
|
39
|
+
// Sort by score (descending)
|
|
40
|
+
scoredResults.sort((a, b) => b.score - a.score);
|
|
41
|
+
// Return top results
|
|
42
|
+
return scoredResults.slice(0, limit).map(r => r.result);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Scores a title based on query relevance
|
|
46
|
+
*/
|
|
47
|
+
scoreTitle(title, query) {
|
|
48
|
+
const normalizedTitle = normalizeText(title);
|
|
49
|
+
const normalizedQuery = normalizeText(query);
|
|
50
|
+
let score = 0;
|
|
51
|
+
// Exact match (case-insensitive)
|
|
52
|
+
if (normalizedTitle === normalizedQuery) {
|
|
53
|
+
return 100;
|
|
54
|
+
}
|
|
55
|
+
// Exact match (case-sensitive)
|
|
56
|
+
if (title === query) {
|
|
57
|
+
return 95;
|
|
58
|
+
}
|
|
59
|
+
// Contains exact query
|
|
60
|
+
if (normalizedTitle.includes(normalizedQuery)) {
|
|
61
|
+
score += 80;
|
|
62
|
+
}
|
|
63
|
+
// Starts with query
|
|
64
|
+
if (normalizedTitle.startsWith(normalizedQuery)) {
|
|
65
|
+
score += 70;
|
|
66
|
+
}
|
|
67
|
+
// Contains all words from query
|
|
68
|
+
if (containsAllWords(title, query)) {
|
|
69
|
+
score += 60;
|
|
70
|
+
}
|
|
71
|
+
// Fuzzy match (Levenshtein distance)
|
|
72
|
+
const fuzzyScore = fuzzyMatchScore(title, query);
|
|
73
|
+
if (fuzzyScore > 70) {
|
|
74
|
+
score += fuzzyScore / 2; // Reduce weight of fuzzy matches
|
|
75
|
+
}
|
|
76
|
+
// Individual word matches
|
|
77
|
+
const titleTokens = tokenize(title);
|
|
78
|
+
const queryTokens = tokenize(query);
|
|
79
|
+
for (const queryToken of queryTokens) {
|
|
80
|
+
for (const titleToken of titleTokens) {
|
|
81
|
+
if (titleToken === queryToken) {
|
|
82
|
+
score += 20; // Exact word match
|
|
83
|
+
}
|
|
84
|
+
else if (titleToken.startsWith(queryToken)) {
|
|
85
|
+
score += 10; // Word prefix match
|
|
86
|
+
}
|
|
87
|
+
else if (titleToken.includes(queryToken)) {
|
|
88
|
+
score += 5; // Partial word match
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return score;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.js","sourceRoot":"","sources":["../../src/search/title.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SAP Business Technology Platform Documentation MCP Server
|
|
3
|
+
*/
|
|
4
|
+
export declare class SAPISDocsServer {
|
|
5
|
+
private server;
|
|
6
|
+
private config;
|
|
7
|
+
private fileRegistry;
|
|
8
|
+
private topicIndex;
|
|
9
|
+
private fileCache;
|
|
10
|
+
private searchCache;
|
|
11
|
+
private fulltextSearch;
|
|
12
|
+
private titleSearch;
|
|
13
|
+
private semanticSearch;
|
|
14
|
+
private searchTool;
|
|
15
|
+
private readArticleTool;
|
|
16
|
+
private listTopicsTool;
|
|
17
|
+
private getRelatedTool;
|
|
18
|
+
constructor();
|
|
19
|
+
/**
|
|
20
|
+
* Initializes the server components
|
|
21
|
+
*/
|
|
22
|
+
initialize(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Sets up request handlers
|
|
25
|
+
*/
|
|
26
|
+
private setupHandlers;
|
|
27
|
+
/**
|
|
28
|
+
* Starts the server
|
|
29
|
+
*/
|
|
30
|
+
start(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAqBA;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAe;IAG7B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,WAAW,CAAe;IAGlC,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,cAAc,CAAkB;IAGxC,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,eAAe,CAAmB;IAC1C,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,cAAc,CAA0B;;IA6BhD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgDjC;;OAEG;IACH,OAAO,CAAC,aAAa;IAqFrB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
|
package/build/server.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { FileRegistry } from './indexing/file-registry.js';
|
|
5
|
+
import { TopicIndex } from './indexing/topic-index.js';
|
|
6
|
+
import { FileCache } from './cache/file-cache.js';
|
|
7
|
+
import { SearchCache } from './cache/search-cache.js';
|
|
8
|
+
import { FullTextSearch } from './search/fulltext.js';
|
|
9
|
+
import { TitleSearch } from './search/title.js';
|
|
10
|
+
import { SemanticSearch } from './search/semantic.js';
|
|
11
|
+
import { SearchTool } from './tools/search.js';
|
|
12
|
+
import { ReadArticleTool } from './tools/read-article.js';
|
|
13
|
+
import { ListTopicsTool } from './tools/list-topics.js';
|
|
14
|
+
import { GetRelatedArticlesTool } from './tools/get-related.js';
|
|
15
|
+
import { resolveDocsPath, resolveCacheDir } from './utils/paths.js';
|
|
16
|
+
import { ensureDocsAvailable } from './utils/docs-downloader.js';
|
|
17
|
+
/**
|
|
18
|
+
* SAP Business Technology Platform Documentation MCP Server
|
|
19
|
+
*/
|
|
20
|
+
export class SAPISDocsServer {
|
|
21
|
+
server;
|
|
22
|
+
config;
|
|
23
|
+
// Components
|
|
24
|
+
fileRegistry;
|
|
25
|
+
topicIndex;
|
|
26
|
+
fileCache;
|
|
27
|
+
searchCache;
|
|
28
|
+
// Search engines
|
|
29
|
+
fulltextSearch;
|
|
30
|
+
titleSearch;
|
|
31
|
+
semanticSearch;
|
|
32
|
+
// Tools
|
|
33
|
+
searchTool;
|
|
34
|
+
readArticleTool;
|
|
35
|
+
listTopicsTool;
|
|
36
|
+
getRelatedTool;
|
|
37
|
+
constructor() {
|
|
38
|
+
this.server = new Server({
|
|
39
|
+
name: 'sapbtp-docs-mcp',
|
|
40
|
+
version: '1.0.0',
|
|
41
|
+
}, {
|
|
42
|
+
capabilities: {
|
|
43
|
+
tools: {},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
// Load configuration
|
|
47
|
+
this.config = {
|
|
48
|
+
docsPath: resolveDocsPath(),
|
|
49
|
+
cacheDir: resolveCacheDir(),
|
|
50
|
+
fileCacheSize: parseInt(process.env.MCP_FILE_CACHE_SIZE || '100'),
|
|
51
|
+
searchCacheTTL: parseInt(process.env.MCP_SEARCH_CACHE_TTL || '300'),
|
|
52
|
+
embeddingProvider: process.env.EMBEDDING_PROVIDER || 'local',
|
|
53
|
+
voyageApiKey: process.env.VOYAGE_API_KEY,
|
|
54
|
+
openaiApiKey: process.env.OPENAI_API_KEY,
|
|
55
|
+
};
|
|
56
|
+
this.setupHandlers();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Initializes the server components
|
|
60
|
+
*/
|
|
61
|
+
async initialize() {
|
|
62
|
+
console.error('Initializing SAP Business Technology Platform Documentation MCP Server...');
|
|
63
|
+
console.error(`Docs path: ${this.config.docsPath}`);
|
|
64
|
+
console.error(`Cache dir: ${this.config.cacheDir}`);
|
|
65
|
+
console.error(`Embedding provider: ${this.config.embeddingProvider}`);
|
|
66
|
+
// Ensure documentation is available (download if necessary)
|
|
67
|
+
const docsAvailable = await ensureDocsAvailable(this.config.docsPath);
|
|
68
|
+
if (!docsAvailable) {
|
|
69
|
+
throw new Error('Documentation not available and download failed. Please see instructions above.');
|
|
70
|
+
}
|
|
71
|
+
// Initialize caches
|
|
72
|
+
this.fileCache = new FileCache(this.config.fileCacheSize);
|
|
73
|
+
this.searchCache = new SearchCache(this.config.searchCacheTTL);
|
|
74
|
+
// Initialize indexing
|
|
75
|
+
this.fileRegistry = new FileRegistry(this.config.docsPath);
|
|
76
|
+
await this.fileRegistry.build();
|
|
77
|
+
this.topicIndex = new TopicIndex(this.config.docsPath);
|
|
78
|
+
await this.topicIndex.build();
|
|
79
|
+
// Initialize search engines
|
|
80
|
+
this.fulltextSearch = new FullTextSearch(this.fileRegistry, this.fileCache);
|
|
81
|
+
this.titleSearch = new TitleSearch(this.fileRegistry);
|
|
82
|
+
this.semanticSearch = new SemanticSearch(this.fileRegistry, this.fileCache);
|
|
83
|
+
// Initialize tools
|
|
84
|
+
this.searchTool = new SearchTool(this.fulltextSearch, this.titleSearch, this.semanticSearch, this.searchCache);
|
|
85
|
+
this.readArticleTool = new ReadArticleTool(this.fileRegistry, this.fileCache);
|
|
86
|
+
this.listTopicsTool = new ListTopicsTool(this.topicIndex);
|
|
87
|
+
this.getRelatedTool = new GetRelatedArticlesTool(this.fileRegistry, this.fileCache, this.semanticSearch);
|
|
88
|
+
console.error('Server initialized successfully!');
|
|
89
|
+
console.error(`Ready to search ${this.fileRegistry.size()} documentation files`);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Sets up request handlers
|
|
93
|
+
*/
|
|
94
|
+
setupHandlers() {
|
|
95
|
+
// List available tools
|
|
96
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
97
|
+
return {
|
|
98
|
+
tools: [
|
|
99
|
+
SearchTool.getSchema(),
|
|
100
|
+
ReadArticleTool.getSchema(),
|
|
101
|
+
ListTopicsTool.getSchema(),
|
|
102
|
+
GetRelatedArticlesTool.getSchema(),
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
// Handle tool calls
|
|
107
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
108
|
+
try {
|
|
109
|
+
const { name, arguments: args } = request.params;
|
|
110
|
+
switch (name) {
|
|
111
|
+
case 'search_documentation': {
|
|
112
|
+
const result = await this.searchTool.execute(args);
|
|
113
|
+
return {
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: 'text',
|
|
117
|
+
text: JSON.stringify(result, null, 2),
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
case 'read_article': {
|
|
123
|
+
const result = await this.readArticleTool.execute(args);
|
|
124
|
+
return {
|
|
125
|
+
content: [
|
|
126
|
+
{
|
|
127
|
+
type: 'text',
|
|
128
|
+
text: JSON.stringify(result, null, 2),
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
case 'list_topics': {
|
|
134
|
+
const result = await this.listTopicsTool.execute(args);
|
|
135
|
+
return {
|
|
136
|
+
content: [
|
|
137
|
+
{
|
|
138
|
+
type: 'text',
|
|
139
|
+
text: JSON.stringify(result, null, 2),
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
case 'get_related_articles': {
|
|
145
|
+
const result = await this.getRelatedTool.execute(args);
|
|
146
|
+
return {
|
|
147
|
+
content: [
|
|
148
|
+
{
|
|
149
|
+
type: 'text',
|
|
150
|
+
text: JSON.stringify(result, null, 2),
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
default:
|
|
156
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
161
|
+
return {
|
|
162
|
+
content: [
|
|
163
|
+
{
|
|
164
|
+
type: 'text',
|
|
165
|
+
text: `Error: ${errorMessage}`,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
isError: true,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Starts the server
|
|
175
|
+
*/
|
|
176
|
+
async start() {
|
|
177
|
+
await this.initialize();
|
|
178
|
+
const transport = new StdioServerTransport();
|
|
179
|
+
await this.server.connect(transport);
|
|
180
|
+
console.error('Server running on stdio');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { GetRelatedArticlesInput, GetRelatedArticlesOutput } from '../types/index.js';
|
|
2
|
+
import { FileRegistry } from '../indexing/file-registry.js';
|
|
3
|
+
import { FileCache } from '../cache/file-cache.js';
|
|
4
|
+
import { SemanticSearch } from '../search/semantic.js';
|
|
5
|
+
/**
|
|
6
|
+
* Get related articles tool handler
|
|
7
|
+
*/
|
|
8
|
+
export declare class GetRelatedArticlesTool {
|
|
9
|
+
private registry;
|
|
10
|
+
private fileCache;
|
|
11
|
+
private semanticSearch;
|
|
12
|
+
constructor(registry: FileRegistry, fileCache: FileCache, semanticSearch: SemanticSearch);
|
|
13
|
+
/**
|
|
14
|
+
* Finds articles related to a given article
|
|
15
|
+
*/
|
|
16
|
+
execute(input: GetRelatedArticlesInput): Promise<GetRelatedArticlesOutput>;
|
|
17
|
+
/**
|
|
18
|
+
* Finds related articles based on links
|
|
19
|
+
*/
|
|
20
|
+
private findByLinks;
|
|
21
|
+
/**
|
|
22
|
+
* Finds related articles based on semantic similarity
|
|
23
|
+
*/
|
|
24
|
+
private findBySemantic;
|
|
25
|
+
/**
|
|
26
|
+
* Deduplicates and sorts related articles
|
|
27
|
+
*/
|
|
28
|
+
private deduplicateAndSort;
|
|
29
|
+
/**
|
|
30
|
+
* Resolves identifier to file path
|
|
31
|
+
*/
|
|
32
|
+
private resolveIdentifier;
|
|
33
|
+
/**
|
|
34
|
+
* Gets the tool schema for MCP
|
|
35
|
+
*/
|
|
36
|
+
static getSchema(): {
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: string;
|
|
41
|
+
properties: {
|
|
42
|
+
identifier: {
|
|
43
|
+
type: string;
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
46
|
+
method: {
|
|
47
|
+
type: string;
|
|
48
|
+
enum: string[];
|
|
49
|
+
description: string;
|
|
50
|
+
default: string;
|
|
51
|
+
};
|
|
52
|
+
limit: {
|
|
53
|
+
type: string;
|
|
54
|
+
description: string;
|
|
55
|
+
default: number;
|
|
56
|
+
minimum: number;
|
|
57
|
+
maximum: number;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
required: string[];
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=get-related.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-related.d.ts","sourceRoot":"","sources":["../../src/tools/get-related.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,wBAAwB,EAAkB,MAAM,mBAAmB,CAAC;AAC3G,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAIvD;;GAEG;AACH,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,cAAc;gBAFd,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,cAAc;IAGxC;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAuChF;;OAEG;YACW,WAAW;IAwBzB;;OAEG;YACW,cAAc;IAiD5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAuC1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;OAEG;IACH,MAAM,CAAC,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BjB"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { cosineSimilarity } from '../utils/text-processing.js';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
/**
|
|
4
|
+
* Get related articles tool handler
|
|
5
|
+
*/
|
|
6
|
+
export class GetRelatedArticlesTool {
|
|
7
|
+
registry;
|
|
8
|
+
fileCache;
|
|
9
|
+
semanticSearch;
|
|
10
|
+
constructor(registry, fileCache, semanticSearch) {
|
|
11
|
+
this.registry = registry;
|
|
12
|
+
this.fileCache = fileCache;
|
|
13
|
+
this.semanticSearch = semanticSearch;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Finds articles related to a given article
|
|
17
|
+
*/
|
|
18
|
+
async execute(input) {
|
|
19
|
+
const { identifier, method = 'both', limit = 10 } = input;
|
|
20
|
+
// Resolve identifier to file path
|
|
21
|
+
const filePath = this.resolveIdentifier(identifier);
|
|
22
|
+
if (!filePath) {
|
|
23
|
+
throw new Error(`Article not found: ${identifier}`);
|
|
24
|
+
}
|
|
25
|
+
// Get source document
|
|
26
|
+
const sourceDoc = await this.fileCache.get(filePath);
|
|
27
|
+
// Find related articles based on method
|
|
28
|
+
let relatedArticles = [];
|
|
29
|
+
if (method === 'links' || method === 'both') {
|
|
30
|
+
const linkRelated = await this.findByLinks(filePath);
|
|
31
|
+
relatedArticles.push(...linkRelated);
|
|
32
|
+
}
|
|
33
|
+
if (method === 'semantic' || method === 'both') {
|
|
34
|
+
const semanticRelated = await this.findBySemantic(filePath, limit);
|
|
35
|
+
relatedArticles.push(...semanticRelated);
|
|
36
|
+
}
|
|
37
|
+
// Deduplicate and sort
|
|
38
|
+
const deduped = this.deduplicateAndSort(relatedArticles, limit);
|
|
39
|
+
return {
|
|
40
|
+
sourceArticle: {
|
|
41
|
+
title: sourceDoc.title,
|
|
42
|
+
filePath: sourceDoc.metadata.filePath,
|
|
43
|
+
loioId: sourceDoc.loioId,
|
|
44
|
+
},
|
|
45
|
+
relatedArticles: deduped,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Finds related articles based on links
|
|
50
|
+
*/
|
|
51
|
+
async findByLinks(filePath) {
|
|
52
|
+
const doc = await this.fileCache.get(filePath);
|
|
53
|
+
const relatedArticles = [];
|
|
54
|
+
// Get all internal links
|
|
55
|
+
const internalLinks = doc.links.filter(link => !link.isExternal && existsSync(link.absolutePath));
|
|
56
|
+
for (const link of internalLinks) {
|
|
57
|
+
const entry = this.registry.getByPath(link.absolutePath);
|
|
58
|
+
if (entry) {
|
|
59
|
+
relatedArticles.push({
|
|
60
|
+
title: entry.title,
|
|
61
|
+
filePath: link.absolutePath,
|
|
62
|
+
relationshipType: 'explicit_link',
|
|
63
|
+
score: 100, // Explicit links get highest score
|
|
64
|
+
loioId: entry.loioId,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return relatedArticles;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Finds related articles based on semantic similarity
|
|
72
|
+
*/
|
|
73
|
+
async findBySemantic(filePath, limit) {
|
|
74
|
+
try {
|
|
75
|
+
// Get embedding for source document
|
|
76
|
+
const sourceEmbedding = await this.semanticSearch.getDocumentEmbedding(filePath);
|
|
77
|
+
if (!sourceEmbedding) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
// Get all files
|
|
81
|
+
const files = this.registry.getAllFiles();
|
|
82
|
+
const similarities = [];
|
|
83
|
+
// Calculate similarity to each file
|
|
84
|
+
for (const file of files) {
|
|
85
|
+
// Skip the source file itself
|
|
86
|
+
if (file.filePath === filePath) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const embedding = await this.semanticSearch.getDocumentEmbedding(file.filePath);
|
|
90
|
+
if (embedding) {
|
|
91
|
+
const similarity = cosineSimilarity(sourceEmbedding, embedding);
|
|
92
|
+
const score = similarity * 100;
|
|
93
|
+
if (score > 50) { // Only include if reasonably similar
|
|
94
|
+
similarities.push({ file, score });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Sort by score and take top results
|
|
99
|
+
similarities.sort((a, b) => b.score - a.score);
|
|
100
|
+
return similarities.slice(0, limit).map(({ file, score }) => ({
|
|
101
|
+
title: file.title,
|
|
102
|
+
filePath: file.filePath,
|
|
103
|
+
relationshipType: 'semantic',
|
|
104
|
+
score,
|
|
105
|
+
loioId: file.loioId,
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// Semantic search might not be initialized
|
|
110
|
+
console.error('Semantic search not available:', error);
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Deduplicates and sorts related articles
|
|
116
|
+
*/
|
|
117
|
+
deduplicateAndSort(articles, limit) {
|
|
118
|
+
const fileMap = new Map();
|
|
119
|
+
for (const article of articles) {
|
|
120
|
+
const existing = fileMap.get(article.filePath);
|
|
121
|
+
if (!existing) {
|
|
122
|
+
fileMap.set(article.filePath, article);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Keep the one with higher score, or prefer explicit links
|
|
126
|
+
if (article.score > existing.score) {
|
|
127
|
+
article.relationshipType = existing.relationshipType === 'explicit_link'
|
|
128
|
+
? 'combined'
|
|
129
|
+
: article.relationshipType;
|
|
130
|
+
fileMap.set(article.filePath, article);
|
|
131
|
+
}
|
|
132
|
+
else if (article.relationshipType === 'explicit_link') {
|
|
133
|
+
existing.relationshipType = 'combined';
|
|
134
|
+
existing.score = Math.max(existing.score, article.score);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Convert to array and sort
|
|
139
|
+
return Array.from(fileMap.values())
|
|
140
|
+
.sort((a, b) => {
|
|
141
|
+
// Prioritize explicit links
|
|
142
|
+
if (a.relationshipType === 'explicit_link' && b.relationshipType !== 'explicit_link') {
|
|
143
|
+
return -1;
|
|
144
|
+
}
|
|
145
|
+
if (b.relationshipType === 'explicit_link' && a.relationshipType !== 'explicit_link') {
|
|
146
|
+
return 1;
|
|
147
|
+
}
|
|
148
|
+
// Then sort by score
|
|
149
|
+
return b.score - a.score;
|
|
150
|
+
})
|
|
151
|
+
.slice(0, limit);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Resolves identifier to file path
|
|
155
|
+
*/
|
|
156
|
+
resolveIdentifier(identifier) {
|
|
157
|
+
// Check if it's a LOIO ID
|
|
158
|
+
if (identifier.startsWith('loio')) {
|
|
159
|
+
const entry = this.registry.getByLoioId(identifier);
|
|
160
|
+
return entry ? entry.filePath : null;
|
|
161
|
+
}
|
|
162
|
+
// Check if it's a direct file path
|
|
163
|
+
if (existsSync(identifier)) {
|
|
164
|
+
return identifier;
|
|
165
|
+
}
|
|
166
|
+
// Try to find in registry
|
|
167
|
+
const entry = this.registry.getByPath(identifier);
|
|
168
|
+
return entry ? entry.filePath : null;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Gets the tool schema for MCP
|
|
172
|
+
*/
|
|
173
|
+
static getSchema() {
|
|
174
|
+
return {
|
|
175
|
+
name: 'get_related_articles',
|
|
176
|
+
description: 'Find articles related to a given article based on links and content similarity.',
|
|
177
|
+
inputSchema: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
properties: {
|
|
180
|
+
identifier: {
|
|
181
|
+
type: 'string',
|
|
182
|
+
description: 'File path or LOIO ID of the article'
|
|
183
|
+
},
|
|
184
|
+
method: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
enum: ['links', 'semantic', 'both'],
|
|
187
|
+
description: 'How to find related articles: links (explicit references), semantic (similar content), both',
|
|
188
|
+
default: 'both'
|
|
189
|
+
},
|
|
190
|
+
limit: {
|
|
191
|
+
type: 'number',
|
|
192
|
+
description: 'Maximum number of related articles to return',
|
|
193
|
+
default: 10,
|
|
194
|
+
minimum: 1,
|
|
195
|
+
maximum: 30
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
required: ['identifier']
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=get-related.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-related.js","sourceRoot":"","sources":["../../src/tools/get-related.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ListTopicsInput, TopicHierarchy } from '../types/index.js';
|
|
2
|
+
import { TopicIndex } from '../indexing/topic-index.js';
|
|
3
|
+
/**
|
|
4
|
+
* List topics tool handler
|
|
5
|
+
*/
|
|
6
|
+
export declare class ListTopicsTool {
|
|
7
|
+
private topicIndex;
|
|
8
|
+
constructor(topicIndex: TopicIndex);
|
|
9
|
+
/**
|
|
10
|
+
* Lists documentation topics in hierarchical structure
|
|
11
|
+
*/
|
|
12
|
+
execute(input: ListTopicsInput): Promise<TopicHierarchy>;
|
|
13
|
+
/**
|
|
14
|
+
* Gets the tool schema for MCP
|
|
15
|
+
*/
|
|
16
|
+
static getSchema(): {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: string;
|
|
21
|
+
properties: {
|
|
22
|
+
area: {
|
|
23
|
+
type: string;
|
|
24
|
+
enum: string[];
|
|
25
|
+
description: string;
|
|
26
|
+
};
|
|
27
|
+
depth: {
|
|
28
|
+
type: string;
|
|
29
|
+
description: string;
|
|
30
|
+
default: number;
|
|
31
|
+
minimum: number;
|
|
32
|
+
maximum: number;
|
|
33
|
+
};
|
|
34
|
+
parentPath: {
|
|
35
|
+
type: string;
|
|
36
|
+
description: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
required: string[];
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=list-topics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-topics.d.ts","sourceRoot":"","sources":["../../src/tools/list-topics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAExD;;GAEG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,UAAU;gBAAV,UAAU,EAAE,UAAU;IAE1C;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAwB9D;;OAEG;IACH,MAAM,CAAC,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BjB"}
|