@creative-ia/cortex 1.0.5

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 (64) hide show
  1. package/README.md +41 -0
  2. package/dist/config/cloud-proxy.d.ts +15 -0
  3. package/dist/config/cloud-proxy.js +63 -0
  4. package/dist/config/cloudwatch-store.d.ts +13 -0
  5. package/dist/config/cloudwatch-store.js +66 -0
  6. package/dist/config/license.d.ts +29 -0
  7. package/dist/config/license.js +165 -0
  8. package/dist/config/ssm-store.d.ts +2 -0
  9. package/dist/config/ssm-store.js +38 -0
  10. package/dist/config/telemetry.d.ts +17 -0
  11. package/dist/config/telemetry.js +93 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +460 -0
  14. package/dist/knowledge/dynamo-store.d.ts +17 -0
  15. package/dist/knowledge/dynamo-store.js +85 -0
  16. package/dist/knowledge/embeddings.d.ts +2 -0
  17. package/dist/knowledge/embeddings.js +36 -0
  18. package/dist/knowledge/loader.d.ts +8 -0
  19. package/dist/knowledge/loader.js +57 -0
  20. package/dist/lambda-package.zip +0 -0
  21. package/dist/lambda.d.ts +22 -0
  22. package/dist/lambda.js +496 -0
  23. package/dist/package.json +1 -0
  24. package/dist/tools/advance-process.d.ts +7 -0
  25. package/dist/tools/advance-process.js +128 -0
  26. package/dist/tools/analyze-code.d.ts +7 -0
  27. package/dist/tools/analyze-code.js +131 -0
  28. package/dist/tools/analyze-docs.d.ts +8 -0
  29. package/dist/tools/analyze-docs.js +147 -0
  30. package/dist/tools/config-registry.d.ts +3 -0
  31. package/dist/tools/config-registry.js +20 -0
  32. package/dist/tools/create-process.d.ts +6 -0
  33. package/dist/tools/create-process.js +257 -0
  34. package/dist/tools/decompose-epic.d.ts +7 -0
  35. package/dist/tools/decompose-epic.js +603 -0
  36. package/dist/tools/diagrams.d.ts +51 -0
  37. package/dist/tools/diagrams.js +304 -0
  38. package/dist/tools/generate-report.d.ts +9 -0
  39. package/dist/tools/generate-report.js +891 -0
  40. package/dist/tools/generate-wiki.d.ts +10 -0
  41. package/dist/tools/generate-wiki.js +700 -0
  42. package/dist/tools/get-architecture.d.ts +6 -0
  43. package/dist/tools/get-architecture.js +78 -0
  44. package/dist/tools/get-code-standards.d.ts +7 -0
  45. package/dist/tools/get-code-standards.js +52 -0
  46. package/dist/tools/init-process.d.ts +7 -0
  47. package/dist/tools/init-process.js +82 -0
  48. package/dist/tools/knowledge-crud.d.ts +26 -0
  49. package/dist/tools/knowledge-crud.js +142 -0
  50. package/dist/tools/logo-base64.d.ts +1 -0
  51. package/dist/tools/logo-base64.js +1 -0
  52. package/dist/tools/logs-query.d.ts +15 -0
  53. package/dist/tools/logs-query.js +46 -0
  54. package/dist/tools/reverse-engineer.d.ts +13 -0
  55. package/dist/tools/reverse-engineer.js +956 -0
  56. package/dist/tools/semantic-search.d.ts +7 -0
  57. package/dist/tools/semantic-search.js +68 -0
  58. package/dist/tools/update-process.d.ts +17 -0
  59. package/dist/tools/update-process.js +195 -0
  60. package/dist/tools/validate-idea.d.ts +7 -0
  61. package/dist/tools/validate-idea.js +339 -0
  62. package/dist/tools/validate-process.d.ts +6 -0
  63. package/dist/tools/validate-process.js +102 -0
  64. package/package.json +31 -0
