claude-flow-novice 2.14.35 → 2.14.37
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/.claude/commands/CFN_LOOP_TASK_MODE.md +1 -1
- package/.claude/commands/cfn-loop-cli.md +491 -456
- package/.claude/commands/switch-api.md +1 -1
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +2 -1
- package/.claude/skills/cfn-loop-validation/config.json +2 -2
- package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +220 -220
- package/claude-assets/agents/README-AGENT_LIFECYCLE.md +37 -10
- package/claude-assets/agents/README-VALIDATION.md +0 -8
- package/claude-assets/agents/cfn-dev-team/README.md +0 -8
- package/claude-assets/agents/cfn-dev-team/coordinators/README.md +1 -9
- package/claude-assets/agents/cfn-dev-team/developers/README.md +1 -9
- package/claude-assets/agents/cfn-dev-team/documentation/README-VALIDATION.md +0 -8
- package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md +0 -10
- package/claude-assets/agents/cfn-dev-team/reviewers/README.md +1 -9
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/quality-metrics.md +0 -10
- package/claude-assets/agents/cfn-dev-team/test-agent.md +0 -10
- package/claude-assets/agents/cfn-dev-team/testers/README.md +1 -9
- package/claude-assets/agents/csuite/cto-agent.md +0 -10
- package/claude-assets/agents/custom/cfn-system-expert.md +1 -128
- package/claude-assets/agents/custom/claude-code-expert.md +151 -2
- package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +39 -3
- package/claude-assets/agents/docker-team/csuite/c-suite-template.md +1 -5
- package/claude-assets/agents/docker-team/infrastructure/team-coordinator-template.md +1 -5
- package/claude-assets/agents/marketing_hybrid/cost_tracker.md +0 -10
- package/claude-assets/agents/marketing_hybrid/docker_deployer.md +0 -10
- package/claude-assets/agents/marketing_hybrid/zai_worker_spawner.md +0 -10
- package/claude-assets/commands/CFN_LOOP_TASK_MODE.md +1 -1
- package/claude-assets/commands/cfn-loop-cli.md +491 -456
- package/claude-assets/commands/switch-api.md +1 -1
- package/claude-assets/skills/cfn-error-logging/SKILL.md +339 -0
- package/claude-assets/skills/cfn-error-logging/cleanup-error-logs.sh +334 -0
- package/claude-assets/skills/cfn-error-logging/integrate-cli.sh +232 -0
- package/claude-assets/skills/cfn-error-logging/integrate-docker.sh +294 -0
- package/claude-assets/skills/cfn-error-logging/invoke-error-logging.sh +839 -0
- package/claude-assets/skills/cfn-error-logging/test-error-logging.sh +475 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +2 -1
- package/claude-assets/skills/cfn-loop-validation/config.json +2 -2
- package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +326 -322
- package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +220 -220
- package/claude-assets/skills/cfn-task-config-init/initialize-config.sh +2 -2
- package/claude-assets/skills/cfn-task-mode-sanitize/task-mode-env-sanitizer.sh +224 -181
- package/claude-assets/skills/cfn-validation-runner-instrumentation/wrapped-executor.sh +235 -271
- package/dist/agents/agent-loader.js +467 -133
- package/dist/agents/agent-loader.js.map +1 -1
- package/dist/cli/config-manager.js +109 -91
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/hello.js +27 -3
- package/dist/hello.js.map +1 -1
- package/dist/server.js +194 -0
- package/dist/server.js.map +1 -0
- package/dist/server.test.js +207 -0
- package/dist/server.test.js.map +1 -0
- package/package.json +2 -1
- package/scripts/docker-build-mcp.sh +155 -0
- package/scripts/docker-test-mcp.sh +260 -0
- package/scripts/mcp-health-check.sh +123 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { hello, healthCheck, createApiResponse } from './hello.js';
|
|
3
|
+
const app = express();
|
|
4
|
+
const PORT = process.env.PORT || 3000;
|
|
5
|
+
// Middleware for JSON parsing and security
|
|
6
|
+
app.use(express.json());
|
|
7
|
+
app.use(express.urlencoded({
|
|
8
|
+
extended: true
|
|
9
|
+
}));
|
|
10
|
+
// Security headers middleware
|
|
11
|
+
app.use((req, res, next)=>{
|
|
12
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
13
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
14
|
+
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
15
|
+
next();
|
|
16
|
+
});
|
|
17
|
+
// Request logging middleware
|
|
18
|
+
app.use((req, res, next)=>{
|
|
19
|
+
console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
|
|
20
|
+
next();
|
|
21
|
+
});
|
|
22
|
+
// API Routes
|
|
23
|
+
/**
|
|
24
|
+
* GET /api/hello
|
|
25
|
+
* Basic hello world endpoint
|
|
26
|
+
*/ app.get('/api/hello', (req, res)=>{
|
|
27
|
+
try {
|
|
28
|
+
const message = hello();
|
|
29
|
+
const response = createApiResponse({
|
|
30
|
+
greeting: message
|
|
31
|
+
});
|
|
32
|
+
res.json(response);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('Error in /api/hello:', error);
|
|
35
|
+
res.status(500).json({
|
|
36
|
+
success: false,
|
|
37
|
+
message: 'Internal server error',
|
|
38
|
+
timestamp: new Date().toISOString()
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* GET /api/hello/:name
|
|
44
|
+
* Personalized hello endpoint
|
|
45
|
+
*/ app.get('/api/hello/:name', (req, res)=>{
|
|
46
|
+
try {
|
|
47
|
+
const { name } = req.params;
|
|
48
|
+
// Input validation
|
|
49
|
+
if (!name || typeof name !== 'string' || name.length > 100) {
|
|
50
|
+
return res.status(400).json({
|
|
51
|
+
success: false,
|
|
52
|
+
message: 'Invalid name parameter',
|
|
53
|
+
timestamp: new Date().toISOString()
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// Sanitize input (remove potential XSS)
|
|
57
|
+
const sanitizedName = name.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
|
|
58
|
+
const message = hello(sanitizedName);
|
|
59
|
+
const response = createApiResponse({
|
|
60
|
+
greeting: message,
|
|
61
|
+
name: sanitizedName
|
|
62
|
+
});
|
|
63
|
+
res.json(response);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Error in /api/hello/:name:', error);
|
|
66
|
+
res.status(500).json({
|
|
67
|
+
success: false,
|
|
68
|
+
message: 'Internal server error',
|
|
69
|
+
timestamp: new Date().toISOString()
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* GET /api/health
|
|
75
|
+
* Health check endpoint
|
|
76
|
+
*/ app.get('/api/health', (req, res)=>{
|
|
77
|
+
try {
|
|
78
|
+
const health = healthCheck();
|
|
79
|
+
const response = createApiResponse(health, 'Service is healthy');
|
|
80
|
+
res.json(response);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error('Error in /api/health:', error);
|
|
83
|
+
res.status(500).json({
|
|
84
|
+
success: false,
|
|
85
|
+
message: 'Health check failed',
|
|
86
|
+
timestamp: new Date().toISOString()
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* POST /api/hello
|
|
92
|
+
* Hello endpoint with POST body
|
|
93
|
+
*/ app.post('/api/hello', (req, res)=>{
|
|
94
|
+
try {
|
|
95
|
+
const { name, language } = req.body;
|
|
96
|
+
// Input validation
|
|
97
|
+
if (name && (typeof name !== 'string' || name.length > 100)) {
|
|
98
|
+
return res.status(400).json({
|
|
99
|
+
success: false,
|
|
100
|
+
message: 'Invalid name in request body',
|
|
101
|
+
timestamp: new Date().toISOString()
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Support for different languages
|
|
105
|
+
let greeting = 'Hello';
|
|
106
|
+
if (language && typeof language === 'string') {
|
|
107
|
+
const greetings = {
|
|
108
|
+
'es': 'Hola',
|
|
109
|
+
'fr': 'Bonjour',
|
|
110
|
+
'de': 'Hallo',
|
|
111
|
+
'it': 'Ciao',
|
|
112
|
+
'pt': 'Olá',
|
|
113
|
+
'ja': 'こんにちは',
|
|
114
|
+
'zh': '你好',
|
|
115
|
+
'hi': 'नमस्ते',
|
|
116
|
+
'ar': 'مرحبا'
|
|
117
|
+
};
|
|
118
|
+
greeting = greetings[language.toLowerCase()] || greeting;
|
|
119
|
+
}
|
|
120
|
+
const sanitizedName = name ? name.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') : 'World';
|
|
121
|
+
const message = `${greeting} ${sanitizedName}!`;
|
|
122
|
+
const response = createApiResponse({
|
|
123
|
+
greeting: message,
|
|
124
|
+
name: sanitizedName,
|
|
125
|
+
language: language || 'en'
|
|
126
|
+
});
|
|
127
|
+
res.json(response);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error('Error in POST /api/hello:', error);
|
|
130
|
+
res.status(500).json({
|
|
131
|
+
success: false,
|
|
132
|
+
message: 'Internal server error',
|
|
133
|
+
timestamp: new Date().toISOString()
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* GET / - Root endpoint
|
|
139
|
+
*/ app.get('/', (req, res)=>{
|
|
140
|
+
res.json({
|
|
141
|
+
success: true,
|
|
142
|
+
message: 'Hello World Backend Service',
|
|
143
|
+
version: '1.0.0',
|
|
144
|
+
endpoints: [
|
|
145
|
+
'GET /api/hello - Basic hello world',
|
|
146
|
+
'GET /api/hello/:name - Personalized greeting',
|
|
147
|
+
'POST /api/hello - Greeting with language support',
|
|
148
|
+
'GET /api/health - Health check'
|
|
149
|
+
],
|
|
150
|
+
timestamp: new Date().toISOString()
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
/**
|
|
154
|
+
* 404 handler
|
|
155
|
+
*/ app.use('*', (req, res)=>{
|
|
156
|
+
res.status(404).json({
|
|
157
|
+
success: false,
|
|
158
|
+
message: 'Endpoint not found',
|
|
159
|
+
path: req.originalUrl,
|
|
160
|
+
timestamp: new Date().toISOString()
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
/**
|
|
164
|
+
* Global error handler
|
|
165
|
+
*/ app.use((error, req, res, next)=>{
|
|
166
|
+
console.error('Unhandled error:', error);
|
|
167
|
+
res.status(500).json({
|
|
168
|
+
success: false,
|
|
169
|
+
message: 'Internal server error',
|
|
170
|
+
timestamp: new Date().toISOString()
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
// Start server
|
|
174
|
+
const server = app.listen(PORT, ()=>{
|
|
175
|
+
console.log(`🚀 Hello World Backend Service running on port ${PORT}`);
|
|
176
|
+
console.log(`📖 API Documentation: http://localhost:${PORT}/`);
|
|
177
|
+
console.log(`❤️ Health Check: http://localhost:${PORT}/api/health`);
|
|
178
|
+
});
|
|
179
|
+
// Graceful shutdown
|
|
180
|
+
process.on('SIGTERM', ()=>{
|
|
181
|
+
console.log('SIGTERM received, shutting down gracefully');
|
|
182
|
+
server.close(()=>{
|
|
183
|
+
console.log('Process terminated');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
process.on('SIGINT', ()=>{
|
|
187
|
+
console.log('SIGINT received, shutting down gracefully');
|
|
188
|
+
server.close(()=>{
|
|
189
|
+
console.log('Process terminated');
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
export default app;
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.js"],"sourcesContent":["import express from 'express';\nimport { hello, healthCheck, createApiResponse } from './hello.js';\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\n\n// Middleware for JSON parsing and security\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\n\n// Security headers middleware\napp.use((req, res, next) => {\n res.setHeader('X-Content-Type-Options', 'nosniff');\n res.setHeader('X-Frame-Options', 'DENY');\n res.setHeader('X-XSS-Protection', '1; mode=block');\n next();\n});\n\n// Request logging middleware\napp.use((req, res, next) => {\n console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);\n next();\n});\n\n// API Routes\n\n/**\n * GET /api/hello\n * Basic hello world endpoint\n */\napp.get('/api/hello', (req, res) => {\n try {\n const message = hello();\n const response = createApiResponse({ greeting: message });\n res.json(response);\n } catch (error) {\n console.error('Error in /api/hello:', error);\n res.status(500).json({\n success: false,\n message: 'Internal server error',\n timestamp: new Date().toISOString()\n });\n }\n});\n\n/**\n * GET /api/hello/:name\n * Personalized hello endpoint\n */\napp.get('/api/hello/:name', (req, res) => {\n try {\n const { name } = req.params;\n \n // Input validation\n if (!name || typeof name !== 'string' || name.length > 100) {\n return res.status(400).json({\n success: false,\n message: 'Invalid name parameter',\n timestamp: new Date().toISOString()\n });\n }\n\n // Sanitize input (remove potential XSS)\n const sanitizedName = name.replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '');\n const message = hello(sanitizedName);\n const response = createApiResponse({ \n greeting: message,\n name: sanitizedName \n });\n res.json(response);\n } catch (error) {\n console.error('Error in /api/hello/:name:', error);\n res.status(500).json({\n success: false,\n message: 'Internal server error',\n timestamp: new Date().toISOString()\n });\n }\n});\n\n/**\n * GET /api/health\n * Health check endpoint\n */\napp.get('/api/health', (req, res) => {\n try {\n const health = healthCheck();\n const response = createApiResponse(health, 'Service is healthy');\n res.json(response);\n } catch (error) {\n console.error('Error in /api/health:', error);\n res.status(500).json({\n success: false,\n message: 'Health check failed',\n timestamp: new Date().toISOString()\n });\n }\n});\n\n/**\n * POST /api/hello\n * Hello endpoint with POST body\n */\napp.post('/api/hello', (req, res) => {\n try {\n const { name, language } = req.body;\n \n // Input validation\n if (name && (typeof name !== 'string' || name.length > 100)) {\n return res.status(400).json({\n success: false,\n message: 'Invalid name in request body',\n timestamp: new Date().toISOString()\n });\n }\n\n // Support for different languages\n let greeting = 'Hello';\n if (language && typeof language === 'string') {\n const greetings = {\n 'es': 'Hola',\n 'fr': 'Bonjour',\n 'de': 'Hallo',\n 'it': 'Ciao',\n 'pt': 'Olá',\n 'ja': 'こんにちは',\n 'zh': '你好',\n 'hi': 'नमस्ते',\n 'ar': 'مرحبا'\n };\n greeting = greetings[language.toLowerCase()] || greeting;\n }\n\n const sanitizedName = name ? name.replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '') : 'World';\n const message = `${greeting} ${sanitizedName}!`;\n \n const response = createApiResponse({ \n greeting: message,\n name: sanitizedName,\n language: language || 'en'\n });\n res.json(response);\n } catch (error) {\n console.error('Error in POST /api/hello:', error);\n res.status(500).json({\n success: false,\n message: 'Internal server error',\n timestamp: new Date().toISOString()\n });\n }\n});\n\n/**\n * GET / - Root endpoint\n */\napp.get('/', (req, res) => {\n res.json({\n success: true,\n message: 'Hello World Backend Service',\n version: '1.0.0',\n endpoints: [\n 'GET /api/hello - Basic hello world',\n 'GET /api/hello/:name - Personalized greeting',\n 'POST /api/hello - Greeting with language support',\n 'GET /api/health - Health check'\n ],\n timestamp: new Date().toISOString()\n });\n});\n\n/**\n * 404 handler\n */\napp.use('*', (req, res) => {\n res.status(404).json({\n success: false,\n message: 'Endpoint not found',\n path: req.originalUrl,\n timestamp: new Date().toISOString()\n });\n});\n\n/**\n * Global error handler\n */\napp.use((error, req, res, next) => {\n console.error('Unhandled error:', error);\n res.status(500).json({\n success: false,\n message: 'Internal server error',\n timestamp: new Date().toISOString()\n });\n});\n\n// Start server\nconst server = app.listen(PORT, () => {\n console.log(`🚀 Hello World Backend Service running on port ${PORT}`);\n console.log(`📖 API Documentation: http://localhost:${PORT}/`);\n console.log(`❤️ Health Check: http://localhost:${PORT}/api/health`);\n});\n\n// Graceful shutdown\nprocess.on('SIGTERM', () => {\n console.log('SIGTERM received, shutting down gracefully');\n server.close(() => {\n console.log('Process terminated');\n });\n});\n\nprocess.on('SIGINT', () => {\n console.log('SIGINT received, shutting down gracefully');\n server.close(() => {\n console.log('Process terminated');\n });\n});\n\nexport default app;"],"names":["express","hello","healthCheck","createApiResponse","app","PORT","process","env","use","json","urlencoded","extended","req","res","next","setHeader","console","log","Date","toISOString","method","path","get","message","response","greeting","error","status","success","timestamp","name","params","length","sanitizedName","replace","health","post","language","body","greetings","toLowerCase","version","endpoints","originalUrl","server","listen","on","close"],"mappings":"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"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import app from '../src/server.js';
|
|
3
|
+
describe('Hello World Backend Service', ()=>{
|
|
4
|
+
describe('GET /', ()=>{
|
|
5
|
+
it('should return service information', async ()=>{
|
|
6
|
+
const response = await request(app).get('/').expect(200);
|
|
7
|
+
expect(response.body.success).toBe(true);
|
|
8
|
+
expect(response.body.message).toBe('Hello World Backend Service');
|
|
9
|
+
expect(response.body.endpoints).toBeDefined();
|
|
10
|
+
expect(response.body.timestamp).toBeDefined();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe('GET /api/health', ()=>{
|
|
14
|
+
it('should return health status', async ()=>{
|
|
15
|
+
const response = await request(app).get('/api/health').expect(200);
|
|
16
|
+
expect(response.body.success).toBe(true);
|
|
17
|
+
expect(response.body.data.status).toBe('healthy');
|
|
18
|
+
expect(response.body.data.timestamp).toBeDefined();
|
|
19
|
+
expect(response.body.data.uptime).toBeDefined();
|
|
20
|
+
expect(response.body.timestamp).toBeDefined();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('GET /api/hello', ()=>{
|
|
24
|
+
it('should return basic hello world greeting', async ()=>{
|
|
25
|
+
const response = await request(app).get('/api/hello').expect(200);
|
|
26
|
+
expect(response.body.success).toBe(true);
|
|
27
|
+
expect(response.body.data.greeting).toBe('Hello World!');
|
|
28
|
+
expect(response.body.timestamp).toBeDefined();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('GET /api/hello/:name', ()=>{
|
|
32
|
+
it('should return personalized greeting', async ()=>{
|
|
33
|
+
const response = await request(app).get('/api/hello/John').expect(200);
|
|
34
|
+
expect(response.body.success).toBe(true);
|
|
35
|
+
expect(response.body.data.greeting).toBe('Hello John!');
|
|
36
|
+
expect(response.body.data.name).toBe('John');
|
|
37
|
+
expect(response.body.timestamp).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
it('should sanitize XSS attempts in name parameter', async ()=>{
|
|
40
|
+
const maliciousName = '<script>alert("xss")</script>John';
|
|
41
|
+
const response = await request(app).get(`/api/hello/${encodeURIComponent(maliciousName)}`).expect(200);
|
|
42
|
+
expect(response.body.success).toBe(true);
|
|
43
|
+
expect(response.body.data.greeting).not.toContain('<script>');
|
|
44
|
+
expect(response.body.data.name).not.toContain('<script>');
|
|
45
|
+
expect(response.body.data.greeting).toBe('Hello John!');
|
|
46
|
+
});
|
|
47
|
+
it('should handle empty name', async ()=>{
|
|
48
|
+
const response = await request(app).get('/api/hello/').expect(404);
|
|
49
|
+
});
|
|
50
|
+
it('should reject names longer than 100 characters', async ()=>{
|
|
51
|
+
const longName = 'a'.repeat(101);
|
|
52
|
+
const response = await request(app).get(`/api/hello/${longName}`).expect(400);
|
|
53
|
+
expect(response.body.success).toBe(false);
|
|
54
|
+
expect(response.body.message).toContain('Invalid name parameter');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('POST /api/hello', ()=>{
|
|
58
|
+
it('should return greeting with name from request body', async ()=>{
|
|
59
|
+
const response = await request(app).post('/api/hello').send({
|
|
60
|
+
name: 'Alice'
|
|
61
|
+
}).expect(200);
|
|
62
|
+
expect(response.body.success).toBe(true);
|
|
63
|
+
expect(response.body.data.greeting).toBe('Hello Alice!');
|
|
64
|
+
expect(response.body.data.name).toBe('Alice');
|
|
65
|
+
expect(response.body.data.language).toBe('en');
|
|
66
|
+
expect(response.body.timestamp).toBeDefined();
|
|
67
|
+
});
|
|
68
|
+
it('should handle greeting without name', async ()=>{
|
|
69
|
+
const response = await request(app).post('/api/hello').send({}).expect(200);
|
|
70
|
+
expect(response.body.success).toBe(true);
|
|
71
|
+
expect(response.body.data.greeting).toBe('Hello World!');
|
|
72
|
+
expect(response.body.data.name).toBe('World');
|
|
73
|
+
});
|
|
74
|
+
it('should support different languages', async ()=>{
|
|
75
|
+
const testCases = [
|
|
76
|
+
{
|
|
77
|
+
language: 'es',
|
|
78
|
+
expected: 'Hola'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
language: 'fr',
|
|
82
|
+
expected: 'Bonjour'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
language: 'de',
|
|
86
|
+
expected: 'Hallo'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
language: 'it',
|
|
90
|
+
expected: 'Ciao'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
language: 'pt',
|
|
94
|
+
expected: 'Olá'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
language: 'ja',
|
|
98
|
+
expected: 'こんにちは'
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
language: 'zh',
|
|
102
|
+
expected: '你好'
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
language: 'hi',
|
|
106
|
+
expected: 'नमस्ते'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
language: 'ar',
|
|
110
|
+
expected: 'مرحبا'
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
language: 'invalid',
|
|
114
|
+
expected: 'Hello'
|
|
115
|
+
}
|
|
116
|
+
];
|
|
117
|
+
for (const testCase of testCases){
|
|
118
|
+
const response = await request(app).post('/api/hello').send({
|
|
119
|
+
name: 'World',
|
|
120
|
+
language: testCase.language
|
|
121
|
+
}).expect(200);
|
|
122
|
+
expect(response.body.success).toBe(true);
|
|
123
|
+
expect(response.body.data.greeting).toBe(`${testCase.expected} World!`);
|
|
124
|
+
expect(response.body.data.language).toBe(testCase.language);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
it('should sanitize XSS attempts in POST request body', async ()=>{
|
|
128
|
+
const maliciousPayload = {
|
|
129
|
+
name: '<script>alert("xss")</script>Bob',
|
|
130
|
+
language: 'en'
|
|
131
|
+
};
|
|
132
|
+
const response = await request(app).post('/api/hello').send(maliciousPayload).expect(200);
|
|
133
|
+
expect(response.body.success).toBe(true);
|
|
134
|
+
expect(response.body.data.greeting).not.toContain('<script>');
|
|
135
|
+
expect(response.body.data.name).not.toContain('<script>');
|
|
136
|
+
expect(response.body.data.greeting).toBe('Hello Bob!');
|
|
137
|
+
});
|
|
138
|
+
it('should reject names longer than 100 characters', async ()=>{
|
|
139
|
+
const longName = 'a'.repeat(101);
|
|
140
|
+
const response = await request(app).post('/api/hello').send({
|
|
141
|
+
name: longName
|
|
142
|
+
}).expect(400);
|
|
143
|
+
expect(response.body.success).toBe(false);
|
|
144
|
+
expect(response.body.message).toContain('Invalid name');
|
|
145
|
+
});
|
|
146
|
+
it('should reject invalid language types', async ()=>{
|
|
147
|
+
const response = await request(app).post('/api/hello').send({
|
|
148
|
+
name: 'World',
|
|
149
|
+
language: 123
|
|
150
|
+
}).expect(200); // Should still work, language defaults to English
|
|
151
|
+
expect(response.body.success).toBe(true);
|
|
152
|
+
expect(response.body.data.greeting).toBe('Hello World!');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
describe('Error Handling', ()=>{
|
|
156
|
+
it('should return 404 for non-existent endpoints', async ()=>{
|
|
157
|
+
const response = await request(app).get('/api/nonexistent').expect(404);
|
|
158
|
+
expect(response.body.success).toBe(false);
|
|
159
|
+
expect(response.body.message).toContain('Endpoint not found');
|
|
160
|
+
expect(response.body.path).toBe('/api/nonexistent');
|
|
161
|
+
});
|
|
162
|
+
it('should return 404 for nested non-existent endpoints', async ()=>{
|
|
163
|
+
const response = await request(app).get('/api/hello/nonexistent/deep').expect(404);
|
|
164
|
+
expect(response.body.success).toBe(false);
|
|
165
|
+
expect(response.body.message).toContain('Endpoint not found');
|
|
166
|
+
});
|
|
167
|
+
it('should handle malformed JSON in POST requests', async ()=>{
|
|
168
|
+
const response = await request(app).post('/api/hello').set('Content-Type', 'application/json').send('{"invalid": json}').expect(400);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
describe('Security Headers', ()=>{
|
|
172
|
+
it('should include security headers', async ()=>{
|
|
173
|
+
const response = await request(app).get('/api/hello').expect(200);
|
|
174
|
+
expect(response.headers['x-content-type-options']).toBe('nosniff');
|
|
175
|
+
expect(response.headers['x-frame-options']).toBe('DENY');
|
|
176
|
+
expect(response.headers['x-xss-protection']).toBe('1; mode=block');
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
describe('Performance and Load Testing', ()=>{
|
|
180
|
+
it('should handle multiple concurrent requests', async ()=>{
|
|
181
|
+
const requests = Array(10).fill().map(()=>request(app).get('/api/hello'));
|
|
182
|
+
const responses = await Promise.all(requests);
|
|
183
|
+
responses.forEach((response)=>{
|
|
184
|
+
expect(response.status).toBe(200);
|
|
185
|
+
expect(response.body.success).toBe(true);
|
|
186
|
+
expect(response.body.data.greeting).toBe('Hello World!');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
it('should handle requests with small delays', async ()=>{
|
|
190
|
+
for(let i = 0; i < 5; i++){
|
|
191
|
+
const response = await request(app).get('/api/hello/TestUser').expect(200);
|
|
192
|
+
expect(response.body.success).toBe(true);
|
|
193
|
+
expect(response.body.data.greeting).toBe('Hello TestUser!');
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('Content-Type Handling', ()=>{
|
|
198
|
+
it('should handle form-urlencoded data', async ()=>{
|
|
199
|
+
const response = await request(app).post('/api/hello').send('name=FormUser&language=es').set('Content-Type', 'application/x-www-form-urlencoded').expect(200);
|
|
200
|
+
expect(response.body.success).toBe(true);
|
|
201
|
+
expect(response.body.data.greeting).toBe('Hola FormUser!');
|
|
202
|
+
expect(response.body.data.language).toBe('es');
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
//# sourceMappingURL=server.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.test.js"],"sourcesContent":["import request from 'supertest';\nimport app from '../src/server.js';\n\ndescribe('Hello World Backend Service', () => {\n describe('GET /', () => {\n it('should return service information', async () => {\n const response = await request(app)\n .get('/')\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.message).toBe('Hello World Backend Service');\n expect(response.body.endpoints).toBeDefined();\n expect(response.body.timestamp).toBeDefined();\n });\n });\n\n describe('GET /api/health', () => {\n it('should return health status', async () => {\n const response = await request(app)\n .get('/api/health')\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.status).toBe('healthy');\n expect(response.body.data.timestamp).toBeDefined();\n expect(response.body.data.uptime).toBeDefined();\n expect(response.body.timestamp).toBeDefined();\n });\n });\n\n describe('GET /api/hello', () => {\n it('should return basic hello world greeting', async () => {\n const response = await request(app)\n .get('/api/hello')\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hello World!');\n expect(response.body.timestamp).toBeDefined();\n });\n });\n\n describe('GET /api/hello/:name', () => {\n it('should return personalized greeting', async () => {\n const response = await request(app)\n .get('/api/hello/John')\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hello John!');\n expect(response.body.data.name).toBe('John');\n expect(response.body.timestamp).toBeDefined();\n });\n\n it('should sanitize XSS attempts in name parameter', async () => {\n const maliciousName = '<script>alert(\"xss\")</script>John';\n const response = await request(app)\n .get(`/api/hello/${encodeURIComponent(maliciousName)}`)\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).not.toContain('<script>');\n expect(response.body.data.name).not.toContain('<script>');\n expect(response.body.data.greeting).toBe('Hello John!');\n });\n\n it('should handle empty name', async () => {\n const response = await request(app)\n .get('/api/hello/')\n .expect(404);\n });\n\n it('should reject names longer than 100 characters', async () => {\n const longName = 'a'.repeat(101);\n const response = await request(app)\n .get(`/api/hello/${longName}`)\n .expect(400);\n\n expect(response.body.success).toBe(false);\n expect(response.body.message).toContain('Invalid name parameter');\n });\n });\n\n describe('POST /api/hello', () => {\n it('should return greeting with name from request body', async () => {\n const response = await request(app)\n .post('/api/hello')\n .send({ name: 'Alice' })\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hello Alice!');\n expect(response.body.data.name).toBe('Alice');\n expect(response.body.data.language).toBe('en');\n expect(response.body.timestamp).toBeDefined();\n });\n\n it('should handle greeting without name', async () => {\n const response = await request(app)\n .post('/api/hello')\n .send({})\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hello World!');\n expect(response.body.data.name).toBe('World');\n });\n\n it('should support different languages', async () => {\n const testCases = [\n { language: 'es', expected: 'Hola' },\n { language: 'fr', expected: 'Bonjour' },\n { language: 'de', expected: 'Hallo' },\n { language: 'it', expected: 'Ciao' },\n { language: 'pt', expected: 'Olá' },\n { language: 'ja', expected: 'こんにちは' },\n { language: 'zh', expected: '你好' },\n { language: 'hi', expected: 'नमस्ते' },\n { language: 'ar', expected: 'مرحبا' },\n { language: 'invalid', expected: 'Hello' }\n ];\n\n for (const testCase of testCases) {\n const response = await request(app)\n .post('/api/hello')\n .send({ name: 'World', language: testCase.language })\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe(`${testCase.expected} World!`);\n expect(response.body.data.language).toBe(testCase.language);\n }\n });\n\n it('should sanitize XSS attempts in POST request body', async () => {\n const maliciousPayload = {\n name: '<script>alert(\"xss\")</script>Bob',\n language: 'en'\n };\n\n const response = await request(app)\n .post('/api/hello')\n .send(maliciousPayload)\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).not.toContain('<script>');\n expect(response.body.data.name).not.toContain('<script>');\n expect(response.body.data.greeting).toBe('Hello Bob!');\n });\n\n it('should reject names longer than 100 characters', async () => {\n const longName = 'a'.repeat(101);\n const response = await request(app)\n .post('/api/hello')\n .send({ name: longName })\n .expect(400);\n\n expect(response.body.success).toBe(false);\n expect(response.body.message).toContain('Invalid name');\n });\n\n it('should reject invalid language types', async () => {\n const response = await request(app)\n .post('/api/hello')\n .send({ name: 'World', language: 123 })\n .expect(200); // Should still work, language defaults to English\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hello World!');\n });\n });\n\n describe('Error Handling', () => {\n it('should return 404 for non-existent endpoints', async () => {\n const response = await request(app)\n .get('/api/nonexistent')\n .expect(404);\n\n expect(response.body.success).toBe(false);\n expect(response.body.message).toContain('Endpoint not found');\n expect(response.body.path).toBe('/api/nonexistent');\n });\n\n it('should return 404 for nested non-existent endpoints', async () => {\n const response = await request(app)\n .get('/api/hello/nonexistent/deep')\n .expect(404);\n\n expect(response.body.success).toBe(false);\n expect(response.body.message).toContain('Endpoint not found');\n });\n\n it('should handle malformed JSON in POST requests', async () => {\n const response = await request(app)\n .post('/api/hello')\n .set('Content-Type', 'application/json')\n .send('{\"invalid\": json}')\n .expect(400);\n });\n });\n\n describe('Security Headers', () => {\n it('should include security headers', async () => {\n const response = await request(app)\n .get('/api/hello')\n .expect(200);\n\n expect(response.headers['x-content-type-options']).toBe('nosniff');\n expect(response.headers['x-frame-options']).toBe('DENY');\n expect(response.headers['x-xss-protection']).toBe('1; mode=block');\n });\n });\n\n describe('Performance and Load Testing', () => {\n it('should handle multiple concurrent requests', async () => {\n const requests = Array(10).fill().map(() => \n request(app).get('/api/hello')\n );\n\n const responses = await Promise.all(requests);\n \n responses.forEach(response => {\n expect(response.status).toBe(200);\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hello World!');\n });\n });\n\n it('should handle requests with small delays', async () => {\n for (let i = 0; i < 5; i++) {\n const response = await request(app)\n .get('/api/hello/TestUser')\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hello TestUser!');\n }\n });\n });\n\n describe('Content-Type Handling', () => {\n it('should handle form-urlencoded data', async () => {\n const response = await request(app)\n .post('/api/hello')\n .send('name=FormUser&language=es')\n .set('Content-Type', 'application/x-www-form-urlencoded')\n .expect(200);\n\n expect(response.body.success).toBe(true);\n expect(response.body.data.greeting).toBe('Hola FormUser!');\n expect(response.body.data.language).toBe('es');\n });\n });\n});"],"names":["request","app","describe","it","response","get","expect","body","success","toBe","message","endpoints","toBeDefined","timestamp","data","status","uptime","greeting","name","maliciousName","encodeURIComponent","not","toContain","longName","repeat","post","send","language","testCases","expected","testCase","maliciousPayload","path","set","headers","requests","Array","fill","map","responses","Promise","all","forEach","i"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow-novice",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.37",
|
|
4
4
|
"description": "AI agent orchestration framework with namespace-isolated skills, agents, and CFN Loop validation. Safe installation with ~0.01% collision risk.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
"chalk": "^4.1.2",
|
|
133
133
|
"commander": "^11.1.0",
|
|
134
134
|
"dotenv": "^17.2.3",
|
|
135
|
+
"express": "^5.1.0",
|
|
135
136
|
"glob": "^11.0.3",
|
|
136
137
|
"ioredis": "^5.8.2",
|
|
137
138
|
"lodash": "^4.17.21",
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Docker MCP Build Script
|
|
5
|
+
# Builds all MCP server images and enhanced agent image with MCP clients
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
9
|
+
|
|
10
|
+
# Colors for output
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
NC='\033[0m' # No Color
|
|
15
|
+
|
|
16
|
+
echo "========================================="
|
|
17
|
+
echo " Docker MCP Build Script"
|
|
18
|
+
echo "========================================="
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
# Function to print colored output
|
|
22
|
+
print_status() {
|
|
23
|
+
local status=$1
|
|
24
|
+
local message=$2
|
|
25
|
+
case $status in
|
|
26
|
+
"success")
|
|
27
|
+
echo -e "${GREEN}✓${NC} $message"
|
|
28
|
+
;;
|
|
29
|
+
"error")
|
|
30
|
+
echo -e "${RED}✗${NC} $message"
|
|
31
|
+
;;
|
|
32
|
+
"info")
|
|
33
|
+
echo -e "${YELLOW}→${NC} $message"
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Check if Docker is available
|
|
39
|
+
if ! command -v docker &> /dev/null; then
|
|
40
|
+
print_status "error" "Docker is not installed or not in PATH"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Check if docker-compose is available
|
|
45
|
+
if ! command -v docker-compose &> /dev/null; then
|
|
46
|
+
print_status "error" "docker-compose is not installed or not in PATH"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Navigate to project root
|
|
51
|
+
cd "$PROJECT_ROOT"
|
|
52
|
+
|
|
53
|
+
# Validate MCP configuration exists
|
|
54
|
+
if [ ! -f "config/mcp-servers.json" ]; then
|
|
55
|
+
print_status "error" "MCP configuration not found: config/mcp-servers.json"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
print_status "success" "Found MCP configuration"
|
|
60
|
+
|
|
61
|
+
# Build enhanced production Dockerfile with MCP clients
|
|
62
|
+
print_status "info" "Building enhanced agent image with MCP clients..."
|
|
63
|
+
if docker build -f Dockerfile.production \
|
|
64
|
+
--target production \
|
|
65
|
+
--tag cfn-agent-mcp:latest \
|
|
66
|
+
--tag cfn-agent-mcp:$(date +%Y%m%d) \
|
|
67
|
+
--build-arg BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
68
|
+
--build-arg VCS_REF="$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')" \
|
|
69
|
+
--build-arg VERSION="4.1.0-mcp" \
|
|
70
|
+
. 2>&1 | tee /tmp/docker-build-agent.log; then
|
|
71
|
+
print_status "success" "Agent image built successfully"
|
|
72
|
+
else
|
|
73
|
+
print_status "error" "Failed to build agent image"
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Build MCP server images from docker-compose
|
|
78
|
+
print_status "info" "Building MCP server containers..."
|
|
79
|
+
if docker-compose -f docker-compose.production.yml build \
|
|
80
|
+
mcp-playwright \
|
|
81
|
+
mcp-redis-tools \
|
|
82
|
+
mcp-n8n \
|
|
83
|
+
mcp-security-scanner 2>&1 | tee /tmp/docker-build-mcp.log; then
|
|
84
|
+
print_status "success" "MCP server images built successfully"
|
|
85
|
+
else
|
|
86
|
+
print_status "error" "Failed to build MCP server images"
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# Pull base images that we reference directly
|
|
91
|
+
print_status "info" "Pulling base MCP images..."
|
|
92
|
+
docker pull mcr.microsoft.com/playwright:v1.40.0-jammy
|
|
93
|
+
docker pull redis:7-alpine
|
|
94
|
+
docker pull n8nio/n8n:latest
|
|
95
|
+
docker pull aquasec/trivy:latest
|
|
96
|
+
print_status "success" "Base images pulled"
|
|
97
|
+
|
|
98
|
+
# Run security scans if Trivy is available
|
|
99
|
+
if command -v trivy &> /dev/null; then
|
|
100
|
+
print_status "info" "Running security scans with Trivy..."
|
|
101
|
+
|
|
102
|
+
# Scan agent image
|
|
103
|
+
print_status "info" "Scanning cfn-agent-mcp:latest..."
|
|
104
|
+
if trivy image --severity HIGH,CRITICAL \
|
|
105
|
+
--exit-code 0 \
|
|
106
|
+
--no-progress \
|
|
107
|
+
cfn-agent-mcp:latest > /tmp/trivy-scan-agent.txt 2>&1; then
|
|
108
|
+
print_status "success" "Agent image scan complete"
|
|
109
|
+
else
|
|
110
|
+
print_status "error" "Agent image has vulnerabilities (see /tmp/trivy-scan-agent.txt)"
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# Scan MCP server images
|
|
114
|
+
for image in mcr.microsoft.com/playwright:v1.40.0-jammy \
|
|
115
|
+
redis:7-alpine \
|
|
116
|
+
n8nio/n8n:latest \
|
|
117
|
+
aquasec/trivy:latest; do
|
|
118
|
+
print_status "info" "Scanning $image..."
|
|
119
|
+
trivy image --severity HIGH,CRITICAL \
|
|
120
|
+
--exit-code 0 \
|
|
121
|
+
--no-progress \
|
|
122
|
+
"$image" > /tmp/trivy-scan-$(echo $image | sed 's/[^a-zA-Z0-9]/-/g').txt 2>&1 || true
|
|
123
|
+
done
|
|
124
|
+
|
|
125
|
+
print_status "success" "Security scans complete (results in /tmp/trivy-scan-*.txt)"
|
|
126
|
+
else
|
|
127
|
+
print_status "info" "Trivy not found - skipping security scans"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Summary
|
|
131
|
+
echo ""
|
|
132
|
+
echo "========================================="
|
|
133
|
+
echo " Build Summary"
|
|
134
|
+
echo "========================================="
|
|
135
|
+
echo ""
|
|
136
|
+
|
|
137
|
+
docker images | grep -E "(cfn-agent-mcp|mcp-playwright|mcp-redis-tools|mcp-n8n|mcp-security|playwright|n8n|trivy)" | head -20
|
|
138
|
+
|
|
139
|
+
echo ""
|
|
140
|
+
print_status "success" "Build complete!"
|
|
141
|
+
echo ""
|
|
142
|
+
echo "Tagged images:"
|
|
143
|
+
echo " - cfn-agent-mcp:latest"
|
|
144
|
+
echo " - cfn-agent-mcp:$(date +%Y%m%d)"
|
|
145
|
+
echo ""
|
|
146
|
+
echo "MCP Server images ready:"
|
|
147
|
+
echo " - mcp-playwright (mcr.microsoft.com/playwright:v1.40.0-jammy)"
|
|
148
|
+
echo " - mcp-redis-tools (redis:7-alpine)"
|
|
149
|
+
echo " - mcp-n8n (n8nio/n8n:latest)"
|
|
150
|
+
echo " - mcp-security-scanner (aquasec/trivy:latest)"
|
|
151
|
+
echo ""
|
|
152
|
+
echo "Next steps:"
|
|
153
|
+
echo " 1. Run tests: ./scripts/docker-test-mcp.sh"
|
|
154
|
+
echo " 2. Deploy: docker-compose -f docker-compose.production.yml up -d"
|
|
155
|
+
echo ""
|