@specverse/engines 4.1.5 → 4.1.7
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/libs/instance-factories/applications/templates/generic/backend-env-generator.js +22 -0
- package/dist/libs/instance-factories/applications/templates/generic/backend-package-json-generator.js +66 -0
- package/dist/libs/instance-factories/applications/templates/generic/backend-tsconfig-generator.js +54 -0
- package/dist/libs/instance-factories/applications/templates/generic/main-generator.js +290 -0
- package/dist/libs/instance-factories/applications/templates/react/_view-components-source.js +530 -0
- package/dist/libs/instance-factories/applications/templates/react/api-client-generator.js +437 -0
- package/dist/libs/instance-factories/applications/templates/react/api-types-generator.js +146 -0
- package/dist/libs/instance-factories/applications/templates/react/app-tsx-generator.js +73 -0
- package/dist/libs/instance-factories/applications/templates/react/env-example-generator.js +18 -0
- package/dist/libs/instance-factories/applications/templates/react/field-helpers-generator.js +99 -0
- package/dist/libs/instance-factories/applications/templates/react/gitignore-generator.js +35 -0
- package/dist/libs/instance-factories/applications/templates/react/index-css-generator.js +9 -0
- package/dist/libs/instance-factories/applications/templates/react/index-html-generator.js +23 -0
- package/dist/libs/instance-factories/applications/templates/react/main-tsx-generator.js +29 -0
- package/dist/libs/instance-factories/applications/templates/react/package-json-generator.js +49 -0
- package/dist/libs/instance-factories/applications/templates/react/pattern-adapter-generator.js +156 -0
- package/dist/libs/instance-factories/applications/templates/react/react-pattern-adapter.js +935 -0
- package/dist/libs/instance-factories/applications/templates/react/relationship-field-generator.js +143 -0
- package/dist/libs/instance-factories/applications/templates/react/runtime-app-tsx-generator.js +101 -0
- package/dist/libs/instance-factories/applications/templates/react/runtime-package-json-generator.js +50 -0
- package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.js +646 -0
- package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.js +65 -0
- package/dist/libs/instance-factories/applications/templates/react/tsconfig-generator.js +28 -0
- package/dist/libs/instance-factories/applications/templates/react/use-api-hooks-generator.js +132 -0
- package/dist/libs/instance-factories/applications/templates/react/view-dashboard-generator.js +143 -0
- package/dist/libs/instance-factories/applications/templates/react/view-detail-generator.js +143 -0
- package/dist/libs/instance-factories/applications/templates/react/view-form-generator.js +355 -0
- package/dist/libs/instance-factories/applications/templates/react/view-list-generator.js +91 -0
- package/dist/libs/instance-factories/applications/templates/react/view-router-generator.js +79 -0
- package/dist/libs/instance-factories/applications/templates/react/vite-config-generator.js +42 -0
- package/dist/libs/instance-factories/cli/templates/commander/cli-bin-wrapper-generator.js +11 -0
- package/dist/libs/instance-factories/cli/templates/commander/cli-entry-generator.js +111 -0
- package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +928 -0
- package/dist/libs/instance-factories/communication/templates/eventemitter/bus-generator.js +83 -0
- package/dist/libs/instance-factories/communication/templates/eventemitter/publisher-generator.js +91 -0
- package/dist/libs/instance-factories/communication/templates/eventemitter/subscriber-generator.js +86 -0
- package/dist/libs/instance-factories/controllers/templates/fastify/meta-routes-generator.js +93 -0
- package/dist/libs/instance-factories/controllers/templates/fastify/routes-generator.js +280 -0
- package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +125 -0
- package/dist/libs/instance-factories/infrastructure/templates/docker-k8s/infrastructure-generator.js +25 -0
- package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +371 -0
- package/dist/libs/instance-factories/orms/templates/prisma/services-generator.js +266 -0
- package/dist/libs/instance-factories/scaffolding/templates/generic/env-example-generator.js +51 -0
- package/dist/libs/instance-factories/scaffolding/templates/generic/env-generator.js +61 -0
- package/dist/libs/instance-factories/scaffolding/templates/generic/gitignore-generator.js +59 -0
- package/dist/libs/instance-factories/scaffolding/templates/generic/package-json-generator.js +126 -0
- package/dist/libs/instance-factories/scaffolding/templates/generic/readme-generator.js +159 -0
- package/dist/libs/instance-factories/scaffolding/templates/generic/tsconfig-generator.js +56 -0
- package/dist/libs/instance-factories/scaffolding/templates/generic/tsconfig-react-generator.js +37 -0
- package/dist/libs/instance-factories/sdks/templates/python/sdk-generator.js +29 -0
- package/dist/libs/instance-factories/sdks/templates/typescript/sdk-generator.js +28 -0
- package/dist/libs/instance-factories/services/templates/memory/generate-interpreter.js +14 -0
- package/dist/libs/instance-factories/services/templates/memory/step-conventions-memory.js +415 -0
- package/dist/libs/instance-factories/services/templates/prisma/behavior-generator.js +177 -0
- package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +413 -0
- package/dist/libs/instance-factories/services/templates/prisma/service-generator.js +243 -0
- package/dist/libs/instance-factories/services/templates/prisma/step-conventions.js +264 -0
- package/dist/libs/instance-factories/services/templates/shared-patterns.js +24 -0
- package/dist/libs/instance-factories/shared/path-resolver.js +59 -0
- package/dist/libs/instance-factories/storage/templates/mongodb/config-generator.js +13 -0
- package/dist/libs/instance-factories/storage/templates/mongodb/docker-generator.js +16 -0
- package/dist/libs/instance-factories/storage/templates/postgresql/config-generator.js +45 -0
- package/dist/libs/instance-factories/storage/templates/postgresql/docker-generator.js +46 -0
- package/dist/libs/instance-factories/storage/templates/redis/config-generator.js +14 -0
- package/dist/libs/instance-factories/storage/templates/redis/docker-generator.js +16 -0
- package/dist/libs/instance-factories/test-generation.js +145 -0
- package/dist/libs/instance-factories/testing/templates/vitest/tests-generator.js +30 -0
- package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +149 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.js +232 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.js +49 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/index.js +18 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.js +0 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.js +97 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.js +64 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.js +182 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.js +1210 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.js +172 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.js +240 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.js +147 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.js +281 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.js +409 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.js +414 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.js +467 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.js +135 -0
- package/dist/libs/instance-factories/tools/templates/mcp/static/src/types/index.js +0 -0
- package/dist/libs/instance-factories/tools/templates/vscode/static/extension.js +965 -0
- package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js +238 -0
- package/dist/libs/instance-factories/validation/templates/zod/validation-generator.js +25 -0
- package/dist/libs/instance-factories/views/index.js +48 -0
- package/dist/libs/instance-factories/views/templates/react/adapters/antd-adapter.js +742 -0
- package/dist/libs/instance-factories/views/templates/react/adapters/mui-adapter.js +824 -0
- package/dist/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.js +719 -0
- package/dist/libs/instance-factories/views/templates/react/app-generator.js +45 -0
- package/dist/libs/instance-factories/views/templates/react/components-generator.js +779 -0
- package/dist/libs/instance-factories/views/templates/react/forms-generator.js +285 -0
- package/dist/libs/instance-factories/views/templates/react/frontend-package-json-generator.js +46 -0
- package/dist/libs/instance-factories/views/templates/react/hooks-generator.js +111 -0
- package/dist/libs/instance-factories/views/templates/react/index-css-generator.js +9 -0
- package/dist/libs/instance-factories/views/templates/react/index-html-generator.js +23 -0
- package/dist/libs/instance-factories/views/templates/react/main-tsx-generator.js +21 -0
- package/dist/libs/instance-factories/views/templates/react/react-component-generator.js +299 -0
- package/dist/libs/instance-factories/views/templates/react/router-generator.js +136 -0
- package/dist/libs/instance-factories/views/templates/react/router-generic-generator.js +107 -0
- package/dist/libs/instance-factories/views/templates/react/shared-utils-generator.js +179 -0
- package/dist/libs/instance-factories/views/templates/react/spec-json-generator.js +7 -0
- package/dist/libs/instance-factories/views/templates/react/types-generator.js +56 -0
- package/dist/libs/instance-factories/views/templates/react/views-metadata-generator.js +27 -0
- package/dist/libs/instance-factories/views/templates/react/vite-config-generator.js +29 -0
- package/dist/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js +261 -0
- package/dist/libs/instance-factories/views/templates/shared/adapter-types.js +34 -0
- package/dist/libs/instance-factories/views/templates/shared/atomic-components-registry.js +800 -0
- package/dist/libs/instance-factories/views/templates/shared/base-generator.js +305 -0
- package/dist/libs/instance-factories/views/templates/shared/component-metadata.js +517 -0
- package/dist/libs/instance-factories/views/templates/shared/composite-pattern-types.js +0 -0
- package/dist/libs/instance-factories/views/templates/shared/composite-patterns.js +445 -0
- package/dist/libs/instance-factories/views/templates/shared/index.js +80 -0
- package/dist/libs/instance-factories/views/templates/shared/pattern-validator.js +210 -0
- package/dist/libs/instance-factories/views/templates/shared/property-mapper.js +492 -0
- package/dist/libs/instance-factories/views/templates/shared/syntax-mapper.js +321 -0
- package/dist/realize/index.js +36 -12
- package/dist/realize/index.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync, statSync, copyFileSync } from "fs";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
const __generatorDir = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
function generateMCPServer(context) {
|
|
6
|
+
const { spec, outputDir } = context;
|
|
7
|
+
const mcpDir = join(outputDir || ".", "tools", "specverse-mcp");
|
|
8
|
+
if (!existsSync(mcpDir)) mkdirSync(mcpDir, { recursive: true });
|
|
9
|
+
let staticDir = join(__generatorDir, "static");
|
|
10
|
+
if (!existsSync(staticDir)) {
|
|
11
|
+
staticDir = __generatorDir.replace("/dist/libs/", "/libs/");
|
|
12
|
+
staticDir = join(staticDir, "static");
|
|
13
|
+
}
|
|
14
|
+
if (existsSync(staticDir)) {
|
|
15
|
+
copyRecursive(staticDir, mcpDir);
|
|
16
|
+
} else {
|
|
17
|
+
console.warn(`[MCP Generator] Static assets not found at ${staticDir}`);
|
|
18
|
+
}
|
|
19
|
+
const tools = extractMCPTools(spec);
|
|
20
|
+
const resources = extractMCPResources(spec);
|
|
21
|
+
const cliCommands = extractCLICommands(spec);
|
|
22
|
+
const registryCode = generateToolRegistry(tools, resources, cliCommands);
|
|
23
|
+
const registryDir = join(mcpDir, "src", "generated");
|
|
24
|
+
if (!existsSync(registryDir)) mkdirSync(registryDir, { recursive: true });
|
|
25
|
+
writeFileSync(join(registryDir, "spec-registry.ts"), registryCode);
|
|
26
|
+
return `MCP server generated in: ${mcpDir}
|
|
27
|
+
${tools.length} tools, ${resources.length} resources, ${cliCommands.length} CLI commands`;
|
|
28
|
+
}
|
|
29
|
+
function extractMCPTools(spec) {
|
|
30
|
+
const tools = [];
|
|
31
|
+
const components = spec?.components || {};
|
|
32
|
+
const componentList = Array.isArray(components) ? components : Object.values(components);
|
|
33
|
+
if (spec?.services && !Array.isArray(components)) {
|
|
34
|
+
componentList.push({ services: spec.services, models: spec.models });
|
|
35
|
+
}
|
|
36
|
+
for (const component of componentList) {
|
|
37
|
+
const comp = component;
|
|
38
|
+
const services = comp?.services;
|
|
39
|
+
if (services) {
|
|
40
|
+
const serviceList = Array.isArray(services) ? services : Object.entries(services).map(([n, d]) => ({ name: n, ...d }));
|
|
41
|
+
for (const service of serviceList) {
|
|
42
|
+
const operations = service.operations;
|
|
43
|
+
if (operations) {
|
|
44
|
+
const opEntries = Array.isArray(operations) ? operations : Object.entries(operations).map(([n, d]) => ({ name: n, ...d }));
|
|
45
|
+
for (const op of opEntries) {
|
|
46
|
+
tools.push({
|
|
47
|
+
name: `${service.name.replace(/Service$/, "").toLowerCase()}-${op.name}`,
|
|
48
|
+
description: op.description || `${op.name} via ${service.name}`,
|
|
49
|
+
isEntityTool: false
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const models = comp?.models;
|
|
56
|
+
if (models) {
|
|
57
|
+
const modelList = Array.isArray(models) ? models : Object.entries(models).map(([n, d]) => ({ name: n, ...d }));
|
|
58
|
+
for (const model of modelList) {
|
|
59
|
+
const behaviors = model.behaviors;
|
|
60
|
+
if (behaviors) {
|
|
61
|
+
const behaviorEntries = typeof behaviors === "object" && !Array.isArray(behaviors) ? Object.entries(behaviors).map(([n, d]) => ({ name: n, ...d })) : [];
|
|
62
|
+
for (const behavior of behaviorEntries) {
|
|
63
|
+
tools.push({
|
|
64
|
+
name: `${model.name.toLowerCase()}-${behavior.name}`,
|
|
65
|
+
description: behavior.description || `${behavior.name} on ${model.name}`,
|
|
66
|
+
isEntityTool: true
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const cliCmds = extractCLICommands(spec);
|
|
74
|
+
for (const cmd of cliCmds) {
|
|
75
|
+
tools.push({
|
|
76
|
+
name: `specverse-${cmd}`,
|
|
77
|
+
description: `Execute specverse ${cmd} command`,
|
|
78
|
+
isEntityTool: false
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (tools.length === 0) {
|
|
82
|
+
tools.push(
|
|
83
|
+
{ name: "specverse-validate", description: "Validate a specification", isEntityTool: false },
|
|
84
|
+
{ name: "specverse-create", description: "Create a specification", isEntityTool: false }
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return tools;
|
|
88
|
+
}
|
|
89
|
+
function extractMCPResources(spec) {
|
|
90
|
+
return [
|
|
91
|
+
{ uri: "specverse://schema", name: "SpecVerse Schema", description: "JSON Schema for .specly validation" },
|
|
92
|
+
{ uri: "specverse://conventions", name: "Convention Reference", description: "Convention syntax patterns" },
|
|
93
|
+
{ uri: "specverse://library-catalog", name: "Library Catalog", description: "Available SpecVerse libraries" },
|
|
94
|
+
{ uri: "specverse://prompts", name: "Prompt Templates", description: "AI prompt template versions" }
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
function extractCLICommands(spec) {
|
|
98
|
+
const commands = [];
|
|
99
|
+
const components = spec?.components || [];
|
|
100
|
+
for (const component of Array.isArray(components) ? components : Object.values(components)) {
|
|
101
|
+
const cliCommands = component?.commands;
|
|
102
|
+
if (!cliCommands) continue;
|
|
103
|
+
for (const [, rootDef] of Object.entries(cliCommands)) {
|
|
104
|
+
const subs = rootDef?.subcommands || {};
|
|
105
|
+
for (const subName of Object.keys(subs)) {
|
|
106
|
+
commands.push(subName);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return commands;
|
|
111
|
+
}
|
|
112
|
+
function generateToolRegistry(tools, resources, cliCommands) {
|
|
113
|
+
return `/**
|
|
114
|
+
* Spec-Driven MCP Registry
|
|
115
|
+
* Generated from SpecVerse self-specification.
|
|
116
|
+
*
|
|
117
|
+
* Tools, resources, and CLI command mappings derived from the spec.
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
export const SPEC_TOOLS = ${JSON.stringify(tools, null, 2)};
|
|
121
|
+
|
|
122
|
+
export const SPEC_RESOURCES = ${JSON.stringify(resources, null, 2)};
|
|
123
|
+
|
|
124
|
+
export const CLI_COMMANDS = ${JSON.stringify(cliCommands, null, 2)};
|
|
125
|
+
|
|
126
|
+
export function getToolByName(name: string) {
|
|
127
|
+
return SPEC_TOOLS.find(t => t.name === name);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function getResourceByUri(uri: string) {
|
|
131
|
+
return SPEC_RESOURCES.find(r => r.uri === uri);
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
135
|
+
function copyRecursive(src, dest) {
|
|
136
|
+
for (const entry of readdirSync(src)) {
|
|
137
|
+
const srcPath = join(src, entry);
|
|
138
|
+
const destPath = join(dest, entry);
|
|
139
|
+
if (statSync(srcPath).isDirectory()) {
|
|
140
|
+
if (!existsSync(destPath)) mkdirSync(destPath, { recursive: true });
|
|
141
|
+
copyRecursive(srcPath, destPath);
|
|
142
|
+
} else {
|
|
143
|
+
copyFileSync(srcPath, destPath);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export {
|
|
148
|
+
generateMCPServer as default
|
|
149
|
+
};
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import {
|
|
3
|
+
ListResourcesRequestSchema,
|
|
4
|
+
ReadResourceRequestSchema,
|
|
5
|
+
ListToolsRequestSchema,
|
|
6
|
+
CallToolRequestSchema
|
|
7
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import { HybridResourcesProvider } from "../services/HybridResourcesProvider.js";
|
|
9
|
+
import { CLIProxyService } from "../services/CLIProxyService.js";
|
|
10
|
+
import { EntityModuleService } from "../services/EntityModuleService.js";
|
|
11
|
+
import { EventEmitter } from "../events/EventEmitter.js";
|
|
12
|
+
class MCPServerController {
|
|
13
|
+
server;
|
|
14
|
+
config;
|
|
15
|
+
resourcesProvider;
|
|
16
|
+
cliProxy;
|
|
17
|
+
entityModuleService;
|
|
18
|
+
eventEmitter;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.eventEmitter = new EventEmitter();
|
|
22
|
+
this.server = new Server({
|
|
23
|
+
name: "specverse-dynamic-cli",
|
|
24
|
+
version: "1.0.0"
|
|
25
|
+
}, {
|
|
26
|
+
capabilities: {
|
|
27
|
+
resources: {},
|
|
28
|
+
tools: {}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
this.resourcesProvider = new HybridResourcesProvider({
|
|
32
|
+
mode: "auto",
|
|
33
|
+
resourcesPath: config.resources_path
|
|
34
|
+
});
|
|
35
|
+
this.cliProxy = new CLIProxyService();
|
|
36
|
+
this.entityModuleService = new EntityModuleService();
|
|
37
|
+
this.setupHandlers();
|
|
38
|
+
}
|
|
39
|
+
async listResources() {
|
|
40
|
+
try {
|
|
41
|
+
const startTime = Date.now();
|
|
42
|
+
const resources = await this.resourcesProvider.listResources();
|
|
43
|
+
if (this.entityModuleService.isAvailable()) {
|
|
44
|
+
resources.push(...this.entityModuleService.generateResources());
|
|
45
|
+
}
|
|
46
|
+
this.eventEmitter.emit("resource-requested", {
|
|
47
|
+
uri: "LIST_ALL",
|
|
48
|
+
requestTime: /* @__PURE__ */ new Date()
|
|
49
|
+
});
|
|
50
|
+
if (this.config.logging && this.config.mode !== "local" && process.env.MCP_DEBUG) {
|
|
51
|
+
console.error(`Listed ${resources.length} resources in ${Date.now() - startTime}ms`);
|
|
52
|
+
}
|
|
53
|
+
return resources;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
this.eventEmitter.emit("error-occurred", {
|
|
56
|
+
operation: "listResources",
|
|
57
|
+
error: error instanceof Error ? error.message : String(error)
|
|
58
|
+
});
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async readResource(uri) {
|
|
63
|
+
try {
|
|
64
|
+
const startTime = Date.now();
|
|
65
|
+
if (uri.startsWith("specverse://entities/") && this.entityModuleService.isAvailable()) {
|
|
66
|
+
const entityResources = this.entityModuleService.generateResources();
|
|
67
|
+
const resource2 = entityResources.find((r) => r.uri === uri);
|
|
68
|
+
if (resource2) {
|
|
69
|
+
this.eventEmitter.emit("resource-requested", { uri, requestTime: /* @__PURE__ */ new Date() });
|
|
70
|
+
return resource2;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const content = await this.resourcesProvider.getResourceContent(uri);
|
|
74
|
+
const resources = await this.resourcesProvider.listResources();
|
|
75
|
+
const resource = resources.find((r) => r.uri === uri);
|
|
76
|
+
if (!resource) {
|
|
77
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
78
|
+
}
|
|
79
|
+
this.eventEmitter.emit("resource-requested", {
|
|
80
|
+
uri,
|
|
81
|
+
requestTime: /* @__PURE__ */ new Date()
|
|
82
|
+
});
|
|
83
|
+
if (this.config.logging && this.config.mode !== "local" && process.env.MCP_DEBUG) {
|
|
84
|
+
console.error(`Read resource ${uri} in ${Date.now() - startTime}ms`);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
...resource,
|
|
88
|
+
content
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
this.eventEmitter.emit("error-occurred", {
|
|
92
|
+
operation: "readResource",
|
|
93
|
+
error: error instanceof Error ? error.message : String(error),
|
|
94
|
+
context: { uri }
|
|
95
|
+
});
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
setupHandlers() {
|
|
100
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
101
|
+
const resources = await this.listResources();
|
|
102
|
+
return { resources };
|
|
103
|
+
});
|
|
104
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
105
|
+
const resource = await this.readResource(request.params.uri);
|
|
106
|
+
return {
|
|
107
|
+
contents: [{
|
|
108
|
+
uri: resource.uri,
|
|
109
|
+
mimeType: resource.mimeType,
|
|
110
|
+
text: resource.content
|
|
111
|
+
}]
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
115
|
+
let dynamicCliTools = [];
|
|
116
|
+
try {
|
|
117
|
+
dynamicCliTools = await this.cliProxy.generateMCPTools();
|
|
118
|
+
if (this.config.logging && this.config.mode !== "local" && process.env.MCP_DEBUG) {
|
|
119
|
+
console.error(`\u{1F527} Generated ${dynamicCliTools.length} dynamic CLI tools`);
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (this.config.logging && process.env.MCP_DEBUG) {
|
|
123
|
+
console.error("\u26A0\uFE0F Failed to generate dynamic CLI tools:", error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (this.entityModuleService.isAvailable()) {
|
|
127
|
+
dynamicCliTools.push(...this.entityModuleService.generateTools());
|
|
128
|
+
}
|
|
129
|
+
return { tools: dynamicCliTools };
|
|
130
|
+
});
|
|
131
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
132
|
+
try {
|
|
133
|
+
const { name, arguments: args } = request.params;
|
|
134
|
+
const entityToolNames = ["specverse_expand_constraint", "specverse_list_conventions", "specverse_entity_info"];
|
|
135
|
+
if (entityToolNames.includes(name) && this.entityModuleService.isAvailable()) {
|
|
136
|
+
return await this.entityModuleService.executeTool(name, args || {});
|
|
137
|
+
}
|
|
138
|
+
if (name.startsWith("specverse_")) {
|
|
139
|
+
const result = await this.cliProxy.executeCommand(name, args || {});
|
|
140
|
+
return { content: result.content };
|
|
141
|
+
} else {
|
|
142
|
+
return {
|
|
143
|
+
content: [{
|
|
144
|
+
type: "text",
|
|
145
|
+
text: `Error: Unknown tool '${name}'. Only dynamic CLI tools (prefixed with 'specverse_') are supported.`
|
|
146
|
+
}]
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
return {
|
|
151
|
+
content: [{
|
|
152
|
+
type: "text",
|
|
153
|
+
text: `Error in tool handler: ${error instanceof Error ? error.message : String(error)}`
|
|
154
|
+
}]
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Start the MCP server
|
|
161
|
+
*/
|
|
162
|
+
async start() {
|
|
163
|
+
try {
|
|
164
|
+
await this.resourcesProvider.initializeResources();
|
|
165
|
+
const entityAvailable = await this.entityModuleService.initialize();
|
|
166
|
+
if (this.config.logging && process.env.MCP_DEBUG) {
|
|
167
|
+
if (entityAvailable) {
|
|
168
|
+
const modules = this.entityModuleService.getEntityModules();
|
|
169
|
+
console.error(`\u{1F9E9} Entity modules loaded: ${modules.length} modules, ${modules.reduce((s, m) => s + m.inferenceRuleCount, 0)} rules`);
|
|
170
|
+
} else {
|
|
171
|
+
console.error("\u26A0\uFE0F Entity modules not available in this deployment");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
this.eventEmitter.emit("server-started", {
|
|
175
|
+
serverName: "SpecVerse Dynamic CLI",
|
|
176
|
+
mode: this.config.mode,
|
|
177
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
178
|
+
featuresEnabled: this.config.features,
|
|
179
|
+
pid: process.pid
|
|
180
|
+
});
|
|
181
|
+
if (this.config.logging && process.env.MCP_DEBUG) {
|
|
182
|
+
const mode = this.config.mode || "local";
|
|
183
|
+
const resourceCount = this.resourcesProvider.getCachedResourceCount();
|
|
184
|
+
console.error(`\u{1F680} SpecVerse MCP Server started in ${mode} mode`);
|
|
185
|
+
console.error(`\u{1F4DA} Loaded ${resourceCount} resources`);
|
|
186
|
+
console.error(`\u{1F527} Dynamic CLI integration enabled - all tools from CLI`);
|
|
187
|
+
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
this.eventEmitter.emit("error-occurred", {
|
|
190
|
+
operation: "start",
|
|
191
|
+
error: error instanceof Error ? error.message : String(error)
|
|
192
|
+
});
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Stop the MCP server
|
|
198
|
+
*/
|
|
199
|
+
async stop() {
|
|
200
|
+
try {
|
|
201
|
+
await this.server.close();
|
|
202
|
+
if (this.config.logging && process.env.MCP_DEBUG) {
|
|
203
|
+
console.error("\u{1F6D1} SpecVerse MCP Server stopped");
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
this.eventEmitter.emit("error-occurred", {
|
|
207
|
+
operation: "stop",
|
|
208
|
+
error: error instanceof Error ? error.message : String(error)
|
|
209
|
+
});
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Methods expected by the main server
|
|
214
|
+
getEventEmitter() {
|
|
215
|
+
return this.eventEmitter;
|
|
216
|
+
}
|
|
217
|
+
async initialize() {
|
|
218
|
+
await this.start();
|
|
219
|
+
}
|
|
220
|
+
getServer() {
|
|
221
|
+
return this.server;
|
|
222
|
+
}
|
|
223
|
+
getMetrics() {
|
|
224
|
+
return {
|
|
225
|
+
resourceCount: this.resourcesProvider.getCachedResourceCount(),
|
|
226
|
+
cliIntegration: true
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
export {
|
|
231
|
+
MCPServerController
|
|
232
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class EventEmitter {
|
|
2
|
+
listeners = /* @__PURE__ */ new Map();
|
|
3
|
+
on(eventType, handler) {
|
|
4
|
+
if (!this.listeners.has(eventType)) {
|
|
5
|
+
this.listeners.set(eventType, []);
|
|
6
|
+
}
|
|
7
|
+
this.listeners.get(eventType).push(handler);
|
|
8
|
+
}
|
|
9
|
+
off(eventType, handler) {
|
|
10
|
+
const handlers = this.listeners.get(eventType);
|
|
11
|
+
if (handlers) {
|
|
12
|
+
const index = handlers.indexOf(handler);
|
|
13
|
+
if (index !== -1) {
|
|
14
|
+
handlers.splice(index, 1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async emit(eventType, data) {
|
|
19
|
+
const handlers = this.listeners.get(eventType);
|
|
20
|
+
if (handlers) {
|
|
21
|
+
const promises = handlers.map((handler) => {
|
|
22
|
+
try {
|
|
23
|
+
const result = handler(data);
|
|
24
|
+
return Promise.resolve(result);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error(`Error in event handler for ${eventType}:`, error);
|
|
27
|
+
return Promise.resolve();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
await Promise.allSettled(promises);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
removeAllListeners(eventType) {
|
|
34
|
+
if (eventType) {
|
|
35
|
+
this.listeners.delete(eventType);
|
|
36
|
+
} else {
|
|
37
|
+
this.listeners.clear();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
listenerCount(eventType) {
|
|
41
|
+
return this.listeners.get(eventType)?.length || 0;
|
|
42
|
+
}
|
|
43
|
+
eventNames() {
|
|
44
|
+
return Array.from(this.listeners.keys());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
EventEmitter
|
|
49
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SpecVerseCleanMCPServer } from "./server/mcp-server.js";
|
|
2
|
+
import { MCPServerController } from "./controllers/MCPServerController.js";
|
|
3
|
+
import { ResourcesProviderService } from "./services/ResourcesProviderService.js";
|
|
4
|
+
import { LibraryToolsService } from "./services/LibraryToolsService.js";
|
|
5
|
+
import { PromptToolsService } from "./services/PromptToolsService.js";
|
|
6
|
+
import { SpecVerseResourceModel } from "./models/SpecVerseResource.js";
|
|
7
|
+
import { LibrarySuggestionModel } from "./models/LibrarySuggestion.js";
|
|
8
|
+
import { EventEmitter } from "./events/EventEmitter.js";
|
|
9
|
+
export {
|
|
10
|
+
EventEmitter,
|
|
11
|
+
LibrarySuggestionModel,
|
|
12
|
+
LibraryToolsService,
|
|
13
|
+
MCPServerController,
|
|
14
|
+
PromptToolsService,
|
|
15
|
+
ResourcesProviderService,
|
|
16
|
+
SpecVerseCleanMCPServer,
|
|
17
|
+
SpecVerseResourceModel
|
|
18
|
+
};
|
package/dist/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.js
ADDED
|
File without changes
|
package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const LibrarySuggestionSchema = z.object({
|
|
3
|
+
name: z.string().min(1, "Name is required"),
|
|
4
|
+
path: z.string().min(1, "Path is required"),
|
|
5
|
+
type: z.enum(["deployment", "domain", "manifest", "type", "standard"]),
|
|
6
|
+
description: z.string().min(1, "Description is required"),
|
|
7
|
+
ai_description: z.string().min(1, "AI description is required"),
|
|
8
|
+
expansion_factor: z.number().min(1, "Expansion factor must be >= 1"),
|
|
9
|
+
complexity_level: z.enum(["low", "medium", "high"]),
|
|
10
|
+
best_for: z.array(z.string()).min(1, "Must specify at least one use case")
|
|
11
|
+
});
|
|
12
|
+
class LibrarySuggestionModel {
|
|
13
|
+
constructor(name, path, type, description, ai_description, expansion_factor, complexity_level, best_for) {
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.path = path;
|
|
16
|
+
this.type = type;
|
|
17
|
+
this.description = description;
|
|
18
|
+
this.ai_description = ai_description;
|
|
19
|
+
this.expansion_factor = expansion_factor;
|
|
20
|
+
this.complexity_level = complexity_level;
|
|
21
|
+
this.best_for = best_for;
|
|
22
|
+
}
|
|
23
|
+
static create(data) {
|
|
24
|
+
const validated = LibrarySuggestionSchema.parse(data);
|
|
25
|
+
return new LibrarySuggestionModel(
|
|
26
|
+
validated.name,
|
|
27
|
+
validated.path,
|
|
28
|
+
validated.type,
|
|
29
|
+
validated.description,
|
|
30
|
+
validated.ai_description,
|
|
31
|
+
validated.expansion_factor,
|
|
32
|
+
validated.complexity_level,
|
|
33
|
+
validated.best_for
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
static fromJson(json) {
|
|
37
|
+
const data = JSON.parse(json);
|
|
38
|
+
return this.create(data);
|
|
39
|
+
}
|
|
40
|
+
toJson() {
|
|
41
|
+
return JSON.stringify({
|
|
42
|
+
name: this.name,
|
|
43
|
+
path: this.path,
|
|
44
|
+
type: this.type,
|
|
45
|
+
description: this.description,
|
|
46
|
+
ai_description: this.ai_description,
|
|
47
|
+
expansion_factor: this.expansion_factor,
|
|
48
|
+
complexity_level: this.complexity_level,
|
|
49
|
+
best_for: this.best_for
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
matchesContext(context, scale) {
|
|
53
|
+
let score = 0;
|
|
54
|
+
const contextLower = context.toLowerCase();
|
|
55
|
+
for (const useCase of this.best_for) {
|
|
56
|
+
if (contextLower.includes(useCase.toLowerCase())) {
|
|
57
|
+
score += 2;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const scaleComplexity = this.getScaleComplexity(scale);
|
|
61
|
+
const complexityScore = this.getComplexityScore();
|
|
62
|
+
const complexityMatch = Math.abs(complexityScore - scaleComplexity);
|
|
63
|
+
score += Math.max(0, 3 - complexityMatch);
|
|
64
|
+
return score;
|
|
65
|
+
}
|
|
66
|
+
getScaleComplexity(scale) {
|
|
67
|
+
switch (scale) {
|
|
68
|
+
case "personal":
|
|
69
|
+
return 1;
|
|
70
|
+
case "business":
|
|
71
|
+
return 2;
|
|
72
|
+
case "enterprise":
|
|
73
|
+
return 3;
|
|
74
|
+
default:
|
|
75
|
+
return 2;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
getComplexityScore() {
|
|
79
|
+
switch (this.complexity_level) {
|
|
80
|
+
case "low":
|
|
81
|
+
return 1;
|
|
82
|
+
case "medium":
|
|
83
|
+
return 2;
|
|
84
|
+
case "high":
|
|
85
|
+
return 3;
|
|
86
|
+
default:
|
|
87
|
+
return 2;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
getRelevanceScore() {
|
|
91
|
+
return this.expansion_factor * this.getComplexityScore();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
LibrarySuggestionModel,
|
|
96
|
+
LibrarySuggestionSchema
|
|
97
|
+
};
|
package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const SpecVerseResourceSchema = z.object({
|
|
3
|
+
uri: z.string().min(1, "URI is required").regex(/^specverse:\/\//, "URI must start with specverse://"),
|
|
4
|
+
name: z.string().min(1, "Name is required"),
|
|
5
|
+
description: z.string().min(1, "Description is required"),
|
|
6
|
+
mimeType: z.string().min(1, "MIME type is required"),
|
|
7
|
+
content: z.string().optional(),
|
|
8
|
+
metadata: z.record(z.any()).optional()
|
|
9
|
+
});
|
|
10
|
+
class SpecVerseResourceModel {
|
|
11
|
+
constructor(uri, name, description, mimeType, content, metadata) {
|
|
12
|
+
this.uri = uri;
|
|
13
|
+
this.name = name;
|
|
14
|
+
this.description = description;
|
|
15
|
+
this.mimeType = mimeType;
|
|
16
|
+
this.content = content;
|
|
17
|
+
this.metadata = metadata;
|
|
18
|
+
}
|
|
19
|
+
static create(data) {
|
|
20
|
+
const validated = SpecVerseResourceSchema.parse(data);
|
|
21
|
+
return new SpecVerseResourceModel(
|
|
22
|
+
validated.uri,
|
|
23
|
+
validated.name,
|
|
24
|
+
validated.description,
|
|
25
|
+
validated.mimeType,
|
|
26
|
+
validated.content,
|
|
27
|
+
validated.metadata
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
static fromJson(json) {
|
|
31
|
+
const data = JSON.parse(json);
|
|
32
|
+
return this.create(data);
|
|
33
|
+
}
|
|
34
|
+
toJson() {
|
|
35
|
+
return JSON.stringify({
|
|
36
|
+
uri: this.uri,
|
|
37
|
+
name: this.name,
|
|
38
|
+
description: this.description,
|
|
39
|
+
mimeType: this.mimeType,
|
|
40
|
+
content: this.content,
|
|
41
|
+
metadata: this.metadata
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
withContent(content) {
|
|
45
|
+
return new SpecVerseResourceModel(
|
|
46
|
+
this.uri,
|
|
47
|
+
this.name,
|
|
48
|
+
this.description,
|
|
49
|
+
this.mimeType,
|
|
50
|
+
content,
|
|
51
|
+
this.metadata
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
matches(uri) {
|
|
55
|
+
return this.uri === uri;
|
|
56
|
+
}
|
|
57
|
+
isLoaded() {
|
|
58
|
+
return this.content !== void 0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
SpecVerseResourceModel,
|
|
63
|
+
SpecVerseResourceSchema
|
|
64
|
+
};
|