package/dist/index.js ADDED
@@ -0,0 +1,460 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Creative IA 50 — MCP Server
4
+ *
5
+ * Expõe skills, knowledge e code standards como tools MCP protegidas.
6
+ * O conteúdo intelectual (skills, knowledge) NUNCA é exposto diretamente.
7
+ * Clientes recebem apenas respostas processadas pelas tools.
8
+ *
9
+ * License validation via DynamoDB (LocalStack ou AWS).
10
+ * Knowledge storage via S3 (LocalStack ou AWS).
11
+ */
12
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
14
+ import { z } from "zod";
15
+ import { validateLicense, canAccessDomain } from "./config/license.js";
16
+ import { isCloudProxyEnabled, callCloudTool } from "./config/cloud-proxy.js";
17
+ import { withTelemetry, reportTelemetry } from "./config/telemetry.js";
18
+ import { getCodeStandards } from "./tools/get-code-standards.js";
19
+ import { analyzeCode } from "./tools/analyze-code.js";
20
+ import { getArchitectureGuidance } from "./tools/get-architecture.js";
21
+ import { initProcess } from "./tools/init-process.js";
22
+ import { validateProcess } from "./tools/validate-process.js";
23
+ import { validateIdea } from "./tools/validate-idea.js";
24
+ import { generateReport } from "./tools/generate-report.js";
25
+ import { saveKnowledge, getKnowledge, searchKnowledge, deleteKnowledgeEntry, listDomains, } from "./tools/knowledge-crud.js";
26
+ import { getConfig } from "./tools/config-registry.js";
27
+ import { logEvent, searchLogs, insightsQuery } from "./tools/logs-query.js";
28
+ import { semanticSearch } from "./tools/semantic-search.js";
29
+ import { createProcess } from "./tools/create-process.js";
30
+ import { updateProcess } from "./tools/update-process.js";
31
+ import { decomposeEpic } from "./tools/decompose-epic.js";
32
+ import { advanceProcess } from "./tools/advance-process.js";
33
+ import { generateWiki } from "./tools/generate-wiki.js";
34
+ import { reverseEngineer } from "./tools/reverse-engineer.js";
35
+ import { analyzeDocs } from "./tools/analyze-docs.js";
36
+ const CLOUD_MODE = isCloudProxyEnabled();
37
+ const server = new McpServer({
38
+ name: "creative-ia50",
39
+ version: "1.0.0",
40
+ });
41
+ // --- Helper: license gate ---
42
+ async function licenseGate(licenseKey, toolName) {
43
+ const check = await validateLicense(licenseKey, toolName);
44
+ if (!check.valid)
45
+ return { denied: `Access denied: ${check.reason}` };
46
+ return { license: check.license };
47
+ }
48
+ // --- Helper: cloud proxy wrapper ---
49
+ // Quando CLOUD_MODE esta ativo, delega a tool para o endpoint nuvem via HTTPS.
50
+ // Elimina necessidade de credenciais AWS no cliente.
51
+ function cloudResult(text) {
52
+ return { content: [{ type: "text", text }] };
53
+ }
54
+ async function proxyToCloud(toolName, args) {
55
+ const start = Date.now();
56
+ try {
57
+ const text = await callCloudTool(toolName, args);
58
+ const durationMs = Date.now() - start;
59
+ reportTelemetry({ tool: toolName, status: "success", durationMs, summary: `cloud proxy` });
60
+ return cloudResult(text);
61
+ }
62
+ catch (err) {
63
+ const durationMs = Date.now() - start;
64
+ reportTelemetry({ tool: toolName, status: "error", durationMs, error: err.message });
65
+ return cloudResult(`Error: ${err.message}`);
66
+ }
67
+ }
68
+ // Lista de tools que dependem de AWS e devem ser proxied quando em CLOUD_MODE
69
+ const CLOUD_TOOLS = new Set([
70
+ "get_code_standards", "analyze_code", "get_architecture_guidance",
71
+ "validate_idea", "init_process", "validate_process",
72
+ "save_knowledge", "get_knowledge", "search_knowledge",
73
+ "delete_knowledge", "list_knowledge_domains",
74
+ "get_config", "log_event", "search_logs", "insights_query",
75
+ "semantic_search", "update_process",
76
+ ]);
77
+ // --- Tool: get_code_standards ---
78
+ server.tool("get_code_standards", "Returns code standards rules (L1-L4) for the requested level, language, or specific rule ID.", {
79
+ licenseKey: z.string().describe("Client license key"),
80
+ level: z.string().optional().describe("L1, L2, L3, L4, or all"),
81
+ language: z.string().optional().describe("typescript, java, or all"),
82
+ ruleId: z.string().optional().describe("Specific rule ID (e.g. L1-001)"),
83
+ }, async ({ licenseKey, level, language, ruleId }) => {
84
+ if (CLOUD_MODE)
85
+ return proxyToCloud("get_code_standards", { licenseKey, level, language, ruleId });
86
+ const gate = await licenseGate(licenseKey, "get_code_standards");
87
+ if ("denied" in gate)
88
+ return { content: [{ type: "text", text: gate.denied }] };
89
+ const result = await getCodeStandards({ level, language, ruleId });
90
+ return { content: [{ type: "text", text: result }] };
91
+ });
92
+ // --- Tool: analyze_code ---
93
+ server.tool("analyze_code", "Analyzes code against L1-L4 standards. Returns violations with fix suggestions.", {
94
+ licenseKey: z.string().describe("Client license key"),
95
+ code: z.string().describe("Source code to analyze"),
96
+ language: z.string().optional().describe("typescript or java"),
97
+ filename: z.string().optional().describe("Filename for context"),
98
+ }, async ({ licenseKey, code, language, filename }) => {
99
+ if (CLOUD_MODE)
100
+ return proxyToCloud("analyze_code", { licenseKey, code, language, filename });
101
+ const gate = await licenseGate(licenseKey, "analyze_code");
102
+ if ("denied" in gate)
103
+ return { content: [{ type: "text", text: gate.denied }] };
104
+ const result = await analyzeCode({ code, language, filename });
105
+ return { content: [{ type: "text", text: result }] };
106
+ });
107
+ // --- Tool: get_architecture_guidance ---
108
+ server.tool("get_architecture_guidance", "Returns architecture guidance for a specific stack (BFF, Backend, Frontend).", {
109
+ licenseKey: z.string().describe("Client license key"),
110
+ stack: z.string().describe("bff, backend, or frontend"),
111
+ topic: z.string().optional().describe("layers, folders, errors, api, di, or all"),
112
+ }, async ({ licenseKey, stack, topic }) => {
113
+ if (CLOUD_MODE)
114
+ return proxyToCloud("get_architecture_guidance", { licenseKey, stack, topic });
115
+ const gate = await licenseGate(licenseKey, "get_architecture_guidance");
116
+ if ("denied" in gate)
117
+ return { content: [{ type: "text", text: gate.denied }] };
118
+ const result = await getArchitectureGuidance({ stack, topic });
119
+ return { content: [{ type: "text", text: result }] };
120
+ });
121
+ // --- Tool: init_process ---
122
+ server.tool("init_process", "Initializes a new process with UUID, checklist, and mandatory workflow.", {
123
+ licenseKey: z.string().describe("Client license key"),
124
+ title: z.string().describe("Process title"),
125
+ stakeholder: z.string().optional().describe("Stakeholder name"),
126
+ description: z.string().optional().describe("Process description"),
127
+ }, async ({ licenseKey, title, stakeholder, description }) => {
128
+ if (CLOUD_MODE)
129
+ return proxyToCloud("init_process", { licenseKey, title, stakeholder, description });
130
+ const gate = await licenseGate(licenseKey, "init_process");
131
+ if ("denied" in gate)
132
+ return { content: [{ type: "text", text: gate.denied }] };
133
+ const result = await initProcess({ title, stakeholder, description });
134
+ return { content: [{ type: "text", text: result }] };
135
+ });
136
+ // --- Tool: validate_process ---
137
+ server.tool("validate_process", "Validates if a process follows the mandatory workflow and has all required artifacts.", {
138
+ licenseKey: z.string().describe("Client license key"),
139
+ processId: z.string().describe("Process UUID"),
140
+ artifacts: z.array(z.string()).describe("List of artifact filenames in the process"),
141
+ }, async ({ licenseKey, processId, artifacts }) => {
142
+ if (CLOUD_MODE)
143
+ return proxyToCloud("validate_process", { licenseKey, processId, artifacts });
144
+ const gate = await licenseGate(licenseKey, "validate_process");
145
+ if ("denied" in gate)
146
+ return { content: [{ type: "text", text: gate.denied }] };
147
+ const result = await validateProcess({ processId, artifacts });
148
+ return { content: [{ type: "text", text: result }] };
149
+ });
150
+ // --- Tool: validate_idea ---
151
+ server.tool("validate_idea", "Analyzes a business idea against the company knowledge base (domains, integrations, architecture, past processes) and returns a feasibility report. The knowledge base is never exposed — only the processed analysis is returned.", {
152
+ licenseKey: z.string().describe("Client license key"),
153
+ idea: z.string().describe("Business idea in natural language (e.g. 'Preciso construir uma jornada de Credito Consignado INSS no app')"),
154
+ context: z.string().optional().describe("Additional context about the idea"),
155
+ }, async ({ licenseKey, idea, context }) => {
156
+ if (CLOUD_MODE)
157
+ return proxyToCloud("validate_idea", { licenseKey, idea, context });
158
+ const gate = await licenseGate(licenseKey, "validate_idea");
159
+ if ("denied" in gate)
160
+ return { content: [{ type: "text", text: gate.denied }] };
161
+ const result = await validateIdea({ idea, context });
162
+ return { content: [{ type: "text", text: result }] };
163
+ });
164
+ // --- Tool: generate_report ---
165
+ server.tool("generate_report", "Generates a branded HTML report on the client machine from processed content. The HTML template is proprietary (never exposed as source). Output goes to ~/creative-reports/ or a custom directory.", {
166
+ licenseKey: z.string().describe("Client license key"),
167
+ title: z.string().describe("Report title"),
168
+ content: z.string().describe("Report content (output from other tools like validate_idea)"),
169
+ reportType: z.string().describe("Report type: feasibility, analysis, architecture, process"),
170
+ outputDir: z.string().optional().describe("Custom output directory (default: ~/creative-reports/)"),
171
+ }, async ({ licenseKey, title, content, reportType, outputDir }) => {
172
+ const gate = await licenseGate(licenseKey, "generate_report");
173
+ if ("denied" in gate)
174
+ return { content: [{ type: "text", text: gate.denied }] };
175
+ const result = await withTelemetry("generate_report", () => generateReport({ title, content, reportType, outputDir }), (r) => `report=${reportType} title=${title.slice(0, 50)}`, { reportType });
176
+ return { content: [{ type: "text", text: result }] };
177
+ });
178
+ // =============================================================================
179
+ // Knowledge CRUD Tools — Memória organizacional persistente via DynamoDB
180
+ // =============================================================================
181
+ // --- Tool: save_knowledge ---
182
+ server.tool("save_knowledge", "Salva ou atualiza um registro de conhecimento organizacional no DynamoDB. Domains: decisions, changelog, troubleshooting, glossary, integrations, lessons-learned, pending, ports, stakeholders, environments.", {
183
+ licenseKey: z.string().describe("Client license key"),
184
+ domain: z.string().describe("Knowledge domain (decisions, changelog, troubleshooting, glossary, integrations, lessons-learned, pending, ports, stakeholders, environments)"),
185
+ id: z.string().describe("Unique ID within domain (e.g. ADR-001, TASK-030, TS-005)"),
186
+ title: z.string().describe("Entry title"),
187
+ content: z.string().describe("Entry content (markdown)"),
188
+ tags: z.array(z.string()).optional().describe("Tags for search/filtering"),
189
+ metadata: z.record(z.unknown()).optional().describe("Additional structured metadata"),
190
+ }, async ({ licenseKey, domain, id, title, content, tags, metadata }) => {
191
+ if (CLOUD_MODE)
192
+ return proxyToCloud("save_knowledge", { licenseKey, domain, id, title, content, tags, metadata });
193
+ const gate = await licenseGate(licenseKey, "save_knowledge");
194
+ if ("denied" in gate)
195
+ return { content: [{ type: "text", text: gate.denied }] };
196
+ if (!canAccessDomain(gate.license, domain))
197
+ return { content: [{ type: "text", text: `Access denied: domain '${domain}' not allowed for this license` }] };
198
+ const result = await saveKnowledge({ domain, id, title, content, tags, metadata });
199
+ return { content: [{ type: "text", text: result }] };
200
+ });
201
+ // --- Tool: get_knowledge ---
202
+ server.tool("get_knowledge", "Recupera conhecimento organizacional. Sem ID retorna todos os registros do domain.", {
203
+ licenseKey: z.string().describe("Client license key"),
204
+ domain: z.string().describe("Knowledge domain"),
205
+ id: z.string().optional().describe("Specific entry ID (omit to list all in domain)"),
206
+ limit: z.number().optional().describe("Max entries to return (default 50)"),
207
+ }, async ({ licenseKey, domain, id, limit }) => {
208
+ if (CLOUD_MODE)
209
+ return proxyToCloud("get_knowledge", { licenseKey, domain, id, limit });
210
+ const gate = await licenseGate(licenseKey, "get_knowledge");
211
+ if ("denied" in gate)
212
+ return { content: [{ type: "text", text: gate.denied }] };
213
+ if (!canAccessDomain(gate.license, domain))
214
+ return { content: [{ type: "text", text: `Access denied: domain '${domain}' not allowed for this license` }] };
215
+ const result = await getKnowledge({ domain, id, limit });
216
+ return { content: [{ type: "text", text: result }] };
217
+ });
218
+ // --- Tool: search_knowledge ---
219
+ server.tool("search_knowledge", "Busca textual no conhecimento organizacional. Busca em título, conteúdo e tags.", {
220
+ licenseKey: z.string().describe("Client license key"),
221
+ query: z.string().describe("Search text"),
222
+ domain: z.string().optional().describe("Limit search to specific domain"),
223
+ tag: z.string().optional().describe("Search by tag (uses GSI)"),
224
+ limit: z.number().optional().describe("Max results (default 20)"),
225
+ }, async ({ licenseKey, query, domain, tag, limit }) => {
226
+ if (CLOUD_MODE)
227
+ return proxyToCloud("search_knowledge", { licenseKey, query, domain, tag, limit });
228
+ const gate = await licenseGate(licenseKey, "search_knowledge");
229
+ if ("denied" in gate)
230
+ return { content: [{ type: "text", text: gate.denied }] };
231
+ if (domain && !canAccessDomain(gate.license, domain))
232
+ return { content: [{ type: "text", text: `Access denied: domain '${domain}' not allowed for this license` }] };
233
+ const result = await searchKnowledge({ query, domain, tag, limit, license: gate.license });
234
+ return { content: [{ type: "text", text: result }] };
235
+ });
236
+ // --- Tool: delete_knowledge ---
237
+ server.tool("delete_knowledge", "Remove um registro de conhecimento organizacional.", {
238
+ licenseKey: z.string().describe("Client license key"),
239
+ domain: z.string().describe("Knowledge domain"),
240
+ id: z.string().describe("Entry ID to delete"),
241
+ }, async ({ licenseKey, domain, id }) => {
242
+ if (CLOUD_MODE)
243
+ return proxyToCloud("delete_knowledge", { licenseKey, domain, id });
244
+ const gate = await licenseGate(licenseKey, "delete_knowledge");
245
+ if ("denied" in gate)
246
+ return { content: [{ type: "text", text: gate.denied }] };
247
+ if (!canAccessDomain(gate.license, domain))
248
+ return { content: [{ type: "text", text: `Access denied: domain '${domain}' not allowed for this license` }] };
249
+ const result = await deleteKnowledgeEntry({ domain, id });
250
+ return { content: [{ type: "text", text: result }] };
251
+ });
252
+ // --- Tool: list_knowledge_domains ---
253
+ server.tool("list_knowledge_domains", "Lista todos os domains de conhecimento e quantidade de registros em cada um.", {
254
+ licenseKey: z.string().describe("Client license key"),
255
+ }, async ({ licenseKey }) => {
256
+ if (CLOUD_MODE)
257
+ return proxyToCloud("list_knowledge_domains", { licenseKey });
258
+ const gate = await licenseGate(licenseKey, "list_knowledge_domains");
259
+ if ("denied" in gate)
260
+ return { content: [{ type: "text", text: gate.denied }] };
261
+ const result = await listDomains(gate.license);
262
+ return { content: [{ type: "text", text: result }] };
263
+ });
264
+ // =============================================================================
265
+ // Fase 3 — SSM Config Registry + CloudWatch Logs
266
+ // =============================================================================
267
+ // --- Tool: get_config ---
268
+ server.tool("get_config", "Lê configuração do MCP Server via SSM Parameter Store. Sem key retorna todas as configs.", {
269
+ licenseKey: z.string().describe("Client license key"),
270
+ key: z.string().optional().describe("Config key (e.g. 'version', 'features'). Omit to list all."),
271
+ }, async ({ licenseKey, key }) => {
272
+ if (CLOUD_MODE)
273
+ return proxyToCloud("get_config", { licenseKey, key });
274
+ const gate = await licenseGate(licenseKey, "get_config");
275
+ if ("denied" in gate)
276
+ return { content: [{ type: "text", text: gate.denied }] };
277
+ const result = await getConfig({ key });
278
+ return { content: [{ type: "text", text: result }] };
279
+ });
280
+ // --- Tool: log_event ---
281
+ server.tool("log_event", "Registra um evento de log no CloudWatch Logs do MCP Server.", {
282
+ licenseKey: z.string().describe("Client license key"),
283
+ level: z.string().describe("Log level: info, warn, error, debug"),
284
+ message: z.string().describe("Log message"),
285
+ meta: z.record(z.unknown()).optional().describe("Additional metadata"),
286
+ }, async ({ licenseKey, level, message, meta }) => {
287
+ if (CLOUD_MODE)
288
+ return proxyToCloud("log_event", { licenseKey, level, message, meta });
289
+ const gate = await licenseGate(licenseKey, "log_event");
290
+ if ("denied" in gate)
291
+ return { content: [{ type: "text", text: gate.denied }] };
292
+ const result = await logEvent({ level, message, meta });
293
+ return { content: [{ type: "text", text: result }] };
294
+ });
295
+ // --- Tool: search_logs ---
296
+ server.tool("search_logs", "Busca logs no CloudWatch por pattern. Default: últimas 24h.", {
297
+ licenseKey: z.string().describe("Client license key"),
298
+ pattern: z.string().optional().describe("Filter pattern (CloudWatch syntax)"),
299
+ hours: z.number().optional().describe("Hours to look back (default: 24)"),
300
+ limit: z.number().optional().describe("Max results (default: 50)"),
301
+ }, async ({ licenseKey, pattern, hours, limit }) => {
302
+ if (CLOUD_MODE)
303
+ return proxyToCloud("search_logs", { licenseKey, pattern, hours, limit });
304
+ const gate = await licenseGate(licenseKey, "search_logs");
305
+ if ("denied" in gate)
306
+ return { content: [{ type: "text", text: gate.denied }] };
307
+ const result = await searchLogs({ pattern, hours, limit });
308
+ return { content: [{ type: "text", text: result }] };
309
+ });
310
+ // --- Tool: insights_query ---
311
+ server.tool("insights_query", "Executa uma query CloudWatch Insights nos logs do MCP Server.", {
312
+ licenseKey: z.string().describe("Client license key"),
313
+ query: z.string().describe("CloudWatch Insights query (e.g. 'fields @timestamp, @message | filter level = \"error\"')"),
314
+ hours: z.number().optional().describe("Hours to look back (default: 24)"),
315
+ limit: z.number().optional().describe("Max results (default: 50)"),
316
+ }, async ({ licenseKey, query, hours, limit }) => {
317
+ if (CLOUD_MODE)
318
+ return proxyToCloud("insights_query", { licenseKey, query, hours, limit });
319
+ const gate = await licenseGate(licenseKey, "insights_query");
320
+ if ("denied" in gate)
321
+ return { content: [{ type: "text", text: gate.denied }] };
322
+ const result = await insightsQuery({ query, hours, limit });
323
+ return { content: [{ type: "text", text: result }] };
324
+ });
325
+ // =============================================================================
326
+ // Fase 4 — Semantic Search via Bedrock Embeddings
327
+ // =============================================================================
328
+ // --- Tool: semantic_search ---
329
+ server.tool("semantic_search", "Busca semântica no knowledge base usando Bedrock Titan Embeddings. Encontra registros por significado, não apenas texto exato.", {
330
+ licenseKey: z.string().describe("Client license key"),
331
+ query: z.string().describe("Natural language search query"),
332
+ domain: z.string().optional().describe("Limit to specific domain (omit to search all)"),
333
+ limit: z.number().optional().describe("Max results (default: 5)"),
334
+ }, async ({ licenseKey, query, domain, limit }) => {
335
+ if (CLOUD_MODE)
336
+ return proxyToCloud("semantic_search", { licenseKey, query, domain, limit });
337
+ const gate = await licenseGate(licenseKey, "semantic_search");
338
+ if ("denied" in gate)
339
+ return { content: [{ type: "text", text: gate.denied }] };
340
+ if (domain && !canAccessDomain(gate.license, domain))
341
+ return { content: [{ type: "text", text: `Access denied: domain '${domain}' not allowed for this license` }] };
342
+ const result = await semanticSearch({ query, domain, limit, license: gate.license });
343
+ return { content: [{ type: "text", text: result }] };
344
+ });
345
+ // =============================================================================
346
+ // Fase 5 — Process Lifecycle + Wiki + Reverse Engineer (filesystem tools)
347
+ // =============================================================================
348
+ // --- Tool: create_process ---
349
+ server.tool("create_process", "Cria esqueleto de processo: recebe frase em linguagem natural, inicializa no DynamoDB e retorna arquivos locais (README, 01-stakeholder, knowledge.json, orchestration.json).", {
350
+ licenseKey: z.string().describe("Client license key"),
351
+ prompt: z.string().describe("Frase em linguagem natural descrevendo o processo"),
352
+ stakeholder: z.string().optional().describe("Nome do stakeholder ou squad"),
353
+ }, async ({ licenseKey, prompt, stakeholder }) => {
354
+ const gate = await licenseGate(licenseKey, "create_process");
355
+ if ("denied" in gate)
356
+ return { content: [{ type: "text", text: gate.denied }] };
357
+ const result = await withTelemetry("create_process", () => createProcess({ prompt, stakeholder }), (r) => `prompt=${prompt.slice(0, 80)}`, { stakeholder });
358
+ return { content: [{ type: "text", text: result }] };
359
+ });
360
+ // --- Tool: update_process ---
361
+ server.tool("update_process", "Acrescenta informações a um processo existente (tech stack, decisões, status de fases, notas).", {
362
+ licenseKey: z.string().describe("Client license key"),
363
+ processId: z.string().describe("UUID do processo (ex: 'ddb8715d')"),
364
+ updates: z.object({
365
+ tech_stack: z.record(z.string()).optional().describe("Mapa chave-valor do tech stack"),
366
+ decisions: z.array(z.object({
367
+ title: z.string().describe("Título da decisão"),
368
+ decision: z.string().describe("Decisão tomada"),
369
+ rationale: z.string().optional().describe("Justificativa"),
370
+ })).optional().describe("Novas decisões técnicas a adicionar"),
371
+ phase_status: z.record(z.string()).optional().describe("Atualização de status de fases"),
372
+ notes: z.string().optional().describe("Nota ou observação a adicionar"),
373
+ stakeholder: z.string().optional().describe("Atualizar stakeholder"),
374
+ }).describe("Objeto com as atualizações a aplicar"),
375
+ listProcesses: z.boolean().optional().describe("Se true, lista processos acessíveis"),
376
+ }, async ({ licenseKey, processId, updates, listProcesses }) => {
377
+ if (CLOUD_MODE)
378
+ return proxyToCloud("update_process", { licenseKey, processId, updates, listProcesses });
379
+ const gate = await licenseGate(licenseKey, "update_process");
380
+ if ("denied" in gate)
381
+ return { content: [{ type: "text", text: gate.denied }] };
382
+ const result = await updateProcess({ processId, updates, listProcesses });
383
+ return { content: [{ type: "text", text: result }] };
384
+ });
385
+ // --- Tool: decompose_epic ---
386
+ server.tool("decompose_epic", "Decompõe um épico (EP-XX) em artefatos completos: EPIC.md + Features + User Stories + Tasks.", {
387
+ licenseKey: z.string().describe("Client license key"),
388
+ processId: z.string().describe("UUID do processo (ex: '5b650020')"),
389
+ epicId: z.string().describe("ID do épico a decompor (ex: 'EP-01', 'EP-02')"),
390
+ processDir: z.string().describe("Caminho absoluto do diretório do processo"),
391
+ }, async ({ licenseKey, processId, epicId, processDir }) => {
392
+ const gate = await licenseGate(licenseKey, "decompose_epic");
393
+ if ("denied" in gate)
394
+ return { content: [{ type: "text", text: gate.denied }] };
395
+ const result = await withTelemetry("decompose_epic", () => decomposeEpic({ processId, epicId, processDir }), (r) => `process=${processId} epic=${epicId}`, { processId, epicId });
396
+ return { content: [{ type: "text", text: result }] };
397
+ });
398
+ // --- Tool: advance_process ---
399
+ server.tool("advance_process", "Orquestrador inteligente: detecta a fase atual do processo e avança para o próximo artefato.", {
400
+ licenseKey: z.string().describe("Client license key"),
401
+ processId: z.string().describe("UUID do processo (ex: '5b650020')"),
402
+ processDir: z.string().describe("Caminho absoluto do diretório do processo"),
403
+ epicId: z.string().optional().describe("ID do épico específico (ex: 'EP-01')"),
404
+ }, async ({ licenseKey, processId, processDir, epicId }) => {
405
+ const gate = await licenseGate(licenseKey, "advance_process");
406
+ if ("denied" in gate)
407
+ return { content: [{ type: "text", text: gate.denied }] };
408
+ const result = await withTelemetry("advance_process", () => advanceProcess({ processId, processDir, epicId }), (r) => `process=${processId}${epicId ? ` epic=${epicId}` : ""}`, { processId, epicId });
409
+ return { content: [{ type: "text", text: result }] };
410
+ });
411
+ // --- Tool: generate_wiki ---
412
+ server.tool("generate_wiki", "Gera/atualiza wiki navegável do processo: index.html, pages/, styles.css, loader.js e server.cjs.", {
413
+ licenseKey: z.string().describe("Client license key"),
414
+ processId: z.string().describe("UUID do processo (ex: '5b650020')"),
415
+ processDir: z.string().describe("Caminho absoluto do diretório do processo"),
416
+ }, async ({ licenseKey, processId, processDir }) => {
417
+ const gate = await licenseGate(licenseKey, "generate_wiki");
418
+ if ("denied" in gate)
419
+ return { content: [{ type: "text", text: gate.denied }] };
420
+ const result = await withTelemetry("generate_wiki", () => generateWiki({ processId, processDir }), (r) => `process=${processId}`, { processId });
421
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
422
+ });
423
+ // --- Tool: reverse_engineer ---
424
+ server.tool("reverse_engineer", "Analisa repositório local ou remoto (Git URL) e gera artefato .md de engenharia reversa: stack, módulos, dependências, APIs, padrões de arquitetura e métricas. Para repos remotos, configure tokens nas env vars do mcp.json (GITHUB_TOKEN, GITLAB_TOKEN, BITBUCKET_TOKEN, AZURE_DEVOPS_TOKEN).", {
425
+ licenseKey: z.string().describe("Client license key"),
426
+ repoDir: z.string().describe("Caminho absoluto do repositório local OU URL Git remota (https://github.com/org/repo.git)"),
427
+ processId: z.string().optional().describe("UUID do processo (se vinculado a um processo existente)"),
428
+ processDir: z.string().optional().describe("Caminho absoluto do diretório do processo"),
429
+ outputFilename: z.string().optional().describe("Nome do arquivo de saída (default: engenharia-reversa-{repo}.md)"),
430
+ }, async ({ licenseKey, repoDir, processId, processDir, outputFilename }) => {
431
+ const gate = await licenseGate(licenseKey, "reverse_engineer");
432
+ if ("denied" in gate)
433
+ return { content: [{ type: "text", text: gate.denied }] };
434
+ const result = await withTelemetry("reverse_engineer", () => reverseEngineer({ repoDir, processId, processDir, outputFilename }), (r) => `repo=${repoDir.split("/").pop() || repoDir}`, { repoDir, processId });
435
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
436
+ });
437
+ // --- Tool: analyze_docs ---
438
+ server.tool("analyze_docs", "Analisa um diretório de documentação, extrai texto de todos os arquivos suportados (PDF, DOCX, PPTX, XLSX, MD, TXT, JSON, YAML, HTML) e gera um resumo estruturado com o conteúdo extraído. Útil para alimentar processos de arquitetura a partir de documentação existente.", {
439
+ licenseKey: z.string().describe("Client license key"),
440
+ docsDir: z.string().describe("Caminho absoluto do diretório com os documentos"),
441
+ processId: z.string().optional().describe("UUID do processo (se vinculado a um processo existente)"),
442
+ processDir: z.string().optional().describe("Caminho absoluto do diretório do processo (para salvar o artefato)"),
443
+ maxFiles: z.number().optional().describe("Máximo de arquivos a analisar (default: 50)"),
444
+ }, async ({ licenseKey, docsDir, processId, processDir, maxFiles }) => {
445
+ const gate = await licenseGate(licenseKey, "analyze_docs");
446
+ if ("denied" in gate)
447
+ return { content: [{ type: "text", text: gate.denied }] };
448
+ const result = await withTelemetry("analyze_docs", () => analyzeDocs({ docsDir, processId, processDir, maxFiles }), (r) => `dir=${docsDir.split("/").pop() || docsDir}`, { docsDir, processId });
449
+ return { content: [{ type: "text", text: result }] };
450
+ });
451
+ // --- Start server ---
452
+ async function main() {
453
+ const transport = new StdioServerTransport();
454
+ await server.connect(transport);
455
+ console.error("Creative IA 50 MCP Server running on stdio");
456
+ }
457
+ main().catch((err) => {
458
+ console.error("Fatal error:", err);
459
+ process.exit(1);
460
+ });
@@ -0,0 +1,17 @@
1
+ export interface KnowledgeEntry {
2
+ domain: string;
3
+ id: string;
4
+ title: string;
5
+ content: string;
6
+ tags?: string[];
7
+ metadata?: Record<string, unknown>;
8
+ created_at: string;
9
+ updated_at: string;
10
+ }
11
+ export declare function putEntry(entry: KnowledgeEntry): Promise<void>;
12
+ export declare function getEntry(domain: string, id: string): Promise<KnowledgeEntry | null>;
13
+ export declare function queryByDomain(domain: string, limit?: number): Promise<KnowledgeEntry[]>;
14
+ export declare function searchByTag(tag: string, limit?: number): Promise<KnowledgeEntry[]>;
15
+ export declare function searchByText(domain: string, text: string, limit?: number): Promise<KnowledgeEntry[]>;
16
+ export declare function deleteEntry(domain: string, id: string): Promise<void>;
17
+ export declare function countByDomain(domain: string): Promise<number>;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Knowledge DynamoDB Store — CRUD de conhecimento organizacional.
3
+ *
4
+ * Tabela: creative-ia50-knowledge
5
+ * PK: domain (ex: "decisions", "changelog", "troubleshooting", "glossary")
6
+ * SK: id (ex: "ADR-001", "TASK-030", "TS-005", "TERM-001")
7
+ *
8
+ * Suporta LocalStack e AWS real via USE_LOCALSTACK env var.
9
+ */
10
+ import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
11
+ import { DynamoDBDocumentClient, PutCommand, GetCommand, QueryCommand, DeleteCommand, } from "@aws-sdk/lib-dynamodb";
12
+ const isLocal = process.env.USE_LOCALSTACK === "true";
13
+ const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({
14
+ region: process.env.AWS_REGION || "sa-east-1",
15
+ ...(isLocal && {
16
+ endpoint: "http://localhost:4566",
17
+ credentials: { accessKeyId: "test", secretAccessKey: "test" },
18
+ }),
19
+ }));
20
+ const TABLE = process.env.KNOWLEDGE_TABLE || "creative-ia50-knowledge";
21
+ // --- PUT (create or update) ---
22
+ export async function putEntry(entry) {
23
+ await ddb.send(new PutCommand({
24
+ TableName: TABLE,
25
+ Item: {
26
+ ...entry,
27
+ primary_tag: entry.tags?.[0] || "untagged",
28
+ updated_at: new Date().toISOString(),
29
+ },
30
+ }));
31
+ }
32
+ // --- GET single entry ---
33
+ export async function getEntry(domain, id) {
34
+ const res = await ddb.send(new GetCommand({ TableName: TABLE, Key: { domain, id } }));
35
+ return res.Item || null;
36
+ }
37
+ // --- QUERY by domain (list all entries in a domain) ---
38
+ export async function queryByDomain(domain, limit) {
39
+ const res = await ddb.send(new QueryCommand({
40
+ TableName: TABLE,
41
+ KeyConditionExpression: "#d = :domain",
42
+ ExpressionAttributeNames: { "#d": "domain" },
43
+ ExpressionAttributeValues: { ":domain": domain },
44
+ ScanIndexForward: false,
45
+ ...(limit && { Limit: limit }),
46
+ }));
47
+ return res.Items || [];
48
+ }
49
+ // --- SEARCH by tag (uses GSI tag-index) ---
50
+ export async function searchByTag(tag, limit) {
51
+ // Scan with filter — for small datasets this is fine.
52
+ // For large scale, use a GSI on tags (flattened).
53
+ const res = await ddb.send(new QueryCommand({
54
+ TableName: TABLE,
55
+ IndexName: "tag-index",
56
+ KeyConditionExpression: "primary_tag = :tag",
57
+ ExpressionAttributeValues: { ":tag": tag },
58
+ ...(limit && { Limit: limit }),
59
+ }));
60
+ return res.Items || [];
61
+ }
62
+ // --- SEARCH by text (simple contains on title + content) ---
63
+ export async function searchByText(domain, text, limit) {
64
+ const all = await queryByDomain(domain, 500);
65
+ const lower = text.toLowerCase();
66
+ const filtered = all.filter((e) => e.title.toLowerCase().includes(lower) ||
67
+ e.content.toLowerCase().includes(lower) ||
68
+ (e.tags && e.tags.some((t) => t.toLowerCase().includes(lower))));
69
+ return limit ? filtered.slice(0, limit) : filtered;
70
+ }
71
+ // --- DELETE ---
72
+ export async function deleteEntry(domain, id) {
73
+ await ddb.send(new DeleteCommand({ TableName: TABLE, Key: { domain, id } }));
74
+ }
75
+ // --- COUNT entries in a domain ---
76
+ export async function countByDomain(domain) {
77
+ const res = await ddb.send(new QueryCommand({
78
+ TableName: TABLE,
79
+ KeyConditionExpression: "#d = :domain",
80
+ ExpressionAttributeNames: { "#d": "domain" },
81
+ ExpressionAttributeValues: { ":domain": domain },
82
+ Select: "COUNT",
83
+ }));
84
+ return res.Count || 0;
85
+ }
@@ -0,0 +1,2 @@
1
+ export declare function getEmbedding(text: string): Promise<number[]>;
2
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Bedrock Titan Embeddings — Gera embeddings para semantic search.
3
+ * Model: amazon.titan-embed-text-v2:0 (256 dimensions)
4
+ * Custo: ~$0.0002 per 1K input tokens
5
+ */
6
+ import { BedrockRuntimeClient, InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime";
7
+ const isLocal = process.env.USE_LOCALSTACK === "true";
8
+ const bedrock = new BedrockRuntimeClient({
9
+ region: process.env.AWS_REGION || "sa-east-1",
10
+ ...(isLocal && {
11
+ endpoint: "http://localhost:4566",
12
+ credentials: { accessKeyId: "test", secretAccessKey: "test" },
13
+ }),
14
+ });
15
+ const MODEL_ID = "amazon.titan-embed-text-v2:0";
16
+ const DIMENSIONS = 256;
17
+ export async function getEmbedding(text) {
18
+ const body = JSON.stringify({ inputText: text.slice(0, 8000), dimensions: DIMENSIONS });
19
+ const res = await bedrock.send(new InvokeModelCommand({
20
+ modelId: MODEL_ID,
21
+ body: new TextEncoder().encode(body),
22
+ contentType: "application/json",
23
+ accept: "application/json",
24
+ }));
25
+ const output = JSON.parse(new TextDecoder().decode(res.body));
26
+ return output.embedding;
27
+ }
28
+ export function cosineSimilarity(a, b) {
29
+ let dot = 0, normA = 0, normB = 0;
30
+ for (let i = 0; i < a.length; i++) {
31
+ dot += a[i] * b[i];
32
+ normA += a[i] * a[i];
33
+ normB += b[i] * b[i];
34
+ }
35
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB));
36
+ }
@@ -0,0 +1,8 @@
1
+ export declare function loadCodeStandards(): Promise<Record<string, unknown>>;
2
+ export declare function loadDecisions(): Promise<Record<string, unknown>>;
3
+ export declare function loadGlossary(): Promise<Record<string, unknown>>;
4
+ export declare function loadIntegrations(): Promise<Record<string, unknown>>;
5
+ export declare function loadSkill(name: string): Promise<string>;
6
+ export declare function listSkills(): Promise<string[]>;
7
+ export declare function loadIndex(): Promise<Record<string, unknown>>;
8
+ export declare function loadTemplate(name: string): Promise<string>;