@public-ui/mcp 4.3.0-rc.6 → 4.3.0-rc.8
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/dist/cli.cjs +4 -1
- package/dist/cli.mjs +4 -1
- package/dist/mcp.cjs +503 -31
- package/dist/mcp.d.cts +1 -1
- package/dist/mcp.d.mts +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.mjs +502 -31
- package/package.json +8 -5
- package/shared/sample-index.json +36 -28
package/dist/cli.cjs
CHANGED
|
@@ -13,13 +13,16 @@ require('express');
|
|
|
13
13
|
require('zod');
|
|
14
14
|
require('./search.cjs');
|
|
15
15
|
require('fuse.js');
|
|
16
|
+
require('node:path');
|
|
17
|
+
require('glob');
|
|
18
|
+
require('simple-git');
|
|
16
19
|
|
|
17
20
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
18
21
|
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
|
|
19
22
|
const { version: PACKAGE_VERSION = "0.0.0" } = require$1("../package.json");
|
|
20
23
|
const ENABLE_LOGGING = process.env.MCP_LOGGING === "true" || process.env.MCP_LOGGING === "1";
|
|
21
24
|
async function main() {
|
|
22
|
-
const server = mcp.createKolibriMcpServer();
|
|
25
|
+
const server = await mcp.createKolibriMcpServer();
|
|
23
26
|
const transport = new stdio_js.StdioServerTransport();
|
|
24
27
|
await server.connect(transport);
|
|
25
28
|
const metadata = data.getSampleIndexMetadata();
|
package/dist/cli.mjs
CHANGED
|
@@ -11,12 +11,15 @@ import 'express';
|
|
|
11
11
|
import 'zod';
|
|
12
12
|
import './search.mjs';
|
|
13
13
|
import 'fuse.js';
|
|
14
|
+
import 'node:path';
|
|
15
|
+
import 'glob';
|
|
16
|
+
import 'simple-git';
|
|
14
17
|
|
|
15
18
|
const require$1 = createRequire(import.meta.url);
|
|
16
19
|
const { version: PACKAGE_VERSION = "0.0.0" } = require$1("../package.json");
|
|
17
20
|
const ENABLE_LOGGING = process.env.MCP_LOGGING === "true" || process.env.MCP_LOGGING === "1";
|
|
18
21
|
async function main() {
|
|
19
|
-
const server = createKolibriMcpServer();
|
|
22
|
+
const server = await createKolibriMcpServer();
|
|
20
23
|
const transport = new StdioServerTransport();
|
|
21
24
|
await server.connect(transport);
|
|
22
25
|
const metadata = getSampleIndexMetadata();
|
package/dist/mcp.cjs
CHANGED
|
@@ -7,7 +7,10 @@ const node_module = require('node:module');
|
|
|
7
7
|
const zod = require('zod');
|
|
8
8
|
const data = require('./data.cjs');
|
|
9
9
|
const search = require('./search.cjs');
|
|
10
|
-
require('node:fs');
|
|
10
|
+
const node_fs = require('node:fs');
|
|
11
|
+
const node_path = require('node:path');
|
|
12
|
+
const glob = require('glob');
|
|
13
|
+
const simpleGit = require('simple-git');
|
|
11
14
|
require('node:url');
|
|
12
15
|
require('fuse.js');
|
|
13
16
|
|
|
@@ -15,6 +18,297 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
|
|
|
15
18
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
16
19
|
|
|
17
20
|
const express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
21
|
+
const simpleGit__default = /*#__PURE__*/_interopDefaultCompat(simpleGit);
|
|
22
|
+
|
|
23
|
+
const TEMPLATE_REPOS = [
|
|
24
|
+
{
|
|
25
|
+
id: "public-ui-templates",
|
|
26
|
+
name: "KoliBri Generic Templates",
|
|
27
|
+
owner: "public-ui",
|
|
28
|
+
repo: "templates",
|
|
29
|
+
branch: "main",
|
|
30
|
+
description: "Generische KoliBri-Templates und Vorlagen f\xFCr verschiedene Use Cases",
|
|
31
|
+
includePatterns: ["**/*.md", "src/**/*"],
|
|
32
|
+
excludePatterns: ["**/node_modules/**", "**/dist/**", "**/.git/**", "*.lock"],
|
|
33
|
+
type: "generic",
|
|
34
|
+
tags: ["template", "generic", "kolibri", "starter"]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "public-ui-template-react",
|
|
38
|
+
name: "KoliBri React Templates",
|
|
39
|
+
owner: "public-ui",
|
|
40
|
+
repo: "template-react",
|
|
41
|
+
branch: "main",
|
|
42
|
+
description: "React-spezifische Templates mit KoliBri-Integration",
|
|
43
|
+
includePatterns: ["**/*.md", "src/**/*", "*.tsx", "*.ts"],
|
|
44
|
+
excludePatterns: ["**/node_modules/**", "**/dist/**", "**/.git/**", "*.lock"],
|
|
45
|
+
type: "react",
|
|
46
|
+
tags: ["template", "react", "typescript", "kolibri"]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "public-ui-template-theme",
|
|
50
|
+
name: "KoliBri Theme Templates",
|
|
51
|
+
owner: "public-ui",
|
|
52
|
+
repo: "template-theme",
|
|
53
|
+
branch: "main",
|
|
54
|
+
description: "Thema-Vorlagen und Design-System-Konfigurationen",
|
|
55
|
+
includePatterns: ["**/*.md", "src/**/*", "*.css", "*.scss", "*.json"],
|
|
56
|
+
excludePatterns: ["**/node_modules/**", "**/dist/**", "**/.git/**", "*.lock"],
|
|
57
|
+
type: "theme",
|
|
58
|
+
tags: ["template", "theme", "design", "css", "kolibri"]
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const CACHE_DIR$1 = node_path.join(process.cwd(), "data", "templates");
|
|
63
|
+
async function cloneOrUpdateRepo(repoConfig) {
|
|
64
|
+
const repoPath = node_path.join(CACHE_DIR$1, repoConfig.id);
|
|
65
|
+
const git = simpleGit__default();
|
|
66
|
+
try {
|
|
67
|
+
const exists = await node_fs.promises.access(repoPath).then(() => true).catch(() => false);
|
|
68
|
+
if (exists) {
|
|
69
|
+
await git.cwd(repoPath).pull();
|
|
70
|
+
console.log(`\u2705 Updated ${repoConfig.id}`);
|
|
71
|
+
} else {
|
|
72
|
+
await git.clone(`https://github.com/${repoConfig.owner}/${repoConfig.repo}.git`, repoPath, [
|
|
73
|
+
"--branch",
|
|
74
|
+
repoConfig.branch,
|
|
75
|
+
"--single-branch",
|
|
76
|
+
"--depth",
|
|
77
|
+
"1"
|
|
78
|
+
]);
|
|
79
|
+
console.log(`\u2705 Cloned ${repoConfig.id}`);
|
|
80
|
+
}
|
|
81
|
+
return repoPath;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(`\u274C Error cloning/updating ${repoConfig.id}:`, error);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function findFilesInRepo(repoPath, repoConfig) {
|
|
88
|
+
const allFiles = [];
|
|
89
|
+
for (const pattern of repoConfig.includePatterns) {
|
|
90
|
+
const files = await glob.glob(pattern, {
|
|
91
|
+
cwd: repoPath,
|
|
92
|
+
ignore: repoConfig.excludePatterns,
|
|
93
|
+
nodir: true
|
|
94
|
+
});
|
|
95
|
+
allFiles.push(...files);
|
|
96
|
+
}
|
|
97
|
+
return [...new Set(allFiles)];
|
|
98
|
+
}
|
|
99
|
+
function getResourceType(filePath) {
|
|
100
|
+
if (filePath.endsWith(".md") || filePath.endsWith(".markdown")) {
|
|
101
|
+
return "markdown";
|
|
102
|
+
}
|
|
103
|
+
if (filePath.endsWith(".json") || filePath.endsWith(".yaml") || filePath.endsWith(".yml")) {
|
|
104
|
+
return "config";
|
|
105
|
+
}
|
|
106
|
+
return "code";
|
|
107
|
+
}
|
|
108
|
+
function getLanguage(filePath) {
|
|
109
|
+
const extension = filePath.split(".").pop()?.toLowerCase();
|
|
110
|
+
const languageMap = {
|
|
111
|
+
ts: "typescript",
|
|
112
|
+
tsx: "typescript",
|
|
113
|
+
js: "javascript",
|
|
114
|
+
jsx: "javascript",
|
|
115
|
+
css: "css",
|
|
116
|
+
scss: "scss",
|
|
117
|
+
html: "html",
|
|
118
|
+
json: "json",
|
|
119
|
+
yaml: "yaml",
|
|
120
|
+
yml: "yaml"
|
|
121
|
+
};
|
|
122
|
+
return languageMap[extension || ""] || extension || "unknown";
|
|
123
|
+
}
|
|
124
|
+
function extractFrontmatter(content) {
|
|
125
|
+
const frontmatterRegex = /^---[\s\S]*?---/;
|
|
126
|
+
const match = content.match(frontmatterRegex);
|
|
127
|
+
if (!match) return {};
|
|
128
|
+
try {
|
|
129
|
+
const frontmatter = match[0].replace(/^---|---$/g, "").trim();
|
|
130
|
+
const metadata = {};
|
|
131
|
+
frontmatter.split("\n").forEach((line) => {
|
|
132
|
+
const [key, value] = line.split(":").map((s) => s.trim());
|
|
133
|
+
if (key && value) {
|
|
134
|
+
metadata[key] = value.replace(/^['"]|['"]$/g, "");
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return metadata;
|
|
138
|
+
} catch {
|
|
139
|
+
return {};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function indexFile(repoPath, filePath, repoConfig) {
|
|
143
|
+
const absolutePath = node_path.join(repoPath, filePath);
|
|
144
|
+
const content = await node_fs.promises.readFile(absolutePath, "utf-8");
|
|
145
|
+
const stats = await node_fs.promises.stat(absolutePath);
|
|
146
|
+
const resourceType = getResourceType(filePath);
|
|
147
|
+
const frontmatter = resourceType === "markdown" ? extractFrontmatter(content) : {};
|
|
148
|
+
const lines = content.split("\n").length;
|
|
149
|
+
return {
|
|
150
|
+
id: `${repoConfig.id}:${filePath.replace(/[/\\]/g, ":")}`,
|
|
151
|
+
repoId: repoConfig.id,
|
|
152
|
+
path: filePath,
|
|
153
|
+
type: resourceType,
|
|
154
|
+
content,
|
|
155
|
+
metadata: {
|
|
156
|
+
name: frontmatter.title || filePath.split("/").pop() || "",
|
|
157
|
+
description: frontmatter.description || void 0,
|
|
158
|
+
tags: [...repoConfig.tags || [], ...frontmatter.tags ?? []].filter((t) => t),
|
|
159
|
+
templateType: repoConfig.type,
|
|
160
|
+
language: resourceType === "code" ? getLanguage(filePath) : void 0
|
|
161
|
+
},
|
|
162
|
+
stats: {
|
|
163
|
+
size: stats.size,
|
|
164
|
+
lines,
|
|
165
|
+
lastModified: stats.mtime.toISOString()
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
async function indexTemplateRepo(repoConfig) {
|
|
170
|
+
console.log(`\u{1F4C1} Indexing ${repoConfig.id}...`);
|
|
171
|
+
const repoPath = await cloneOrUpdateRepo(repoConfig);
|
|
172
|
+
const files = await findFilesInRepo(repoPath, repoConfig);
|
|
173
|
+
console.log(` Found ${files.length} files to index`);
|
|
174
|
+
const resources = [];
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
try {
|
|
177
|
+
const resource = await indexFile(repoPath, file, repoConfig);
|
|
178
|
+
resources.push(resource);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.warn(` \u26A0\uFE0F Could not index ${file}:`, error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
console.log(`\u2705 Indexed ${resources.length} resources from ${repoConfig.id}`);
|
|
184
|
+
return resources;
|
|
185
|
+
}
|
|
186
|
+
async function indexAllTemplateRepos() {
|
|
187
|
+
const allResources = [];
|
|
188
|
+
for (const repoConfig of TEMPLATE_REPOS) {
|
|
189
|
+
try {
|
|
190
|
+
const resources = await indexTemplateRepo(repoConfig);
|
|
191
|
+
allResources.push(...resources);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error(`\u274C Failed to index ${repoConfig.id}:`, error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return allResources;
|
|
197
|
+
}
|
|
198
|
+
async function updateTemplateIndex() {
|
|
199
|
+
console.log("\u{1F504} Updating template index...");
|
|
200
|
+
const resources = await indexAllTemplateRepos();
|
|
201
|
+
const indexPath = node_path.join(CACHE_DIR$1, "template-index.json");
|
|
202
|
+
await node_fs.promises.mkdir(CACHE_DIR$1, { recursive: true });
|
|
203
|
+
await node_fs.promises.writeFile(indexPath, JSON.stringify(resources, null, 2));
|
|
204
|
+
console.log(`\u2705 Template index updated with ${resources.length} resources`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function extractCodeBlocksFromMarkdown(markdown) {
|
|
208
|
+
const codeBlockRegex = /```(\w*)\s*([\s\S]*?)```/g;
|
|
209
|
+
const blocks = [];
|
|
210
|
+
let match;
|
|
211
|
+
while ((match = codeBlockRegex.exec(markdown)) !== null) {
|
|
212
|
+
const language = match[1] || "";
|
|
213
|
+
const code = match[2].trim();
|
|
214
|
+
const titleMatch = code.match(/^\/\/\s*title:\s*(.+)$/m);
|
|
215
|
+
const title = titleMatch ? titleMatch[1].trim() : void 0;
|
|
216
|
+
blocks.push({ language, code, title });
|
|
217
|
+
}
|
|
218
|
+
return blocks;
|
|
219
|
+
}
|
|
220
|
+
function calculateSimilarityScore(resource, query) {
|
|
221
|
+
let score = 0;
|
|
222
|
+
if (resource.metadata.name.toLowerCase().includes(query.toLowerCase())) {
|
|
223
|
+
score += 100;
|
|
224
|
+
}
|
|
225
|
+
if (resource.metadata.description?.toLowerCase().includes(query.toLowerCase())) {
|
|
226
|
+
score += 50;
|
|
227
|
+
}
|
|
228
|
+
const queryLower = query.toLowerCase();
|
|
229
|
+
for (const tag of resource.metadata.tags) {
|
|
230
|
+
if (tag.toLowerCase().includes(queryLower)) {
|
|
231
|
+
score += 30;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const contentLower = resource.content.toLowerCase();
|
|
235
|
+
const firstMatchIndex = contentLower.indexOf(queryLower);
|
|
236
|
+
if (firstMatchIndex !== -1) {
|
|
237
|
+
const positionScore = Math.max(0, 100 - firstMatchIndex / 100);
|
|
238
|
+
score += positionScore;
|
|
239
|
+
}
|
|
240
|
+
return score;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const CACHE_DIR = node_path.join(process.cwd(), "data", "templates");
|
|
244
|
+
let templateIndex = [];
|
|
245
|
+
async function loadTemplateIndex() {
|
|
246
|
+
try {
|
|
247
|
+
const indexPath = node_path.join(CACHE_DIR, "template-index.json");
|
|
248
|
+
const content = await node_fs.promises.readFile(indexPath, "utf-8");
|
|
249
|
+
const parsed = JSON.parse(content);
|
|
250
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
251
|
+
} catch {
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async function initializeTemplateIndex() {
|
|
256
|
+
console.log("\u{1F4DA} Initializing template index...");
|
|
257
|
+
try {
|
|
258
|
+
templateIndex = await loadTemplateIndex();
|
|
259
|
+
if (templateIndex.length === 0) {
|
|
260
|
+
await updateTemplateIndex();
|
|
261
|
+
templateIndex = await loadTemplateIndex();
|
|
262
|
+
}
|
|
263
|
+
console.log(`\u2705 Template index loaded with ${templateIndex.length} resources`);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error("\u274C Failed to initialize template index:", error);
|
|
266
|
+
templateIndex = [];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function searchTemplates(query, options = {}) {
|
|
270
|
+
const { type, repoId, tags, templateType, limit = 20 } = options;
|
|
271
|
+
let results = templateIndex.filter((resource) => {
|
|
272
|
+
if (repoId && resource.repoId !== repoId) return false;
|
|
273
|
+
if (type && resource.type !== type) return false;
|
|
274
|
+
if (templateType && resource.metadata.templateType !== templateType) return false;
|
|
275
|
+
if (tags && tags.length > 0) {
|
|
276
|
+
const hasAllTags = tags.every((tag) => resource.metadata.tags.includes(tag));
|
|
277
|
+
if (!hasAllTags) return false;
|
|
278
|
+
}
|
|
279
|
+
return true;
|
|
280
|
+
});
|
|
281
|
+
results = results.map((resource) => ({
|
|
282
|
+
...resource,
|
|
283
|
+
score: calculateSimilarityScore(resource, query)
|
|
284
|
+
})).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
285
|
+
return results;
|
|
286
|
+
}
|
|
287
|
+
function getTemplateResource(id) {
|
|
288
|
+
return templateIndex.find((resource) => resource.id === id);
|
|
289
|
+
}
|
|
290
|
+
function getTemplateCodeBlocks(resource) {
|
|
291
|
+
if (resource.type !== "markdown") {
|
|
292
|
+
return [{ language: resource.metadata.language || "unknown", code: resource.content }];
|
|
293
|
+
}
|
|
294
|
+
return extractCodeBlocksFromMarkdown(resource.content);
|
|
295
|
+
}
|
|
296
|
+
function getTemplateTypes() {
|
|
297
|
+
const types = /* @__PURE__ */ new Set();
|
|
298
|
+
for (const repo of TEMPLATE_REPOS) {
|
|
299
|
+
types.add(repo.type);
|
|
300
|
+
}
|
|
301
|
+
return Array.from(types);
|
|
302
|
+
}
|
|
303
|
+
function getAllTemplateTags() {
|
|
304
|
+
const tags = /* @__PURE__ */ new Set();
|
|
305
|
+
for (const resource of templateIndex) {
|
|
306
|
+
for (const tag of resource.metadata.tags) {
|
|
307
|
+
tags.add(tag);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return Array.from(tags).sort();
|
|
311
|
+
}
|
|
18
312
|
|
|
19
313
|
const KIND_OPTIONS = ["doc", "sample", "scenario", "spec"];
|
|
20
314
|
function isValidKind(value) {
|
|
@@ -45,14 +339,19 @@ function log(type, message, data) {
|
|
|
45
339
|
console.error(`${prefix} ${message}`);
|
|
46
340
|
}
|
|
47
341
|
}
|
|
48
|
-
function createKolibriMcpServer() {
|
|
342
|
+
async function createKolibriMcpServer() {
|
|
49
343
|
const server = new mcp_js.McpServer({
|
|
50
344
|
name: PACKAGE_NAME,
|
|
51
345
|
version: PACKAGE_VERSION
|
|
52
346
|
});
|
|
53
347
|
return configureServer(server);
|
|
54
348
|
}
|
|
55
|
-
function configureServer(server) {
|
|
349
|
+
async function configureServer(server) {
|
|
350
|
+
try {
|
|
351
|
+
await initializeTemplateIndex();
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error("Failed to initialize template index:", error);
|
|
354
|
+
}
|
|
56
355
|
server.registerTool(
|
|
57
356
|
"search",
|
|
58
357
|
{
|
|
@@ -272,39 +571,212 @@ Use the 'fetch' tool to retrieve full code samples for specific components.
|
|
|
272
571
|
};
|
|
273
572
|
}
|
|
274
573
|
);
|
|
574
|
+
server.registerTool(
|
|
575
|
+
"search_templates",
|
|
576
|
+
{
|
|
577
|
+
title: "Search KoliBri Templates",
|
|
578
|
+
description: "Searches through KoliBri template repositories (generic, react, theme) for code examples and documentation. Returns matching templates with metadata, previews, and code blocks. Use `type` to filter by resource type (markdown, code, config). Use `templateType` to filter by template type (generic, react, theme). Use `repoId` to filter by specific repository. Use `tags` to filter by tags. Use `limit` to control max results (default: 20).",
|
|
579
|
+
inputSchema: {
|
|
580
|
+
query: zod.z.string().describe('Search query (e.g., "button", "form", "dark theme").'),
|
|
581
|
+
type: zod.z.enum(["all", "markdown", "code", "config"]).optional().default("all").describe("Filter by resource type."),
|
|
582
|
+
templateType: zod.z.string().optional().describe("Filter by template type (generic, react, theme)."),
|
|
583
|
+
repoId: zod.z.string().optional().describe("Filter by repository ID."),
|
|
584
|
+
tags: zod.z.array(zod.z.string()).optional().describe("Filter by tags."),
|
|
585
|
+
limit: zod.z.number().int().min(1).max(50).optional().default(20).describe("Maximum number of results.")
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
({ query, type, templateType, repoId, tags, limit }) => {
|
|
589
|
+
log("tool", "search_templates called", { query, type, templateType, repoId, limit });
|
|
590
|
+
const results = searchTemplates(query, {
|
|
591
|
+
type: type === "all" ? void 0 : type,
|
|
592
|
+
templateType,
|
|
593
|
+
repoId,
|
|
594
|
+
tags,
|
|
595
|
+
limit
|
|
596
|
+
});
|
|
597
|
+
log("tool", "search_templates completed", { resultCount: results.length });
|
|
598
|
+
return {
|
|
599
|
+
content: [
|
|
600
|
+
{
|
|
601
|
+
type: "text",
|
|
602
|
+
text: results.length === 0 ? `No templates found for "${query}"` : `Found ${results.length} template(s) for "${query}":
|
|
603
|
+
|
|
604
|
+
` + results.map((result, index) => {
|
|
605
|
+
const matchScore = (result.score ?? 0).toFixed(1);
|
|
606
|
+
return `${index + 1}. **${result.metadata.name}** (${result.repoId})
|
|
607
|
+
Type: ${result.type} | Template: ${result.metadata.templateType}
|
|
608
|
+
Tags: ${result.metadata.tags.join(", ")}
|
|
609
|
+
Score: ${matchScore}
|
|
610
|
+
Preview: ${result.content.substring(0, 100)}...`;
|
|
611
|
+
}).join("\n\n")
|
|
612
|
+
}
|
|
613
|
+
],
|
|
614
|
+
structuredContent: {
|
|
615
|
+
query,
|
|
616
|
+
total: results.length,
|
|
617
|
+
results: results.map((result) => ({
|
|
618
|
+
id: result.id,
|
|
619
|
+
name: result.metadata.name,
|
|
620
|
+
description: result.metadata.description,
|
|
621
|
+
repoId: result.repoId,
|
|
622
|
+
path: result.path,
|
|
623
|
+
type: result.type,
|
|
624
|
+
templateType: result.metadata.templateType,
|
|
625
|
+
tags: result.metadata.tags,
|
|
626
|
+
score: result.score,
|
|
627
|
+
stats: result.stats
|
|
628
|
+
}))
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
);
|
|
633
|
+
server.registerTool(
|
|
634
|
+
"fetch_template",
|
|
635
|
+
{
|
|
636
|
+
title: "Fetch KoliBri Template",
|
|
637
|
+
description: "Fetches a specific template resource by ID. Returns the full content with metadata and extracted code blocks. Use `search_templates` first to find valid IDs.",
|
|
638
|
+
inputSchema: {
|
|
639
|
+
id: zod.z.string().describe('Template resource ID (e.g., "public-ui-templates:src/button/button.stories.md").'),
|
|
640
|
+
includeCodeBlocks: zod.z.boolean().optional().default(true).describe("Whether to extract code blocks from markdown.")
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
({ id, includeCodeBlocks }) => {
|
|
644
|
+
log("tool", "fetch_template called", { id, includeCodeBlocks });
|
|
645
|
+
const resource = getTemplateResource(id);
|
|
646
|
+
if (!resource) {
|
|
647
|
+
log("error", "fetch_template failed: resource not found", { id });
|
|
648
|
+
throw new Error(`Template not found: ${id}. Use \`search_templates\` to find valid IDs.`);
|
|
649
|
+
}
|
|
650
|
+
const codeBlocks = includeCodeBlocks && resource.type === "markdown" ? getTemplateCodeBlocks(resource) : [];
|
|
651
|
+
log("tool", "fetch_template completed", {
|
|
652
|
+
id,
|
|
653
|
+
contentLength: resource.content.length,
|
|
654
|
+
codeBlockCount: codeBlocks.length
|
|
655
|
+
});
|
|
656
|
+
return {
|
|
657
|
+
content: [
|
|
658
|
+
{
|
|
659
|
+
type: "text",
|
|
660
|
+
text: `# ${resource.metadata.name}
|
|
661
|
+
|
|
662
|
+
**Repository:** ${resource.repoId}
|
|
663
|
+
|
|
664
|
+
**Path:** ${resource.path}
|
|
665
|
+
|
|
666
|
+
**Type:** ${resource.type}
|
|
667
|
+
|
|
668
|
+
**Template Type:** ${resource.metadata.templateType}
|
|
669
|
+
|
|
670
|
+
**Tags:** ${resource.metadata.tags.join(", ")}
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
` + resource.content
|
|
675
|
+
}
|
|
676
|
+
],
|
|
677
|
+
structuredContent: {
|
|
678
|
+
id: resource.id,
|
|
679
|
+
name: resource.metadata.name,
|
|
680
|
+
description: resource.metadata.description,
|
|
681
|
+
repoId: resource.repoId,
|
|
682
|
+
path: resource.path,
|
|
683
|
+
type: resource.type,
|
|
684
|
+
templateType: resource.metadata.templateType,
|
|
685
|
+
tags: resource.metadata.tags,
|
|
686
|
+
language: resource.metadata.language,
|
|
687
|
+
stats: resource.stats,
|
|
688
|
+
codeBlocks: codeBlocks.map((block) => ({
|
|
689
|
+
language: block.language,
|
|
690
|
+
title: block.title,
|
|
691
|
+
codeLength: block.code.length
|
|
692
|
+
}))
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
);
|
|
697
|
+
server.registerTool(
|
|
698
|
+
"list_template_tags",
|
|
699
|
+
{
|
|
700
|
+
title: "List Template Tags",
|
|
701
|
+
description: "Returns all available tags for filtering templates.",
|
|
702
|
+
inputSchema: {}
|
|
703
|
+
},
|
|
704
|
+
() => {
|
|
705
|
+
const tags = getAllTemplateTags();
|
|
706
|
+
return {
|
|
707
|
+
content: [
|
|
708
|
+
{
|
|
709
|
+
type: "text",
|
|
710
|
+
text: `Available template tags (${tags.length}):
|
|
711
|
+
|
|
712
|
+
` + tags.map((tag) => `- ${tag}`).join("\n")
|
|
713
|
+
}
|
|
714
|
+
],
|
|
715
|
+
structuredContent: {
|
|
716
|
+
tags
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
);
|
|
721
|
+
server.registerTool(
|
|
722
|
+
"list_template_types",
|
|
723
|
+
{
|
|
724
|
+
title: "List Template Types",
|
|
725
|
+
description: "Returns all available template types (generic, react, theme).",
|
|
726
|
+
inputSchema: {}
|
|
727
|
+
},
|
|
728
|
+
() => {
|
|
729
|
+
const types = getTemplateTypes();
|
|
730
|
+
return {
|
|
731
|
+
content: [
|
|
732
|
+
{
|
|
733
|
+
type: "text",
|
|
734
|
+
text: `Available template types:
|
|
735
|
+
|
|
736
|
+
` + types.map((type) => `- ${type}`).join("\n")
|
|
737
|
+
}
|
|
738
|
+
],
|
|
739
|
+
structuredContent: {
|
|
740
|
+
types
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
);
|
|
275
745
|
return server;
|
|
276
746
|
}
|
|
277
747
|
if ((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('mcp.cjs', document.baseURI).href)) === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/mcp.ts") || process.argv[1]?.endsWith("/mcp.cjs") || process.argv[1]?.endsWith("/mcp.mjs")) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
748
|
+
void (async () => {
|
|
749
|
+
const server = await createKolibriMcpServer();
|
|
750
|
+
const app = express__default();
|
|
751
|
+
app.use(express__default.json());
|
|
752
|
+
app.post("/mcp", async (req, res) => {
|
|
753
|
+
const transport = new streamableHttp_js.StreamableHTTPServerTransport({
|
|
754
|
+
sessionIdGenerator: void 0,
|
|
755
|
+
enableJsonResponse: true
|
|
756
|
+
});
|
|
757
|
+
res.on("close", () => {
|
|
758
|
+
void transport.close();
|
|
759
|
+
});
|
|
760
|
+
await server.connect(transport);
|
|
761
|
+
await transport.handleRequest(req, res, req.body);
|
|
285
762
|
});
|
|
286
|
-
|
|
287
|
-
|
|
763
|
+
const port = parseInt(process.env.PORT || "3000");
|
|
764
|
+
void app.listen(port, () => {
|
|
765
|
+
console.log(`KoliBri MCP Server v${PACKAGE_VERSION} running on http://localhost:${port}/mcp`);
|
|
766
|
+
const metadata = data.getSampleIndexMetadata();
|
|
767
|
+
console.log(
|
|
768
|
+
`Loaded ${metadata.counts.total} entries (${metadata.counts.totalDocs} docs, ${metadata.counts.totalSamples} samples, ${metadata.counts.totalScenarios ?? 0} scenarios)`
|
|
769
|
+
);
|
|
770
|
+
if (ENABLE_LOGGING) {
|
|
771
|
+
console.log("\u{1F50D} Logging is ENABLED (MCP_LOGGING=true)");
|
|
772
|
+
} else {
|
|
773
|
+
console.log("\u{1F4A1} Logging is disabled. Set MCP_LOGGING=true to enable request logging");
|
|
774
|
+
}
|
|
775
|
+
}).on("error", (error) => {
|
|
776
|
+
console.error("Server error:", error);
|
|
777
|
+
process.exit(1);
|
|
288
778
|
});
|
|
289
|
-
|
|
290
|
-
await transport.handleRequest(req, res, req.body);
|
|
291
|
-
});
|
|
292
|
-
const port = parseInt(process.env.PORT || "3000");
|
|
293
|
-
void app.listen(port, () => {
|
|
294
|
-
console.log(`KoliBri MCP Server v${PACKAGE_VERSION} running on http://localhost:${port}/mcp`);
|
|
295
|
-
const metadata = data.getSampleIndexMetadata();
|
|
296
|
-
console.log(
|
|
297
|
-
`Loaded ${metadata.counts.total} entries (${metadata.counts.totalDocs} docs, ${metadata.counts.totalSamples} samples, ${metadata.counts.totalScenarios ?? 0} scenarios)`
|
|
298
|
-
);
|
|
299
|
-
if (ENABLE_LOGGING) {
|
|
300
|
-
console.log("\u{1F50D} Logging is ENABLED (MCP_LOGGING=true)");
|
|
301
|
-
} else {
|
|
302
|
-
console.log("\u{1F4A1} Logging is disabled. Set MCP_LOGGING=true to enable request logging");
|
|
303
|
-
}
|
|
304
|
-
}).on("error", (error) => {
|
|
305
|
-
console.error("Server error:", error);
|
|
306
|
-
process.exit(1);
|
|
307
|
-
});
|
|
779
|
+
})();
|
|
308
780
|
}
|
|
309
781
|
|
|
310
782
|
exports.createKolibriMcpServer = createKolibriMcpServer;
|
package/dist/mcp.d.cts
CHANGED
|
@@ -4,6 +4,6 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
4
4
|
* Create a configured KoliBri MCP server instance.
|
|
5
5
|
* Can be used with both stdio and HTTP transports.
|
|
6
6
|
*/
|
|
7
|
-
declare function createKolibriMcpServer(): McpServer
|
|
7
|
+
declare function createKolibriMcpServer(): Promise<McpServer>;
|
|
8
8
|
|
|
9
9
|
export { createKolibriMcpServer };
|
package/dist/mcp.d.mts
CHANGED
|
@@ -4,6 +4,6 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
4
4
|
* Create a configured KoliBri MCP server instance.
|
|
5
5
|
* Can be used with both stdio and HTTP transports.
|
|
6
6
|
*/
|
|
7
|
-
declare function createKolibriMcpServer(): McpServer
|
|
7
|
+
declare function createKolibriMcpServer(): Promise<McpServer>;
|
|
8
8
|
|
|
9
9
|
export { createKolibriMcpServer };
|
package/dist/mcp.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
4
4
|
* Create a configured KoliBri MCP server instance.
|
|
5
5
|
* Can be used with both stdio and HTTP transports.
|
|
6
6
|
*/
|
|
7
|
-
declare function createKolibriMcpServer(): McpServer
|
|
7
|
+
declare function createKolibriMcpServer(): Promise<McpServer>;
|
|
8
8
|
|
|
9
9
|
export { createKolibriMcpServer };
|