@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.
Files changed (57) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +184 -0
  3. package/dist/server/artifact-store.d.ts +13 -0
  4. package/dist/server/artifact-store.d.ts.map +1 -0
  5. package/dist/server/artifact-store.js +20 -0
  6. package/dist/server/artifact-store.js.map +1 -0
  7. package/dist/server/config.d.ts +13 -0
  8. package/dist/server/config.d.ts.map +1 -0
  9. package/dist/server/config.js +39 -0
  10. package/dist/server/config.js.map +1 -0
  11. package/dist/server/contracts.d.ts +95 -0
  12. package/dist/server/contracts.d.ts.map +1 -0
  13. package/dist/server/contracts.js +66 -0
  14. package/dist/server/contracts.js.map +1 -0
  15. package/dist/server/http-app.d.ts +11 -0
  16. package/dist/server/http-app.d.ts.map +1 -0
  17. package/dist/server/http-app.js +84 -0
  18. package/dist/server/http-app.js.map +1 -0
  19. package/dist/server/http.d.ts +3 -0
  20. package/dist/server/http.d.ts.map +1 -0
  21. package/dist/server/http.js +22 -0
  22. package/dist/server/http.js.map +1 -0
  23. package/dist/server/index.d.ts +7 -0
  24. package/dist/server/index.d.ts.map +1 -0
  25. package/dist/server/index.js +7 -0
  26. package/dist/server/index.js.map +1 -0
  27. package/dist/server/mcp-server.d.ts +4 -0
  28. package/dist/server/mcp-server.d.ts.map +1 -0
  29. package/dist/server/mcp-server.js +47 -0
  30. package/dist/server/mcp-server.js.map +1 -0
  31. package/dist/server/openui-validator.d.ts +6 -0
  32. package/dist/server/openui-validator.d.ts.map +1 -0
  33. package/dist/server/openui-validator.js +31 -0
  34. package/dist/server/openui-validator.js.map +1 -0
  35. package/dist/server/page-template.d.ts +2 -0
  36. package/dist/server/page-template.d.ts.map +1 -0
  37. package/dist/server/page-template.js +25 -0
  38. package/dist/server/page-template.js.map +1 -0
  39. package/dist/server/policy.d.ts +7 -0
  40. package/dist/server/policy.d.ts.map +1 -0
  41. package/dist/server/policy.js +41 -0
  42. package/dist/server/policy.js.map +1 -0
  43. package/dist/server/render-service.d.ts +13 -0
  44. package/dist/server/render-service.d.ts.map +1 -0
  45. package/dist/server/render-service.js +54 -0
  46. package/dist/server/render-service.js.map +1 -0
  47. package/dist/server/runtime.d.ts +8 -0
  48. package/dist/server/runtime.d.ts.map +1 -0
  49. package/dist/server/runtime.js +11 -0
  50. package/dist/server/runtime.js.map +1 -0
  51. package/dist/server/stdio.d.ts +3 -0
  52. package/dist/server/stdio.d.ts.map +1 -0
  53. package/dist/server/stdio.js +15 -0
  54. package/dist/server/stdio.js.map +1 -0
  55. package/dist/web/sidecar.css +1 -0
  56. package/dist/web/sidecar.js +103914 -0
  57. 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,3 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ //# sourceMappingURL=http.d.ts.map
@@ -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,7 @@
1
+ export * from './artifact-store.js';
2
+ export * from './contracts.js';
3
+ export * from './mcp-server.js';
4
+ export * from './openui-validator.js';
5
+ export * from './policy.js';
6
+ export * from './render-service.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -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,7 @@
1
+ export * from './artifact-store.js';
2
+ export * from './contracts.js';
3
+ export * from './mcp-server.js';
4
+ export * from './openui-validator.js';
5
+ export * from './policy.js';
6
+ export * from './render-service.js';
7
+ //# sourceMappingURL=index.js.map
@@ -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,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { RenderOpenUiService } from './render-service.js';
3
+ export declare function createOpenUiMcpServer(renderService: RenderOpenUiService): McpServer;
4
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -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,6 @@
1
+ export declare class OpenUiDocumentError extends Error {
2
+ readonly details: string[];
3
+ constructor(details: string[]);
4
+ }
5
+ export declare function validateOpenUiDocument(source: string): void;
6
+ //# sourceMappingURL=openui-validator.d.ts.map
@@ -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,2 @@
1
+ export declare function createSidecarPageHtml(artifactId: string, title: string): string;
2
+ //# sourceMappingURL=page-template.d.ts.map
@@ -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('<', '&lt;')
5
+ .replaceAll('>', '&gt;')
6
+ .replaceAll('"', '&quot;')
7
+ .replaceAll("'", '&#039;');
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,3 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ //# sourceMappingURL=stdio.d.ts.map
@@ -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}