viora-ui-mcp 1.0.0
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/index.js +120 -0
- package/package.json +25 -0
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +127 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +139 -0
- package/tsconfig.json +15 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
const REGISTRY_BASE_URL = "https://vioraui.dedyn.io/registry";
|
|
6
|
+
const server = new Server({
|
|
7
|
+
name: "viora-ui-mcp",
|
|
8
|
+
version: "1.0.0",
|
|
9
|
+
}, {
|
|
10
|
+
capabilities: {
|
|
11
|
+
tools: {},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
// Define the tools
|
|
15
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
16
|
+
return {
|
|
17
|
+
tools: [
|
|
18
|
+
{
|
|
19
|
+
name: "list_viora_components",
|
|
20
|
+
description: "Lists all available Viora UI components from the official registry.",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "get_viora_component_code",
|
|
28
|
+
description: "Gets the full raw source code and dependencies for a specific Viora UI component.",
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
componentName: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "The name of the component (e.g. 'carousel-002', 'accordion').",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: ["componentName"],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
// Handle tool execution
|
|
44
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
45
|
+
if (request.params.name === "list_viora_components") {
|
|
46
|
+
try {
|
|
47
|
+
const res = await fetch(`${REGISTRY_BASE_URL}/index.json`);
|
|
48
|
+
if (!res.ok)
|
|
49
|
+
throw new Error(`Failed to fetch index: ${res.statusText}`);
|
|
50
|
+
const components = await res.json();
|
|
51
|
+
// Just extract names and descriptions/types for brevity
|
|
52
|
+
const summary = components.map((c) => ({
|
|
53
|
+
name: c.name,
|
|
54
|
+
type: c.type,
|
|
55
|
+
dependencies: c.dependencies || []
|
|
56
|
+
}));
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: JSON.stringify(summary, null, 2),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
return {
|
|
68
|
+
isError: true,
|
|
69
|
+
content: [{ type: "text", text: `Failed to fetch registry: ${e.message}` }],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (request.params.name === "get_viora_component_code") {
|
|
74
|
+
const componentName = request.params.arguments?.componentName;
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(`${REGISTRY_BASE_URL}/${componentName}.json`);
|
|
77
|
+
if (res.status === 404) {
|
|
78
|
+
return {
|
|
79
|
+
isError: true,
|
|
80
|
+
content: [{ type: "text", text: `Component '${componentName}' not found.` }],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (!res.ok)
|
|
84
|
+
throw new Error(`Failed to fetch component: ${res.statusText}`);
|
|
85
|
+
const componentData = await res.json();
|
|
86
|
+
// Format the output nicely for an AI agent to consume
|
|
87
|
+
let outputText = `Component: ${componentData.name}\nType: ${componentData.type}\n`;
|
|
88
|
+
if (componentData.dependencies && componentData.dependencies.length > 0) {
|
|
89
|
+
outputText += `Dependencies: ${componentData.dependencies.join(", ")}\n`;
|
|
90
|
+
}
|
|
91
|
+
outputText += `\n--- FILES ---\n\n`;
|
|
92
|
+
for (const file of componentData.files) {
|
|
93
|
+
outputText += `File: ${file.path || file.name || 'unknown'}\n`;
|
|
94
|
+
outputText += `Target: ${file.target || 'unknown'}\n`;
|
|
95
|
+
outputText += `\`\`\`tsx\n${file.content}\n\`\`\`\n\n`;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: "text",
|
|
101
|
+
text: outputText,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
return {
|
|
108
|
+
isError: true,
|
|
109
|
+
content: [{ type: "text", text: `Failed to get component code: ${e.message}` }],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
throw new Error(`Tool not found: ${request.params.name}`);
|
|
114
|
+
});
|
|
115
|
+
async function run() {
|
|
116
|
+
const transport = new StdioServerTransport();
|
|
117
|
+
await server.connect(transport);
|
|
118
|
+
console.error("Viora UI MCP Server running on stdio");
|
|
119
|
+
}
|
|
120
|
+
run().catch(console.error);
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "viora-ui-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"build": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [],
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^26.5.1",
|
|
19
|
+
"typescript": "^7.0.2"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"viora-ui-mcp": "./dist/index.js",
|
|
23
|
+
"mcp-server": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":""}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
7
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
// The path to the UI library root, passed as an argument or relative to this script
|
|
12
|
+
const UI_LIB_PATH = process.argv[2] || path_1.default.join(__dirname, "../../");
|
|
13
|
+
const REGISTRY_PATH = path_1.default.join(UI_LIB_PATH, "registry", "registry-components.ts");
|
|
14
|
+
const server = new index_js_1.Server({
|
|
15
|
+
name: "viora-ui-mcp",
|
|
16
|
+
version: "1.0.0",
|
|
17
|
+
}, {
|
|
18
|
+
capabilities: {
|
|
19
|
+
tools: {},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
// Define the tools
|
|
23
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
24
|
+
return {
|
|
25
|
+
tools: [
|
|
26
|
+
{
|
|
27
|
+
name: "list_viora_components",
|
|
28
|
+
description: "Lists all available Viora UI components by parsing the registry.",
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "get_viora_component_code",
|
|
36
|
+
description: "Gets the full raw source code for a specific Viora UI component.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
componentName: {
|
|
41
|
+
type: "string",
|
|
42
|
+
description: "The name of the component (e.g. 'carousel-002', 'sticky-card').",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: ["componentName"],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
// Handle tool execution
|
|
52
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
53
|
+
if (request.params.name === "list_viora_components") {
|
|
54
|
+
try {
|
|
55
|
+
const registryContent = fs_1.default.readFileSync(REGISTRY_PATH, "utf-8");
|
|
56
|
+
// Extremely simple regex to extract component names
|
|
57
|
+
const nameRegex = /name:\s*"([^"]+)"/g;
|
|
58
|
+
const components = [];
|
|
59
|
+
let match;
|
|
60
|
+
while ((match = nameRegex.exec(registryContent)) !== null) {
|
|
61
|
+
components.push(match[1]);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: "text",
|
|
67
|
+
text: JSON.stringify([...new Set(components)], null, 2),
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
return {
|
|
74
|
+
isError: true,
|
|
75
|
+
content: [{ type: "text", text: `Failed to read registry: ${e.message}` }],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (request.params.name === "get_viora_component_code") {
|
|
80
|
+
const componentName = request.params.arguments?.componentName;
|
|
81
|
+
try {
|
|
82
|
+
const registryContent = fs_1.default.readFileSync(REGISTRY_PATH, "utf-8");
|
|
83
|
+
// Find the component block
|
|
84
|
+
const componentIndex = registryContent.indexOf(`name: "${componentName}"`);
|
|
85
|
+
if (componentIndex === -1) {
|
|
86
|
+
return {
|
|
87
|
+
isError: true,
|
|
88
|
+
content: [{ type: "text", text: `Component '${componentName}' not found in registry.` }],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Extract the path
|
|
92
|
+
const pathRegex = /path:\s*"([^"]+)"/g;
|
|
93
|
+
pathRegex.lastIndex = componentIndex;
|
|
94
|
+
const match = pathRegex.exec(registryContent);
|
|
95
|
+
if (!match) {
|
|
96
|
+
return {
|
|
97
|
+
isError: true,
|
|
98
|
+
content: [{ type: "text", text: `Could not find file path for component '${componentName}'.` }],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const componentPath = path_1.default.join(UI_LIB_PATH, match[1]);
|
|
102
|
+
const componentCode = fs_1.default.readFileSync(componentPath, "utf-8");
|
|
103
|
+
return {
|
|
104
|
+
content: [
|
|
105
|
+
{
|
|
106
|
+
type: "text",
|
|
107
|
+
text: componentCode,
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
return {
|
|
114
|
+
isError: true,
|
|
115
|
+
content: [{ type: "text", text: `Failed to get component code: ${e.message}` }],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
throw new Error(`Tool not found: ${request.params.name}`);
|
|
120
|
+
});
|
|
121
|
+
async function run() {
|
|
122
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
123
|
+
await server.connect(transport);
|
|
124
|
+
console.error("Viora UI MCP Server running on stdio");
|
|
125
|
+
}
|
|
126
|
+
run().catch(console.error);
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import {
|
|
5
|
+
CallToolRequestSchema,
|
|
6
|
+
ListToolsRequestSchema,
|
|
7
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
|
|
9
|
+
const REGISTRY_BASE_URL = "https://vioraui.dedyn.io/registry";
|
|
10
|
+
|
|
11
|
+
const server = new Server(
|
|
12
|
+
{
|
|
13
|
+
name: "viora-ui-mcp",
|
|
14
|
+
version: "1.0.0",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
capabilities: {
|
|
18
|
+
tools: {},
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Define the tools
|
|
24
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
25
|
+
return {
|
|
26
|
+
tools: [
|
|
27
|
+
{
|
|
28
|
+
name: "list_viora_components",
|
|
29
|
+
description: "Lists all available Viora UI components from the official registry.",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "get_viora_component_code",
|
|
37
|
+
description: "Gets the full raw source code and dependencies for a specific Viora UI component.",
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: {
|
|
41
|
+
componentName: {
|
|
42
|
+
type: "string",
|
|
43
|
+
description: "The name of the component (e.g. 'carousel-002', 'accordion').",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
required: ["componentName"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Handle tool execution
|
|
54
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
55
|
+
if (request.params.name === "list_viora_components") {
|
|
56
|
+
try {
|
|
57
|
+
const res = await fetch(`${REGISTRY_BASE_URL}/index.json`);
|
|
58
|
+
if (!res.ok) throw new Error(`Failed to fetch index: ${res.statusText}`);
|
|
59
|
+
|
|
60
|
+
const components = await res.json();
|
|
61
|
+
|
|
62
|
+
// Just extract names and descriptions/types for brevity
|
|
63
|
+
const summary = components.map((c: any) => ({
|
|
64
|
+
name: c.name,
|
|
65
|
+
type: c.type,
|
|
66
|
+
dependencies: c.dependencies || []
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: JSON.stringify(summary, null, 2),
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
} catch (e: any) {
|
|
78
|
+
return {
|
|
79
|
+
isError: true,
|
|
80
|
+
content: [{ type: "text", text: `Failed to fetch registry: ${e.message}` }],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (request.params.name === "get_viora_component_code") {
|
|
86
|
+
const componentName = request.params.arguments?.componentName as string;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const res = await fetch(`${REGISTRY_BASE_URL}/${componentName}.json`);
|
|
90
|
+
if (res.status === 404) {
|
|
91
|
+
return {
|
|
92
|
+
isError: true,
|
|
93
|
+
content: [{ type: "text", text: `Component '${componentName}' not found.` }],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (!res.ok) throw new Error(`Failed to fetch component: ${res.statusText}`);
|
|
97
|
+
|
|
98
|
+
const componentData = await res.json();
|
|
99
|
+
|
|
100
|
+
// Format the output nicely for an AI agent to consume
|
|
101
|
+
let outputText = `Component: ${componentData.name}\nType: ${componentData.type}\n`;
|
|
102
|
+
if (componentData.dependencies && componentData.dependencies.length > 0) {
|
|
103
|
+
outputText += `Dependencies: ${componentData.dependencies.join(", ")}\n`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
outputText += `\n--- FILES ---\n\n`;
|
|
107
|
+
|
|
108
|
+
for (const file of componentData.files) {
|
|
109
|
+
outputText += `File: ${file.path || file.name || 'unknown'}\n`;
|
|
110
|
+
outputText += `Target: ${file.target || 'unknown'}\n`;
|
|
111
|
+
outputText += `\`\`\`tsx\n${file.content}\n\`\`\`\n\n`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: outputText,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
} catch (e: any) {
|
|
123
|
+
return {
|
|
124
|
+
isError: true,
|
|
125
|
+
content: [{ type: "text", text: `Failed to get component code: ${e.message}` }],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
throw new Error(`Tool not found: ${request.params.name}`);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
async function run() {
|
|
134
|
+
const transport = new StdioServerTransport();
|
|
135
|
+
await server.connect(transport);
|
|
136
|
+
console.error("Viora UI MCP Server running on stdio");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
run().catch(console.error);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"types": ["node"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"]
|
|
15
|
+
}
|