@public-ui/mcp 4.0.0-alpha.2 → 4.0.0-alpha.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/README.md +339 -139
- package/dist/cli.cjs +37 -42
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +36 -42
- package/dist/data.cjs +88 -0
- package/dist/data.d.cts +34 -0
- package/dist/data.d.mts +34 -0
- package/dist/data.d.ts +34 -0
- package/dist/data.mjs +83 -0
- package/dist/mcp.cjs +298 -0
- package/dist/mcp.d.cts +9 -0
- package/dist/mcp.d.mts +9 -0
- package/dist/mcp.d.ts +9 -0
- package/dist/mcp.mjs +291 -0
- package/dist/search.cjs +52 -0
- package/dist/search.d.cts +16 -0
- package/dist/search.d.mts +16 -0
- package/dist/search.d.ts +16 -0
- package/dist/search.mjs +46 -0
- package/package.json +48 -6
- package/shared/.gitkeep +1 -0
- package/shared/sample-index.json +1860 -0
- package/dist/api-handler.cjs +0 -269
- package/dist/api-handler.mjs +0 -265
- package/dist/chunks/sample-index-runtime.cjs +0 -327
- package/dist/chunks/sample-index-runtime.mjs +0 -320
- package/dist/index.cjs +0 -71
- package/dist/index.mjs +0 -66
- package/dist/sample-index.cjs +0 -117
- package/dist/sample-index.mjs +0 -109
- package/dist/samples.json +0 -1428
- package/dist/samples.mjs +0 -1430
package/dist/cli.mjs
CHANGED
|
@@ -1,46 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import '
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import '
|
|
6
|
-
import '
|
|
7
|
-
import 'node:fs/promises';
|
|
8
|
-
import 'node:path';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { getSampleIndexMetadata } from './data.mjs';
|
|
5
|
+
import { createKolibriMcpServer } from './mcp.mjs';
|
|
6
|
+
import 'node:fs';
|
|
9
7
|
import 'node:url';
|
|
8
|
+
import '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
10
|
+
import 'express';
|
|
11
|
+
import 'zod';
|
|
12
|
+
import './search.mjs';
|
|
13
|
+
import 'fuse.js';
|
|
10
14
|
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const { version: PACKAGE_VERSION = "0.0.0" } = require("../package.json");
|
|
17
|
+
const ENABLE_LOGGING = process.env.MCP_LOGGING === "true" || process.env.MCP_LOGGING === "1";
|
|
18
|
+
async function main() {
|
|
19
|
+
const server = createKolibriMcpServer();
|
|
20
|
+
const transport = new StdioServerTransport();
|
|
21
|
+
await server.connect(transport);
|
|
22
|
+
const metadata = getSampleIndexMetadata();
|
|
23
|
+
console.error(`
|
|
24
|
+
\u{1F680} KoliBri MCP Server v${PACKAGE_VERSION}`);
|
|
25
|
+
console.error("\u2501".repeat(50));
|
|
26
|
+
console.error(`\u{1F4CA} Loaded ${metadata.counts.total} entries:`);
|
|
27
|
+
console.error(` \u2022 ${metadata.counts.totalSamples} samples`);
|
|
28
|
+
console.error(` \u2022 ${metadata.counts.totalSpecs ?? 0} specs`);
|
|
29
|
+
console.error(` \u2022 ${metadata.counts.totalScenarios ?? 0} scenarios`);
|
|
30
|
+
console.error(` \u2022 ${metadata.counts.totalDocs} docs`);
|
|
31
|
+
console.error("\u2501".repeat(50));
|
|
32
|
+
if (ENABLE_LOGGING) {
|
|
33
|
+
console.error("\u{1F50D} Logging: ENABLED (MCP_LOGGING=true)");
|
|
34
|
+
} else {
|
|
35
|
+
console.error("\u{1F4A1} Logging: disabled (set MCP_LOGGING=true to enable)");
|
|
20
36
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
console.log(`\u{1F4CA} API endpoints:`);
|
|
26
|
-
console.log(` GET /mcp/health - Server status`);
|
|
27
|
-
console.log(` GET /mcp/samples - List all samples`);
|
|
28
|
-
console.log(` GET /mcp/sample - Get specific sample`);
|
|
29
|
-
console.log(` GET /mcp/docs - List docs`);
|
|
30
|
-
console.log(` GET /mcp/doc - Get specific doc`);
|
|
31
|
-
console.log(`\u{1F4DA} Documentation: https://www.npmjs.com/package/@public-ui/mcp`);
|
|
32
|
-
});
|
|
33
|
-
process.on("SIGTERM", () => {
|
|
34
|
-
console.log("\u{1F6D1} Received SIGTERM, shutting down gracefully...");
|
|
35
|
-
server.close(() => {
|
|
36
|
-
console.log("\u2705 Server closed");
|
|
37
|
-
process.exit(0);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
process.on("SIGINT", () => {
|
|
41
|
-
console.log("\u{1F6D1} Received SIGINT, shutting down gracefully...");
|
|
42
|
-
server.close(() => {
|
|
43
|
-
console.log("\u2705 Server closed");
|
|
44
|
-
process.exit(0);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
37
|
+
console.error("\u{1F50C} Transport: stdio");
|
|
38
|
+
console.error("\u2705 Ready for MCP requests\n");
|
|
39
|
+
}
|
|
40
|
+
void main();
|
package/dist/data.cjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const node_fs = require('node:fs');
|
|
4
|
+
const node_url = require('node:url');
|
|
5
|
+
|
|
6
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
7
|
+
let cachedData;
|
|
8
|
+
function calculateCounts(entries) {
|
|
9
|
+
const byKind = {};
|
|
10
|
+
for (const entry of entries) {
|
|
11
|
+
const key = entry.kind;
|
|
12
|
+
byKind[key] = (byKind[key] ?? 0) + 1;
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
total: entries.length,
|
|
16
|
+
totalDocs: byKind.doc ?? 0,
|
|
17
|
+
totalSamples: byKind.sample ?? 0,
|
|
18
|
+
totalScenarios: byKind.scenario ?? 0,
|
|
19
|
+
totalSpecs: byKind.spec ?? 0,
|
|
20
|
+
byKind
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function normalizeEntry(entry) {
|
|
24
|
+
const normalizedKind = entry.kind === "doc" ? "doc" : entry.kind === "scenario" ? "scenario" : entry.kind === "spec" ? "spec" : "sample";
|
|
25
|
+
const tags = Array.isArray(entry.tags) ? entry.tags.map((tag) => String(tag)).filter((tag) => tag.trim().length > 0) : void 0;
|
|
26
|
+
return {
|
|
27
|
+
...entry,
|
|
28
|
+
kind: normalizedKind,
|
|
29
|
+
tags
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function normalizeMetadata(metadata, entries) {
|
|
33
|
+
const counts = calculateCounts(entries);
|
|
34
|
+
const repo = metadata?.repo ?? { commit: null, branch: null, repoUrl: null };
|
|
35
|
+
return {
|
|
36
|
+
generatedAt: metadata?.generatedAt ?? null,
|
|
37
|
+
buildMode: metadata?.buildMode ?? "unknown",
|
|
38
|
+
counts: {
|
|
39
|
+
total: metadata?.counts?.total ?? counts.total,
|
|
40
|
+
totalDocs: metadata?.counts?.totalDocs ?? counts.totalDocs,
|
|
41
|
+
totalSamples: metadata?.counts?.totalSamples ?? counts.totalSamples,
|
|
42
|
+
totalScenarios: metadata?.counts?.totalScenarios ?? counts.totalScenarios,
|
|
43
|
+
totalSpecs: metadata?.counts?.totalSpecs ?? counts.totalSpecs,
|
|
44
|
+
byKind: metadata?.counts?.byKind instanceof Map ? Object.fromEntries(metadata.counts.byKind.entries()) : metadata?.counts?.byKind ? Object.fromEntries(Object.entries(metadata.counts.byKind).map(([key, value]) => [key, Number(value)])) : counts.byKind
|
|
45
|
+
},
|
|
46
|
+
repo: {
|
|
47
|
+
commit: repo.commit ?? null,
|
|
48
|
+
branch: repo.branch ?? null,
|
|
49
|
+
repoUrl: repo.repoUrl ?? null
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function loadSampleData() {
|
|
54
|
+
if (cachedData) {
|
|
55
|
+
return cachedData;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const sharedIndexUrl = new URL("../shared/sample-index.json", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('data.cjs', document.baseURI).href)));
|
|
59
|
+
const filePath = node_url.fileURLToPath(sharedIndexUrl);
|
|
60
|
+
const raw = node_fs.readFileSync(filePath, "utf8");
|
|
61
|
+
const parsed = JSON.parse(raw);
|
|
62
|
+
const entries = Array.isArray(parsed.entries) ? parsed.entries.map(normalizeEntry) : [];
|
|
63
|
+
if (entries.length === 0) {
|
|
64
|
+
throw new Error("Sample index does not contain any entries.");
|
|
65
|
+
}
|
|
66
|
+
const metadata = normalizeMetadata(parsed.metadata, entries);
|
|
67
|
+
cachedData = { entries, metadata };
|
|
68
|
+
return cachedData;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Failed to load sample index from shared/sample-index.json. Please run 'pnpm generate-index' to create the index file. Error: ${message}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function getAllEntries() {
|
|
77
|
+
return loadSampleData().entries;
|
|
78
|
+
}
|
|
79
|
+
function getEntryById(id) {
|
|
80
|
+
return getAllEntries().find((entry) => entry.id === id);
|
|
81
|
+
}
|
|
82
|
+
function getSampleIndexMetadata() {
|
|
83
|
+
return loadSampleData().metadata;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
exports.getAllEntries = getAllEntries;
|
|
87
|
+
exports.getEntryById = getEntryById;
|
|
88
|
+
exports.getSampleIndexMetadata = getSampleIndexMetadata;
|
package/dist/data.d.cts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface SampleEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: 'doc' | 'sample' | 'scenario' | 'spec';
|
|
4
|
+
name: string;
|
|
5
|
+
group?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
code?: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
}
|
|
11
|
+
interface SampleIndexCounts {
|
|
12
|
+
total: number;
|
|
13
|
+
totalDocs: number;
|
|
14
|
+
totalSamples: number;
|
|
15
|
+
totalScenarios: number;
|
|
16
|
+
totalSpecs: number;
|
|
17
|
+
byKind: Record<string, number>;
|
|
18
|
+
}
|
|
19
|
+
interface SampleIndexMetadata {
|
|
20
|
+
generatedAt: string | null;
|
|
21
|
+
buildMode: string;
|
|
22
|
+
counts: SampleIndexCounts;
|
|
23
|
+
repo: {
|
|
24
|
+
commit: string | null;
|
|
25
|
+
branch: string | null;
|
|
26
|
+
repoUrl: string | null;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
declare function getAllEntries(): SampleEntry[];
|
|
30
|
+
declare function getEntryById(id: string): SampleEntry | undefined;
|
|
31
|
+
declare function getSampleIndexMetadata(): SampleIndexMetadata;
|
|
32
|
+
|
|
33
|
+
export { getAllEntries, getEntryById, getSampleIndexMetadata };
|
|
34
|
+
export type { SampleEntry };
|
package/dist/data.d.mts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface SampleEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: 'doc' | 'sample' | 'scenario' | 'spec';
|
|
4
|
+
name: string;
|
|
5
|
+
group?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
code?: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
}
|
|
11
|
+
interface SampleIndexCounts {
|
|
12
|
+
total: number;
|
|
13
|
+
totalDocs: number;
|
|
14
|
+
totalSamples: number;
|
|
15
|
+
totalScenarios: number;
|
|
16
|
+
totalSpecs: number;
|
|
17
|
+
byKind: Record<string, number>;
|
|
18
|
+
}
|
|
19
|
+
interface SampleIndexMetadata {
|
|
20
|
+
generatedAt: string | null;
|
|
21
|
+
buildMode: string;
|
|
22
|
+
counts: SampleIndexCounts;
|
|
23
|
+
repo: {
|
|
24
|
+
commit: string | null;
|
|
25
|
+
branch: string | null;
|
|
26
|
+
repoUrl: string | null;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
declare function getAllEntries(): SampleEntry[];
|
|
30
|
+
declare function getEntryById(id: string): SampleEntry | undefined;
|
|
31
|
+
declare function getSampleIndexMetadata(): SampleIndexMetadata;
|
|
32
|
+
|
|
33
|
+
export { getAllEntries, getEntryById, getSampleIndexMetadata };
|
|
34
|
+
export type { SampleEntry };
|
package/dist/data.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface SampleEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: 'doc' | 'sample' | 'scenario' | 'spec';
|
|
4
|
+
name: string;
|
|
5
|
+
group?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
code?: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
}
|
|
11
|
+
interface SampleIndexCounts {
|
|
12
|
+
total: number;
|
|
13
|
+
totalDocs: number;
|
|
14
|
+
totalSamples: number;
|
|
15
|
+
totalScenarios: number;
|
|
16
|
+
totalSpecs: number;
|
|
17
|
+
byKind: Record<string, number>;
|
|
18
|
+
}
|
|
19
|
+
interface SampleIndexMetadata {
|
|
20
|
+
generatedAt: string | null;
|
|
21
|
+
buildMode: string;
|
|
22
|
+
counts: SampleIndexCounts;
|
|
23
|
+
repo: {
|
|
24
|
+
commit: string | null;
|
|
25
|
+
branch: string | null;
|
|
26
|
+
repoUrl: string | null;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
declare function getAllEntries(): SampleEntry[];
|
|
30
|
+
declare function getEntryById(id: string): SampleEntry | undefined;
|
|
31
|
+
declare function getSampleIndexMetadata(): SampleIndexMetadata;
|
|
32
|
+
|
|
33
|
+
export { getAllEntries, getEntryById, getSampleIndexMetadata };
|
|
34
|
+
export type { SampleEntry };
|
package/dist/data.mjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
let cachedData;
|
|
5
|
+
function calculateCounts(entries) {
|
|
6
|
+
const byKind = {};
|
|
7
|
+
for (const entry of entries) {
|
|
8
|
+
const key = entry.kind;
|
|
9
|
+
byKind[key] = (byKind[key] ?? 0) + 1;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
total: entries.length,
|
|
13
|
+
totalDocs: byKind.doc ?? 0,
|
|
14
|
+
totalSamples: byKind.sample ?? 0,
|
|
15
|
+
totalScenarios: byKind.scenario ?? 0,
|
|
16
|
+
totalSpecs: byKind.spec ?? 0,
|
|
17
|
+
byKind
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function normalizeEntry(entry) {
|
|
21
|
+
const normalizedKind = entry.kind === "doc" ? "doc" : entry.kind === "scenario" ? "scenario" : entry.kind === "spec" ? "spec" : "sample";
|
|
22
|
+
const tags = Array.isArray(entry.tags) ? entry.tags.map((tag) => String(tag)).filter((tag) => tag.trim().length > 0) : void 0;
|
|
23
|
+
return {
|
|
24
|
+
...entry,
|
|
25
|
+
kind: normalizedKind,
|
|
26
|
+
tags
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function normalizeMetadata(metadata, entries) {
|
|
30
|
+
const counts = calculateCounts(entries);
|
|
31
|
+
const repo = metadata?.repo ?? { commit: null, branch: null, repoUrl: null };
|
|
32
|
+
return {
|
|
33
|
+
generatedAt: metadata?.generatedAt ?? null,
|
|
34
|
+
buildMode: metadata?.buildMode ?? "unknown",
|
|
35
|
+
counts: {
|
|
36
|
+
total: metadata?.counts?.total ?? counts.total,
|
|
37
|
+
totalDocs: metadata?.counts?.totalDocs ?? counts.totalDocs,
|
|
38
|
+
totalSamples: metadata?.counts?.totalSamples ?? counts.totalSamples,
|
|
39
|
+
totalScenarios: metadata?.counts?.totalScenarios ?? counts.totalScenarios,
|
|
40
|
+
totalSpecs: metadata?.counts?.totalSpecs ?? counts.totalSpecs,
|
|
41
|
+
byKind: metadata?.counts?.byKind instanceof Map ? Object.fromEntries(metadata.counts.byKind.entries()) : metadata?.counts?.byKind ? Object.fromEntries(Object.entries(metadata.counts.byKind).map(([key, value]) => [key, Number(value)])) : counts.byKind
|
|
42
|
+
},
|
|
43
|
+
repo: {
|
|
44
|
+
commit: repo.commit ?? null,
|
|
45
|
+
branch: repo.branch ?? null,
|
|
46
|
+
repoUrl: repo.repoUrl ?? null
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function loadSampleData() {
|
|
51
|
+
if (cachedData) {
|
|
52
|
+
return cachedData;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const sharedIndexUrl = new URL("../shared/sample-index.json", import.meta.url);
|
|
56
|
+
const filePath = fileURLToPath(sharedIndexUrl);
|
|
57
|
+
const raw = readFileSync(filePath, "utf8");
|
|
58
|
+
const parsed = JSON.parse(raw);
|
|
59
|
+
const entries = Array.isArray(parsed.entries) ? parsed.entries.map(normalizeEntry) : [];
|
|
60
|
+
if (entries.length === 0) {
|
|
61
|
+
throw new Error("Sample index does not contain any entries.");
|
|
62
|
+
}
|
|
63
|
+
const metadata = normalizeMetadata(parsed.metadata, entries);
|
|
64
|
+
cachedData = { entries, metadata };
|
|
65
|
+
return cachedData;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Failed to load sample index from shared/sample-index.json. Please run 'pnpm generate-index' to create the index file. Error: ${message}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function getAllEntries() {
|
|
74
|
+
return loadSampleData().entries;
|
|
75
|
+
}
|
|
76
|
+
function getEntryById(id) {
|
|
77
|
+
return getAllEntries().find((entry) => entry.id === id);
|
|
78
|
+
}
|
|
79
|
+
function getSampleIndexMetadata() {
|
|
80
|
+
return loadSampleData().metadata;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { getAllEntries, getEntryById, getSampleIndexMetadata };
|
package/dist/mcp.cjs
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
4
|
+
const streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
5
|
+
const express = require('express');
|
|
6
|
+
const node_module = require('node:module');
|
|
7
|
+
const zod = require('zod');
|
|
8
|
+
const data = require('./data.cjs');
|
|
9
|
+
const search = require('./search.cjs');
|
|
10
|
+
require('node:fs');
|
|
11
|
+
require('node:url');
|
|
12
|
+
require('fuse.js');
|
|
13
|
+
|
|
14
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
15
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
16
|
+
|
|
17
|
+
const express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
18
|
+
|
|
19
|
+
const KIND_OPTIONS = ["doc", "sample", "scenario", "spec"];
|
|
20
|
+
function isValidKind(value) {
|
|
21
|
+
return typeof value === "string" && KIND_OPTIONS.includes(value);
|
|
22
|
+
}
|
|
23
|
+
function normalizeTags(tags) {
|
|
24
|
+
return Array.isArray(tags) ? tags : [];
|
|
25
|
+
}
|
|
26
|
+
function formatTagsForText(tags) {
|
|
27
|
+
const normalized = normalizeTags(tags);
|
|
28
|
+
return normalized.length > 0 ? normalized.join(", ") : "none";
|
|
29
|
+
}
|
|
30
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('mcp.cjs', document.baseURI).href)));
|
|
31
|
+
const {
|
|
32
|
+
version: PACKAGE_VERSION = "0.0.0",
|
|
33
|
+
name: PACKAGE_NAME = "@public-ui/mcp",
|
|
34
|
+
description: PACKAGE_DESCRIPTION
|
|
35
|
+
} = require$1("../package.json");
|
|
36
|
+
const ENABLE_LOGGING = process.env.MCP_LOGGING === "true" || process.env.MCP_LOGGING === "1";
|
|
37
|
+
function log(type, message, data) {
|
|
38
|
+
if (!ENABLE_LOGGING) return;
|
|
39
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
40
|
+
const prefix = `[${timestamp}] [${type.toUpperCase()}]`;
|
|
41
|
+
if (data) {
|
|
42
|
+
console.error(`${prefix} ${message}`, JSON.stringify(data, null, 2));
|
|
43
|
+
} else {
|
|
44
|
+
console.error(`${prefix} ${message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function createKolibriMcpServer() {
|
|
48
|
+
const server = new mcp_js.McpServer({
|
|
49
|
+
name: PACKAGE_NAME,
|
|
50
|
+
version: PACKAGE_VERSION
|
|
51
|
+
});
|
|
52
|
+
return configureServer(server);
|
|
53
|
+
}
|
|
54
|
+
function configureServer(server) {
|
|
55
|
+
server.registerTool(
|
|
56
|
+
"search",
|
|
57
|
+
{
|
|
58
|
+
title: "Search KoliBri Samples and Docs",
|
|
59
|
+
description: 'Search for KoliBri component samples, scenarios, specifications, and documentation using fuzzy search. Parameters: query (optional string), kind (optional select: "doc", "sample", "scenario", or "spec"), limit (optional number, default 10).',
|
|
60
|
+
inputSchema: {
|
|
61
|
+
query: zod.z.string().optional().default(""),
|
|
62
|
+
kind: zod.z.enum(KIND_OPTIONS).optional(),
|
|
63
|
+
limit: zod.z.number().optional()
|
|
64
|
+
},
|
|
65
|
+
outputSchema: {
|
|
66
|
+
query: zod.z.string(),
|
|
67
|
+
totalResults: zod.z.number()
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
({ query, kind, limit }) => {
|
|
71
|
+
log("tool", "search called", { query, kind, limit });
|
|
72
|
+
const queryStr = typeof query === "string" ? query : "";
|
|
73
|
+
const allEntries = data.getAllEntries();
|
|
74
|
+
const searchOptions = {
|
|
75
|
+
limit: typeof limit === "number" ? limit : 10
|
|
76
|
+
};
|
|
77
|
+
if (isValidKind(kind)) {
|
|
78
|
+
searchOptions.kind = kind;
|
|
79
|
+
}
|
|
80
|
+
const results = search.searchEntries(allEntries, queryStr, searchOptions);
|
|
81
|
+
log("tool", "search completed", {
|
|
82
|
+
query: queryStr,
|
|
83
|
+
resultCount: results.length,
|
|
84
|
+
options: searchOptions
|
|
85
|
+
});
|
|
86
|
+
const structuredContent = {
|
|
87
|
+
query: queryStr,
|
|
88
|
+
totalResults: results.length,
|
|
89
|
+
results: results.map(({ item, score }) => ({
|
|
90
|
+
id: item.id,
|
|
91
|
+
kind: item.kind,
|
|
92
|
+
name: item.name,
|
|
93
|
+
group: item.group ?? "N/A",
|
|
94
|
+
description: item.description ?? "N/A",
|
|
95
|
+
tags: normalizeTags(item.tags),
|
|
96
|
+
score: score ?? 1,
|
|
97
|
+
path: item.path ?? "N/A"
|
|
98
|
+
}))
|
|
99
|
+
};
|
|
100
|
+
const resultText = results.length ? results.map(({ item, score }, index) => {
|
|
101
|
+
const matchScore = ((score ?? 1) * 100).toFixed(1);
|
|
102
|
+
const pathLine = item.path ? `
|
|
103
|
+
Path: ${item.path}` : "";
|
|
104
|
+
return `${index + 1}. [${item.kind}] ${item.id}: ${item.name}
|
|
105
|
+
Description: ${item.description ?? "N/A"}
|
|
106
|
+
Match score: ${matchScore}%
|
|
107
|
+
Tags: ${formatTagsForText(item.tags)}${pathLine}`;
|
|
108
|
+
}).join("\n\n") : "No matches found.";
|
|
109
|
+
const tipText = results.length ? "\n\n\u{1F4A1} Tip: Use 'fetch' with any ID above to see full entry details." : "";
|
|
110
|
+
return {
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: "text",
|
|
114
|
+
text: `Found ${results.length} result(s) for "${queryStr}":
|
|
115
|
+
|
|
116
|
+
${resultText}${tipText}`
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
structuredContent
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
server.registerTool(
|
|
124
|
+
"fetch",
|
|
125
|
+
{
|
|
126
|
+
title: "Get Sample or Doc Entry",
|
|
127
|
+
description: 'Get a specific sample, specification, or documentation entry by its ID. Parameter: id (required string, e.g. "button/basic", "spec/button", or "docs/getting-started")',
|
|
128
|
+
inputSchema: {
|
|
129
|
+
id: zod.z.string()
|
|
130
|
+
},
|
|
131
|
+
outputSchema: {
|
|
132
|
+
id: zod.z.string(),
|
|
133
|
+
kind: zod.z.string(),
|
|
134
|
+
name: zod.z.string()
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
({ id }) => {
|
|
138
|
+
log("tool", "fetch called", { id });
|
|
139
|
+
const idStr = String(id ?? "");
|
|
140
|
+
if (!idStr) {
|
|
141
|
+
log("error", "fetch failed: empty id");
|
|
142
|
+
throw new Error("ID parameter is required");
|
|
143
|
+
}
|
|
144
|
+
const entry = data.getEntryById(idStr);
|
|
145
|
+
if (!entry) {
|
|
146
|
+
log("error", "fetch failed: entry not found", { id: idStr });
|
|
147
|
+
throw new Error(`Entry with ID "${idStr}" not found`);
|
|
148
|
+
}
|
|
149
|
+
log("tool", "fetch completed", { id: idStr, kind: entry.kind });
|
|
150
|
+
const output = {
|
|
151
|
+
id: entry.id,
|
|
152
|
+
kind: entry.kind,
|
|
153
|
+
name: entry.name,
|
|
154
|
+
group: entry.group ?? "N/A",
|
|
155
|
+
description: entry.description ?? "N/A",
|
|
156
|
+
tags: entry.tags ?? [],
|
|
157
|
+
code: entry.code ?? "No code available",
|
|
158
|
+
path: entry.path ?? "N/A"
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
content: [
|
|
162
|
+
{
|
|
163
|
+
type: "text",
|
|
164
|
+
text: `# ${entry.name}
|
|
165
|
+
|
|
166
|
+
ID: ${entry.id}
|
|
167
|
+
Kind: ${entry.kind}
|
|
168
|
+
Group: ${entry.group ?? "N/A"}
|
|
169
|
+
Description: ${entry.description ?? "N/A"}
|
|
170
|
+
Tags: ${entry.tags?.join(", ") ?? "none"}
|
|
171
|
+
|
|
172
|
+
## Code
|
|
173
|
+
|
|
174
|
+
\`\`\`
|
|
175
|
+
${entry.code ?? "No code available"}
|
|
176
|
+
\`\`\``
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
structuredContent: output
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
server.registerResource(
|
|
184
|
+
"info",
|
|
185
|
+
new mcp_js.ResourceTemplate("kolibri://info", { list: void 0 }),
|
|
186
|
+
{
|
|
187
|
+
title: "KoliBri MCP Server Info",
|
|
188
|
+
description: "Get information about the KoliBri MCP Server and available samples"
|
|
189
|
+
},
|
|
190
|
+
(uri) => {
|
|
191
|
+
log("resource", "info accessed", { uri: uri.href });
|
|
192
|
+
const metadata = data.getSampleIndexMetadata();
|
|
193
|
+
const infoText = `# KoliBri MCP Server v${PACKAGE_VERSION}
|
|
194
|
+
|
|
195
|
+
${PACKAGE_DESCRIPTION ?? ""}
|
|
196
|
+
|
|
197
|
+
## Sample Index
|
|
198
|
+
- Generated: ${metadata.generatedAt ?? "unknown"}
|
|
199
|
+
- Build mode: ${metadata.buildMode}
|
|
200
|
+
- Total entries: ${metadata.counts.total}
|
|
201
|
+
- Documentation: ${metadata.counts.totalDocs}
|
|
202
|
+
- Specifications: ${metadata.counts.totalSpecs ?? 0}
|
|
203
|
+
- Samples: ${metadata.counts.totalSamples}
|
|
204
|
+
- Scenarios: ${metadata.counts.totalScenarios ?? 0}
|
|
205
|
+
|
|
206
|
+
## Repository
|
|
207
|
+
- Branch: ${metadata.repo.branch ?? "N/A"}
|
|
208
|
+
- Commit: ${metadata.repo.commit ?? "N/A"}
|
|
209
|
+
- URL: ${metadata.repo.repoUrl ?? "N/A"}
|
|
210
|
+
`;
|
|
211
|
+
return {
|
|
212
|
+
contents: [
|
|
213
|
+
{
|
|
214
|
+
uri: uri.href,
|
|
215
|
+
mimeType: "text/markdown",
|
|
216
|
+
text: infoText
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
server.registerResource(
|
|
223
|
+
"best-practices",
|
|
224
|
+
new mcp_js.ResourceTemplate("kolibri://best-practices", { list: void 0 }),
|
|
225
|
+
{
|
|
226
|
+
title: "KoliBri Best Practices",
|
|
227
|
+
description: "Essential guidelines for working with KoliBri Web Components"
|
|
228
|
+
},
|
|
229
|
+
(uri) => {
|
|
230
|
+
log("resource", "best-practices accessed", { uri: uri.href });
|
|
231
|
+
const practicesText = `# KoliBri Web Components - Best Practices
|
|
232
|
+
|
|
233
|
+
## Essential Guidelines
|
|
234
|
+
|
|
235
|
+
1. **Component Registration**
|
|
236
|
+
Always register KoliBri Web Components in the browser runtime before rendering them.
|
|
237
|
+
|
|
238
|
+
2. **Integration Setup**
|
|
239
|
+
Choose the integration guide that matches your project setup to load and bundle the components correctly.
|
|
240
|
+
|
|
241
|
+
3. **Icon Font Assets**
|
|
242
|
+
Bundle the KoliBri icon font assets (for example codicon.css and codicon.ttf) so kol-icon glyphs can render.
|
|
243
|
+
|
|
244
|
+
4. **Form Validation**
|
|
245
|
+
Wrap input elements with <kol-form> and feed its _errorList to surface validation issues via the generated error summary.
|
|
246
|
+
|
|
247
|
+
## Additional Resources
|
|
248
|
+
|
|
249
|
+
Use the 'search' tool to find specific component examples and implementation details.
|
|
250
|
+
Use the 'fetch' tool to retrieve full code samples for specific components.
|
|
251
|
+
`;
|
|
252
|
+
return {
|
|
253
|
+
contents: [
|
|
254
|
+
{
|
|
255
|
+
uri: uri.href,
|
|
256
|
+
mimeType: "text/markdown",
|
|
257
|
+
text: practicesText
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
return server;
|
|
264
|
+
}
|
|
265
|
+
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")) {
|
|
266
|
+
const server = createKolibriMcpServer();
|
|
267
|
+
const app = express__default();
|
|
268
|
+
app.use(express__default.json());
|
|
269
|
+
app.post("/mcp", async (req, res) => {
|
|
270
|
+
const transport = new streamableHttp_js.StreamableHTTPServerTransport({
|
|
271
|
+
sessionIdGenerator: void 0,
|
|
272
|
+
enableJsonResponse: true
|
|
273
|
+
});
|
|
274
|
+
res.on("close", () => {
|
|
275
|
+
void transport.close();
|
|
276
|
+
});
|
|
277
|
+
await server.connect(transport);
|
|
278
|
+
await transport.handleRequest(req, res, req.body);
|
|
279
|
+
});
|
|
280
|
+
const port = parseInt(process.env.PORT || "3000");
|
|
281
|
+
void app.listen(port, () => {
|
|
282
|
+
console.log(`KoliBri MCP Server v${PACKAGE_VERSION} running on http://localhost:${port}/mcp`);
|
|
283
|
+
const metadata = data.getSampleIndexMetadata();
|
|
284
|
+
console.log(
|
|
285
|
+
`Loaded ${metadata.counts.total} entries (${metadata.counts.totalDocs} docs, ${metadata.counts.totalSamples} samples, ${metadata.counts.totalScenarios ?? 0} scenarios)`
|
|
286
|
+
);
|
|
287
|
+
if (ENABLE_LOGGING) {
|
|
288
|
+
console.log("\u{1F50D} Logging is ENABLED (MCP_LOGGING=true)");
|
|
289
|
+
} else {
|
|
290
|
+
console.log("\u{1F4A1} Logging is disabled. Set MCP_LOGGING=true to enable request logging");
|
|
291
|
+
}
|
|
292
|
+
}).on("error", (error) => {
|
|
293
|
+
console.error("Server error:", error);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
exports.createKolibriMcpServer = createKolibriMcpServer;
|
package/dist/mcp.d.cts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a configured KoliBri MCP server instance.
|
|
5
|
+
* Can be used with both stdio and HTTP transports.
|
|
6
|
+
*/
|
|
7
|
+
declare function createKolibriMcpServer(): McpServer;
|
|
8
|
+
|
|
9
|
+
export { createKolibriMcpServer };
|
package/dist/mcp.d.mts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a configured KoliBri MCP server instance.
|
|
5
|
+
* Can be used with both stdio and HTTP transports.
|
|
6
|
+
*/
|
|
7
|
+
declare function createKolibriMcpServer(): McpServer;
|
|
8
|
+
|
|
9
|
+
export { createKolibriMcpServer };
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a configured KoliBri MCP server instance.
|
|
5
|
+
* Can be used with both stdio and HTTP transports.
|
|
6
|
+
*/
|
|
7
|
+
declare function createKolibriMcpServer(): McpServer;
|
|
8
|
+
|
|
9
|
+
export { createKolibriMcpServer };
|