@nuwax-ai/openui-mcp 0.1.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/LICENSE +190 -0
- package/README.md +184 -0
- package/dist/server/artifact-store.d.ts +13 -0
- package/dist/server/artifact-store.d.ts.map +1 -0
- package/dist/server/artifact-store.js +20 -0
- package/dist/server/artifact-store.js.map +1 -0
- package/dist/server/config.d.ts +13 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +39 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/contracts.d.ts +95 -0
- package/dist/server/contracts.d.ts.map +1 -0
- package/dist/server/contracts.js +66 -0
- package/dist/server/contracts.js.map +1 -0
- package/dist/server/http-app.d.ts +11 -0
- package/dist/server/http-app.d.ts.map +1 -0
- package/dist/server/http-app.js +84 -0
- package/dist/server/http-app.js.map +1 -0
- package/dist/server/http.d.ts +3 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +22 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +7 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp-server.d.ts +4 -0
- package/dist/server/mcp-server.d.ts.map +1 -0
- package/dist/server/mcp-server.js +47 -0
- package/dist/server/mcp-server.js.map +1 -0
- package/dist/server/openui-validator.d.ts +6 -0
- package/dist/server/openui-validator.d.ts.map +1 -0
- package/dist/server/openui-validator.js +31 -0
- package/dist/server/openui-validator.js.map +1 -0
- package/dist/server/page-template.d.ts +2 -0
- package/dist/server/page-template.d.ts.map +1 -0
- package/dist/server/page-template.js +25 -0
- package/dist/server/page-template.js.map +1 -0
- package/dist/server/policy.d.ts +7 -0
- package/dist/server/policy.d.ts.map +1 -0
- package/dist/server/policy.js +41 -0
- package/dist/server/policy.js.map +1 -0
- package/dist/server/render-service.d.ts +13 -0
- package/dist/server/render-service.d.ts.map +1 -0
- package/dist/server/render-service.js +54 -0
- package/dist/server/render-service.js.map +1 -0
- package/dist/server/runtime.d.ts +8 -0
- package/dist/server/runtime.d.ts.map +1 -0
- package/dist/server/runtime.js +11 -0
- package/dist/server/runtime.js.map +1 -0
- package/dist/server/stdio.d.ts +3 -0
- package/dist/server/stdio.d.ts.map +1 -0
- package/dist/server/stdio.js +15 -0
- package/dist/server/stdio.js.map +1 -0
- package/dist/web/sidecar.css +1 -0
- package/dist/web/sidecar.js +103914 -0
- package/package.json +89 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import { createOpenUiMcpServer } from './mcp-server.js';
|
|
7
|
+
import { createSidecarPageHtml } from './page-template.js';
|
|
8
|
+
function requestHost(request) {
|
|
9
|
+
return (request.headers.host ?? '').split(':')[0] ?? '';
|
|
10
|
+
}
|
|
11
|
+
function addSecurityHeaders(response, frameAncestors) {
|
|
12
|
+
response.setHeader('Referrer-Policy', 'no-referrer');
|
|
13
|
+
response.setHeader('X-Content-Type-Options', 'nosniff');
|
|
14
|
+
response.setHeader('Content-Security-Policy', `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors ${frameAncestors.join(' ')}`);
|
|
15
|
+
}
|
|
16
|
+
export function createHttpApp(dependencies) {
|
|
17
|
+
const { config, renderService, store } = dependencies;
|
|
18
|
+
const app = express();
|
|
19
|
+
app.disable('x-powered-by');
|
|
20
|
+
app.use(express.json({ limit: '1mb' }));
|
|
21
|
+
app.use((request, response, next) => {
|
|
22
|
+
if (!config.allowedHosts.includes(requestHost(request))) {
|
|
23
|
+
response.status(421).json({ error: 'Untrusted Host header.' });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
next();
|
|
27
|
+
});
|
|
28
|
+
app.get('/healthz', (_request, response) => {
|
|
29
|
+
response.json({ status: 'ok', service: 'nuwax-openui-mcp' });
|
|
30
|
+
});
|
|
31
|
+
app.post('/mcp', async (request, response) => {
|
|
32
|
+
const server = createOpenUiMcpServer(renderService);
|
|
33
|
+
const transport = new StreamableHTTPServerTransport({
|
|
34
|
+
sessionIdGenerator: undefined,
|
|
35
|
+
enableJsonResponse: true,
|
|
36
|
+
});
|
|
37
|
+
response.on('close', () => {
|
|
38
|
+
void transport.close();
|
|
39
|
+
void server.close();
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
await server.connect(transport);
|
|
43
|
+
await transport.handleRequest(request, response, request.body);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (!response.headersSent) {
|
|
47
|
+
response.status(500).json({
|
|
48
|
+
error: error instanceof Error ? error.message : 'MCP request failed.',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
app.get('/openui/artifacts/:artifactId', async (request, response) => {
|
|
54
|
+
const artifact = await store.get(request.params.artifactId);
|
|
55
|
+
if (!artifact) {
|
|
56
|
+
response.status(404).json({ error: 'Artifact not found or expired.' });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
response.setHeader('Cache-Control', 'private, no-store');
|
|
60
|
+
response.json(artifact);
|
|
61
|
+
});
|
|
62
|
+
app.get('/openui/pages/:artifactId', async (request, response) => {
|
|
63
|
+
const artifact = await store.get(request.params.artifactId);
|
|
64
|
+
if (!artifact || artifact.presentation.mode !== 'sidecar') {
|
|
65
|
+
response.status(404).send('Artifact not found or expired.');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
addSecurityHeaders(response, config.frameAncestors);
|
|
69
|
+
response.setHeader('Cache-Control', 'private, no-store');
|
|
70
|
+
response
|
|
71
|
+
.type('html')
|
|
72
|
+
.send(createSidecarPageHtml(artifact.artifactId, artifact.title));
|
|
73
|
+
});
|
|
74
|
+
const moduleDirectory = dirname(fileURLToPath(import.meta.url));
|
|
75
|
+
const webAssetsDirectory = resolve(moduleDirectory, '../web');
|
|
76
|
+
if (existsSync(webAssetsDirectory)) {
|
|
77
|
+
app.use('/openui/assets', express.static(webAssetsDirectory, {
|
|
78
|
+
immutable: true,
|
|
79
|
+
maxAge: '1y',
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
return app;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=http-app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-app.js","sourceRoot":"","sources":["../../src/http-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { loadConfig } from './config.js';
|
|
4
|
+
import { createHttpApp } from './http-app.js';
|
|
5
|
+
import { createRuntime } from './runtime.js';
|
|
6
|
+
const config = loadConfig();
|
|
7
|
+
const runtime = createRuntime(config);
|
|
8
|
+
const app = createHttpApp({ config, ...runtime });
|
|
9
|
+
const server = app.listen(config.port, config.host, () => {
|
|
10
|
+
console.log(`nuwax-openui-mcp listening at ${config.baseUrl} (MCP: ${config.baseUrl}/mcp)`);
|
|
11
|
+
});
|
|
12
|
+
function shutdown() {
|
|
13
|
+
server.close((error) => {
|
|
14
|
+
if (error) {
|
|
15
|
+
console.error(error);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
process.on('SIGINT', shutdown);
|
|
21
|
+
process.on('SIGTERM', shutdown);
|
|
22
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AACtC,MAAM,GAAG,GAAG,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAElD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACvD,OAAO,CAAC,GAAG,CACT,iCAAiC,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,OAAO,OAAO,CAC/E,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,SAAS,QAAQ;IACf,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,mBAAmB,GACjC,SAAS,CAkDX"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { OPENUI_TOOL_NAME, openUiArtifactSchema, renderOpenUiInputSchema, } from './contracts.js';
|
|
4
|
+
import { OpenUiPolicyError } from './policy.js';
|
|
5
|
+
export function createOpenUiMcpServer(renderService) {
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: 'nuwax-openui-mcp',
|
|
8
|
+
version: '0.1.0',
|
|
9
|
+
});
|
|
10
|
+
server.registerTool(OPENUI_TOOL_NAME, {
|
|
11
|
+
title: 'Render Nuwax OpenUI',
|
|
12
|
+
description: 'Validate and publish an OpenUI Lang document for Nuwax. Use inline for compact UI inside the tool block, or sidecar for a full page opened in the Nuwax preview iframe.',
|
|
13
|
+
inputSchema: renderOpenUiInputSchema,
|
|
14
|
+
outputSchema: openUiArtifactSchema,
|
|
15
|
+
}, async (input) => {
|
|
16
|
+
try {
|
|
17
|
+
const artifact = await renderService.render(input);
|
|
18
|
+
return {
|
|
19
|
+
content: [
|
|
20
|
+
{
|
|
21
|
+
type: 'text',
|
|
22
|
+
text: artifact.presentation.mode === 'inline'
|
|
23
|
+
? `OpenUI inline artifact ready: ${artifact.artifactId}`
|
|
24
|
+
: `OpenUI sidecar artifact ready: ${artifact.page?.url}`,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
structuredContent: artifact,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
const message = error instanceof z.ZodError
|
|
32
|
+
? z.prettifyError(error)
|
|
33
|
+
: error instanceof Error
|
|
34
|
+
? error.message
|
|
35
|
+
: 'Unknown OpenUI validation error.';
|
|
36
|
+
return {
|
|
37
|
+
isError: true,
|
|
38
|
+
content: [{ type: 'text', text: message }],
|
|
39
|
+
_meta: error instanceof OpenUiPolicyError
|
|
40
|
+
? { code: error.code }
|
|
41
|
+
: { code: 'invalid-openui-document' },
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return server;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,UAAU,qBAAqB,CACnC,aAAkC;IAElC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,yKAAyK;QAC3K,WAAW,EAAE,uBAAuB;QACpC,YAAY,EAAE,oBAAoB;KACnC,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnD,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EACF,QAAQ,CAAC,YAAY,CAAC,IAAI,KAAK,QAAQ;4BACrC,CAAC,CAAC,iCAAiC,QAAQ,CAAC,UAAU,EAAE;4BACxD,CAAC,CAAC,kCAAkC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;qBAC7D;iBACF;gBACD,iBAAiB,EAAE,QAAQ;aAC5B,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GACX,KAAK,YAAY,CAAC,CAAC,QAAQ;gBACzB,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;gBACxB,CAAC,CAAC,KAAK,YAAY,KAAK;oBACtB,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,kCAAkC,CAAC;YAC3C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBACnD,KAAK,EACH,KAAK,YAAY,iBAAiB;oBAChC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;oBACtB,CAAC,CAAC,EAAE,IAAI,EAAE,yBAAyB,EAAE;aAC1C,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openui-validator.d.ts","sourceRoot":"","sources":["../../src/openui-validator.ts"],"names":[],"mappings":"AAKA,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,OAAO,EAAE,MAAM,EAAE;gBAAjB,OAAO,EAAE,MAAM,EAAE;CAI9C;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAiB3D"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createParser } from '@openuidev/react-lang';
|
|
2
|
+
import { openuiLibrary } from '@openuidev/react-ui/genui-lib';
|
|
3
|
+
const parser = createParser(openuiLibrary.toJSONSchema(), 'Stack');
|
|
4
|
+
export class OpenUiDocumentError extends Error {
|
|
5
|
+
details;
|
|
6
|
+
constructor(details) {
|
|
7
|
+
super(`Invalid OpenUI document: ${details.join('; ')}`);
|
|
8
|
+
this.details = details;
|
|
9
|
+
this.name = 'OpenUiDocumentError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function validateOpenUiDocument(source) {
|
|
13
|
+
const result = parser.parse(source);
|
|
14
|
+
const errors = result.meta.errors.map((error) => error.message);
|
|
15
|
+
if (!result.root)
|
|
16
|
+
errors.push('The document has no renderable root.');
|
|
17
|
+
if (result.root && result.root.typeName !== 'Stack') {
|
|
18
|
+
errors.push('The root component must be Stack.');
|
|
19
|
+
}
|
|
20
|
+
if (result.meta.incomplete)
|
|
21
|
+
errors.push('The document is incomplete.');
|
|
22
|
+
if (result.meta.unresolved.length > 0) {
|
|
23
|
+
errors.push(`Unresolved references: ${result.meta.unresolved.join(', ')}.`);
|
|
24
|
+
}
|
|
25
|
+
if (result.meta.orphaned.length > 0) {
|
|
26
|
+
errors.push(`Orphaned statements: ${result.meta.orphaned.join(', ')}.`);
|
|
27
|
+
}
|
|
28
|
+
if (errors.length > 0)
|
|
29
|
+
throw new OpenUiDocumentError(errors);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=openui-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openui-validator.js","sourceRoot":"","sources":["../../src/openui-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;AAEnE,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAChB;IAA5B,YAA4B,OAAiB;QAC3C,KAAK,CAAC,4BAA4B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAD9B,YAAO,GAAP,OAAO,CAAU;QAE3C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEhE,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IACtE,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU;QAAE,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACvE,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,0BAA0B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,wBAAwB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-template.d.ts","sourceRoot":"","sources":["../../src/page-template.ts"],"names":[],"mappings":"AASA,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GACZ,MAAM,CAeR"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function escapeHtml(value) {
|
|
2
|
+
return value
|
|
3
|
+
.replaceAll('&', '&')
|
|
4
|
+
.replaceAll('<', '<')
|
|
5
|
+
.replaceAll('>', '>')
|
|
6
|
+
.replaceAll('"', '"')
|
|
7
|
+
.replaceAll("'", ''');
|
|
8
|
+
}
|
|
9
|
+
export function createSidecarPageHtml(artifactId, title) {
|
|
10
|
+
return `<!doctype html>
|
|
11
|
+
<html lang="en">
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="UTF-8" />
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
15
|
+
<meta name="referrer" content="no-referrer" />
|
|
16
|
+
<title>${escapeHtml(title)}</title>
|
|
17
|
+
<link rel="stylesheet" href="/openui/assets/sidecar.css" />
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<main id="root" data-artifact-id="${escapeHtml(artifactId)}"></main>
|
|
21
|
+
<script type="module" src="/openui/assets/sidecar.js"></script>
|
|
22
|
+
</body>
|
|
23
|
+
</html>`;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=page-template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-template.js","sourceRoot":"","sources":["../../src/page-template.ts"],"names":[],"mappings":"AAAA,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,UAAkB,EAClB,KAAa;IAEb,OAAO;;;;;;aAMI,UAAU,CAAC,KAAK,CAAC;;;;wCAIU,UAAU,CAAC,UAAU,CAAC;;;QAGtD,CAAC;AACT,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RenderOpenUiInput } from './contracts.js';
|
|
2
|
+
export declare class OpenUiPolicyError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
constructor(code: string, message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare function enforceOpenUiPolicy(input: RenderOpenUiInput): void;
|
|
7
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAcxD,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAoClE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const FORBIDDEN_SOURCE_PATTERNS = [
|
|
2
|
+
{ code: 'raw-script', pattern: /<\s*script\b/i },
|
|
3
|
+
{ code: 'javascript-url', pattern: /javascript\s*:/i },
|
|
4
|
+
{ code: 'html-data-url', pattern: /data\s*:\s*text\/html/i },
|
|
5
|
+
{ code: 'dynamic-import', pattern: /\bimport\s*\(/i },
|
|
6
|
+
{ code: 'eval', pattern: /\beval\s*\(/i },
|
|
7
|
+
{ code: 'function-constructor', pattern: /\bFunction\s*\(/ },
|
|
8
|
+
];
|
|
9
|
+
const MAX_LINES = 2_000;
|
|
10
|
+
const MAX_BINDINGS = 32;
|
|
11
|
+
export class OpenUiPolicyError extends Error {
|
|
12
|
+
code;
|
|
13
|
+
constructor(code, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.name = 'OpenUiPolicyError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function enforceOpenUiPolicy(input) {
|
|
20
|
+
const lineCount = input.document.source.split(/\r?\n/).length;
|
|
21
|
+
if (lineCount > MAX_LINES) {
|
|
22
|
+
throw new OpenUiPolicyError('too-many-lines', `OpenUI document exceeds ${MAX_LINES} lines.`);
|
|
23
|
+
}
|
|
24
|
+
if (input.bindings.tools.length > MAX_BINDINGS) {
|
|
25
|
+
throw new OpenUiPolicyError('too-many-bindings', `OpenUI document exceeds ${MAX_BINDINGS} tool bindings.`);
|
|
26
|
+
}
|
|
27
|
+
const duplicateBindings = new Set();
|
|
28
|
+
for (const binding of input.bindings.tools) {
|
|
29
|
+
const key = `${binding.serverId}:${binding.toolName}`;
|
|
30
|
+
if (duplicateBindings.has(key)) {
|
|
31
|
+
throw new OpenUiPolicyError('duplicate-binding', `Duplicate MCP binding: ${key}.`);
|
|
32
|
+
}
|
|
33
|
+
duplicateBindings.add(key);
|
|
34
|
+
}
|
|
35
|
+
for (const forbidden of FORBIDDEN_SOURCE_PATTERNS) {
|
|
36
|
+
if (forbidden.pattern.test(input.document.source)) {
|
|
37
|
+
throw new OpenUiPolicyError(forbidden.code, `OpenUI document contains forbidden content: ${forbidden.code}.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/policy.ts"],"names":[],"mappings":"AAEA,MAAM,yBAAyB,GAA6C;IAC1E,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE;IAChD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,iBAAiB,EAAE;IACtD,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,wBAAwB,EAAE;IAC5D,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,EAAE;IACrD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE;IACzC,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,iBAAiB,EAAE;CAC7D,CAAC;AAEF,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IADlB,YACkB,IAAY,EAC5B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAQ;QAI5B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAwB;IAC1D,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAC9D,IAAI,SAAS,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,iBAAiB,CACzB,gBAAgB,EAChB,2BAA2B,SAAS,SAAS,CAC9C,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;QAC/C,MAAM,IAAI,iBAAiB,CACzB,mBAAmB,EACnB,2BAA2B,YAAY,iBAAiB,CACzD,CAAC;IACJ,CAAC;IAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtD,IAAI,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,iBAAiB,CACzB,mBAAmB,EACnB,0BAA0B,GAAG,GAAG,CACjC,CAAC;QACJ,CAAC;QACD,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,yBAAyB,EAAE,CAAC;QAClD,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,iBAAiB,CACzB,SAAS,CAAC,IAAI,EACd,+CAA+C,SAAS,CAAC,IAAI,GAAG,CACjE,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type OpenUiArtifact } from './contracts.js';
|
|
2
|
+
import type { ArtifactStore } from './artifact-store.js';
|
|
3
|
+
export interface RenderServiceOptions {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
artifactTtlSeconds: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class RenderOpenUiService {
|
|
8
|
+
private readonly store;
|
|
9
|
+
private readonly options;
|
|
10
|
+
constructor(store: ArtifactStore, options: RenderServiceOptions);
|
|
11
|
+
render(rawInput: unknown): Promise<OpenUiArtifact>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=render-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-service.d.ts","sourceRoot":"","sources":["../../src/render-service.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,cAAc,EAEpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAUD,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,oBAAoB;IAG1C,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;CAwCzD"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { openUiArtifactSchema, renderOpenUiInputSchema, } from './contracts.js';
|
|
3
|
+
import { validateOpenUiDocument } from './openui-validator.js';
|
|
4
|
+
import { enforceOpenUiPolicy } from './policy.js';
|
|
5
|
+
function createDigest(source) {
|
|
6
|
+
return `sha256:${createHash('sha256').update(source).digest('hex')}`;
|
|
7
|
+
}
|
|
8
|
+
function trimTrailingSlash(value) {
|
|
9
|
+
return value.replace(/\/+$/, '');
|
|
10
|
+
}
|
|
11
|
+
export class RenderOpenUiService {
|
|
12
|
+
store;
|
|
13
|
+
options;
|
|
14
|
+
constructor(store, options) {
|
|
15
|
+
this.store = store;
|
|
16
|
+
this.options = options;
|
|
17
|
+
}
|
|
18
|
+
async render(rawInput) {
|
|
19
|
+
const input = renderOpenUiInputSchema.parse(rawInput);
|
|
20
|
+
enforceOpenUiPolicy(input);
|
|
21
|
+
validateOpenUiDocument(input.document.source);
|
|
22
|
+
const artifactId = randomUUID();
|
|
23
|
+
const createdAt = new Date();
|
|
24
|
+
const expiresAt = new Date(createdAt.getTime() + this.options.artifactTtlSeconds * 1_000);
|
|
25
|
+
const artifact = {
|
|
26
|
+
type: 'nuwax.openui',
|
|
27
|
+
schemaVersion: input.schemaVersion,
|
|
28
|
+
artifactId,
|
|
29
|
+
title: input.title,
|
|
30
|
+
presentation: input.presentation,
|
|
31
|
+
document: {
|
|
32
|
+
...input.document,
|
|
33
|
+
digest: createDigest(input.document.source),
|
|
34
|
+
},
|
|
35
|
+
bindings: input.bindings,
|
|
36
|
+
fallback: input.fallback,
|
|
37
|
+
createdAt: createdAt.toISOString(),
|
|
38
|
+
expiresAt: expiresAt.toISOString(),
|
|
39
|
+
...(input.presentation.mode === 'sidecar'
|
|
40
|
+
? {
|
|
41
|
+
page: {
|
|
42
|
+
url: `${trimTrailingSlash(this.options.baseUrl)}/openui/pages/${artifactId}`,
|
|
43
|
+
expiresAt: expiresAt.toISOString(),
|
|
44
|
+
sandboxProfile: 'openui-sidecar-v1',
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
: {}),
|
|
48
|
+
};
|
|
49
|
+
const validatedArtifact = openUiArtifactSchema.parse(artifact);
|
|
50
|
+
await this.store.put(validatedArtifact);
|
|
51
|
+
return validatedArtifact;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=render-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-service.js","sourceRoot":"","sources":["../../src/render-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EACL,oBAAoB,EACpB,uBAAuB,GAGxB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAOlD,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,OAAO,mBAAmB;IAEX;IACA;IAFnB,YACmB,KAAoB,EACpB,OAA6B;QAD7B,UAAK,GAAL,KAAK,CAAe;QACpB,YAAO,GAAP,OAAO,CAAsB;IAC7C,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,QAAiB;QAC5B,MAAM,KAAK,GAAsB,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACzE,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC3B,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE9C,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,IAAI,CACxB,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,GAAG,KAAK,CAC9D,CAAC;QAEF,MAAM,QAAQ,GAAmB;YAC/B,IAAI,EAAE,cAAc;YACpB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,UAAU;YACV,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,QAAQ,EAAE;gBACR,GAAG,KAAK,CAAC,QAAQ;gBACjB,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;aAC5C;YACD,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;YAClC,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;YAClC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,KAAK,SAAS;gBACvC,CAAC,CAAC;oBACE,IAAI,EAAE;wBACJ,GAAG,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,UAAU,EAAE;wBAC5E,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;wBAClC,cAAc,EAAE,mBAA4B;qBAC7C;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QAEF,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/D,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QACxC,OAAO,iBAAiB,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { InMemoryArtifactStore } from './artifact-store.js';
|
|
2
|
+
import type { AppConfig } from './config.js';
|
|
3
|
+
import { RenderOpenUiService } from './render-service.js';
|
|
4
|
+
export declare function createRuntime(config: AppConfig): {
|
|
5
|
+
store: InMemoryArtifactStore;
|
|
6
|
+
renderService: RenderOpenUiService;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS;;;EAQ9C"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InMemoryArtifactStore } from './artifact-store.js';
|
|
2
|
+
import { RenderOpenUiService } from './render-service.js';
|
|
3
|
+
export function createRuntime(config) {
|
|
4
|
+
const store = new InMemoryArtifactStore();
|
|
5
|
+
const renderService = new RenderOpenUiService(store, {
|
|
6
|
+
baseUrl: config.baseUrl,
|
|
7
|
+
artifactTtlSeconds: config.artifactTtlSeconds,
|
|
8
|
+
});
|
|
9
|
+
return { store, renderService };
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC7C,MAAM,KAAK,GAAG,IAAI,qBAAqB,EAAE,CAAC;IAC1C,MAAM,aAAa,GAAG,IAAI,mBAAmB,CAAC,KAAK,EAAE;QACnD,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;KAC9C,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/stdio.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
import { createOpenUiMcpServer } from './mcp-server.js';
|
|
6
|
+
import { createRuntime } from './runtime.js';
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
const { renderService } = createRuntime(config);
|
|
9
|
+
const server = createOpenUiMcpServer(renderService);
|
|
10
|
+
const transport = new StdioServerTransport();
|
|
11
|
+
await server.connect(transport);
|
|
12
|
+
process.on('SIGINT', () => {
|
|
13
|
+
void server.close().finally(() => process.exit(0));
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/stdio.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,EAAE,aAAa,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAChD,MAAM,MAAM,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;AACpD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{color:#172033;background:#f6f8fb;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-synthesis:none;text-rendering:optimizeLegibility}*{box-sizing:border-box}html,body,#root{min-height:100%;margin:0}body{min-width:320px}.openui-sidecar{width:min(1440px,100%);min-height:100vh;margin:0 auto;padding:24px}.openui-state{display:grid;min-height:100vh;place-items:center;color:#647089}.openui-error{color:#b42318}
|