opc-agent 2.1.0 → 3.0.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 (144) hide show
  1. package/README.md +603 -545
  2. package/dist/channels/voice.d.ts +59 -0
  3. package/dist/channels/voice.js +351 -1
  4. package/dist/cli.js +172 -1
  5. package/dist/core/agent.d.ts +4 -0
  6. package/dist/core/agent.js +35 -0
  7. package/dist/core/collaboration.d.ts +89 -0
  8. package/dist/core/collaboration.js +201 -0
  9. package/dist/deploy/index.d.ts +40 -0
  10. package/dist/deploy/index.js +261 -0
  11. package/dist/index.d.ts +7 -1
  12. package/dist/index.js +47 -3
  13. package/dist/mcp/servers/calculator-mcp.d.ts +3 -0
  14. package/dist/mcp/servers/calculator-mcp.js +65 -0
  15. package/dist/mcp/servers/crypto-mcp.d.ts +3 -0
  16. package/dist/mcp/servers/crypto-mcp.js +108 -0
  17. package/dist/mcp/servers/database-mcp.d.ts +3 -0
  18. package/dist/mcp/servers/database-mcp.js +73 -0
  19. package/dist/mcp/servers/datetime-mcp.d.ts +3 -0
  20. package/dist/mcp/servers/datetime-mcp.js +71 -0
  21. package/dist/mcp/servers/filesystem.d.ts +3 -0
  22. package/dist/mcp/servers/filesystem.js +101 -0
  23. package/dist/mcp/servers/github-mcp.d.ts +3 -0
  24. package/dist/mcp/servers/github-mcp.js +60 -0
  25. package/dist/mcp/servers/index.d.ts +21 -0
  26. package/dist/mcp/servers/index.js +50 -0
  27. package/dist/mcp/servers/json-mcp.d.ts +3 -0
  28. package/dist/mcp/servers/json-mcp.js +126 -0
  29. package/dist/mcp/servers/memory-mcp.d.ts +3 -0
  30. package/dist/mcp/servers/memory-mcp.js +60 -0
  31. package/dist/mcp/servers/regex-mcp.d.ts +3 -0
  32. package/dist/mcp/servers/regex-mcp.js +56 -0
  33. package/dist/mcp/servers/web-mcp.d.ts +3 -0
  34. package/dist/mcp/servers/web-mcp.js +51 -0
  35. package/dist/schema/oad.d.ts +292 -12
  36. package/dist/schema/oad.js +12 -1
  37. package/dist/security/guardrails.d.ts +50 -0
  38. package/dist/security/guardrails.js +197 -0
  39. package/dist/studio/server.d.ts +31 -1
  40. package/dist/studio/server.js +154 -3
  41. package/dist/studio-ui/index.html +1278 -662
  42. package/dist/tools/integrations/calendar.d.ts +3 -0
  43. package/dist/tools/integrations/calendar.js +73 -0
  44. package/dist/tools/integrations/code-exec.d.ts +3 -0
  45. package/dist/tools/integrations/code-exec.js +42 -0
  46. package/dist/tools/integrations/csv-analyzer.d.ts +3 -0
  47. package/dist/tools/integrations/csv-analyzer.js +142 -0
  48. package/dist/tools/integrations/database.d.ts +3 -0
  49. package/dist/tools/integrations/database.js +44 -0
  50. package/dist/tools/integrations/email-send.d.ts +3 -0
  51. package/dist/tools/integrations/email-send.js +104 -0
  52. package/dist/tools/integrations/git-tool.d.ts +3 -0
  53. package/dist/tools/integrations/git-tool.js +49 -0
  54. package/dist/tools/integrations/github-tool.d.ts +3 -0
  55. package/dist/tools/integrations/github-tool.js +77 -0
  56. package/dist/tools/integrations/image-gen.d.ts +3 -0
  57. package/dist/tools/integrations/image-gen.js +58 -0
  58. package/dist/tools/integrations/index.d.ts +30 -0
  59. package/dist/tools/integrations/index.js +107 -0
  60. package/dist/tools/integrations/jira.d.ts +3 -0
  61. package/dist/tools/integrations/jira.js +85 -0
  62. package/dist/tools/integrations/notion.d.ts +3 -0
  63. package/dist/tools/integrations/notion.js +71 -0
  64. package/dist/tools/integrations/npm-tool.d.ts +3 -0
  65. package/dist/tools/integrations/npm-tool.js +49 -0
  66. package/dist/tools/integrations/pdf-reader.d.ts +3 -0
  67. package/dist/tools/integrations/pdf-reader.js +91 -0
  68. package/dist/tools/integrations/slack.d.ts +3 -0
  69. package/dist/tools/integrations/slack.js +67 -0
  70. package/dist/tools/integrations/summarizer.d.ts +3 -0
  71. package/dist/tools/integrations/summarizer.js +49 -0
  72. package/dist/tools/integrations/translator.d.ts +3 -0
  73. package/dist/tools/integrations/translator.js +48 -0
  74. package/dist/tools/integrations/trello.d.ts +3 -0
  75. package/dist/tools/integrations/trello.js +60 -0
  76. package/dist/tools/integrations/vector-search.d.ts +3 -0
  77. package/dist/tools/integrations/vector-search.js +44 -0
  78. package/dist/tools/integrations/web-scraper.d.ts +3 -0
  79. package/dist/tools/integrations/web-scraper.js +48 -0
  80. package/dist/tools/integrations/web-search.d.ts +3 -0
  81. package/dist/tools/integrations/web-search.js +60 -0
  82. package/dist/tools/integrations/webhook.d.ts +3 -0
  83. package/dist/tools/integrations/webhook.js +39 -0
  84. package/dist/ui/components.d.ts +10 -0
  85. package/dist/ui/components.js +123 -0
  86. package/package.json +1 -1
  87. package/src/channels/voice.ts +365 -0
  88. package/src/cli.ts +176 -2
  89. package/src/core/agent.ts +38 -0
  90. package/src/core/collaboration.ts +275 -0
  91. package/src/deploy/index.ts +255 -0
  92. package/src/index.ts +21 -1
  93. package/src/mcp/servers/calculator-mcp.ts +65 -0
  94. package/src/mcp/servers/crypto-mcp.ts +73 -0
  95. package/src/mcp/servers/database-mcp.ts +72 -0
  96. package/src/mcp/servers/datetime-mcp.ts +69 -0
  97. package/src/mcp/servers/filesystem.ts +66 -0
  98. package/src/mcp/servers/github-mcp.ts +58 -0
  99. package/src/mcp/servers/index.ts +63 -0
  100. package/src/mcp/servers/json-mcp.ts +102 -0
  101. package/src/mcp/servers/memory-mcp.ts +56 -0
  102. package/src/mcp/servers/regex-mcp.ts +53 -0
  103. package/src/mcp/servers/web-mcp.ts +49 -0
  104. package/src/schema/oad.ts +13 -0
  105. package/src/security/guardrails.ts +248 -0
  106. package/src/studio/server.ts +166 -4
  107. package/src/studio-ui/index.html +1278 -662
  108. package/src/tools/integrations/calendar.ts +73 -0
  109. package/src/tools/integrations/code-exec.ts +39 -0
  110. package/src/tools/integrations/csv-analyzer.ts +92 -0
  111. package/src/tools/integrations/database.ts +44 -0
  112. package/src/tools/integrations/email-send.ts +76 -0
  113. package/src/tools/integrations/git-tool.ts +42 -0
  114. package/src/tools/integrations/github-tool.ts +76 -0
  115. package/src/tools/integrations/image-gen.ts +56 -0
  116. package/src/tools/integrations/index.ts +92 -0
  117. package/src/tools/integrations/jira.ts +83 -0
  118. package/src/tools/integrations/notion.ts +71 -0
  119. package/src/tools/integrations/npm-tool.ts +48 -0
  120. package/src/tools/integrations/pdf-reader.ts +58 -0
  121. package/src/tools/integrations/slack.ts +65 -0
  122. package/src/tools/integrations/summarizer.ts +49 -0
  123. package/src/tools/integrations/translator.ts +48 -0
  124. package/src/tools/integrations/trello.ts +60 -0
  125. package/src/tools/integrations/vector-search.ts +42 -0
  126. package/src/tools/integrations/web-scraper.ts +47 -0
  127. package/src/tools/integrations/web-search.ts +58 -0
  128. package/src/tools/integrations/webhook.ts +38 -0
  129. package/src/ui/components.ts +127 -0
  130. package/tests/brain-seed-extended.test.ts +490 -0
  131. package/tests/collaboration.test.ts +319 -0
  132. package/tests/deploy-and-dag.test.ts +196 -0
  133. package/tests/guardrails.test.ts +177 -0
  134. package/tests/integrations.test.ts +249 -0
  135. package/tests/mcp-servers.test.ts +260 -0
  136. package/tests/voice-enhanced.test.ts +169 -0
  137. package/dist/dtv/data.d.ts +0 -18
  138. package/dist/dtv/data.js +0 -25
  139. package/dist/dtv/trust.d.ts +0 -19
  140. package/dist/dtv/trust.js +0 -40
  141. package/dist/dtv/value.d.ts +0 -23
  142. package/dist/dtv/value.js +0 -38
  143. package/dist/marketplace/index.d.ts +0 -34
  144. package/dist/marketplace/index.js +0 -202
@@ -0,0 +1,73 @@
1
+ import * as crypto from 'crypto';
2
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
3
+
4
+ export function createCryptoServer(): MCPServerConfig {
5
+ return {
6
+ name: 'crypto',
7
+ version: '1.0.0',
8
+ tools: [
9
+ {
10
+ name: 'crypto_hash',
11
+ description: 'Generate hash of input text (md5, sha1, sha256, sha512)',
12
+ inputSchema: { type: 'object', properties: { text: { type: 'string' }, algorithm: { type: 'string', enum: ['md5', 'sha1', 'sha256', 'sha512'], default: 'sha256' } }, required: ['text'] },
13
+ handler: async (args: { text: string; algorithm?: string }) => {
14
+ const hash = crypto.createHash(args.algorithm || 'sha256').update(args.text).digest('hex');
15
+ return { hash, algorithm: args.algorithm || 'sha256' };
16
+ },
17
+ },
18
+ {
19
+ name: 'crypto_hmac',
20
+ description: 'Generate HMAC signature',
21
+ inputSchema: { type: 'object', properties: { text: { type: 'string' }, key: { type: 'string' }, algorithm: { type: 'string', default: 'sha256' } }, required: ['text', 'key'] },
22
+ handler: async (args: { text: string; key: string; algorithm?: string }) => {
23
+ const hmac = crypto.createHmac(args.algorithm || 'sha256', args.key).update(args.text).digest('hex');
24
+ return { hmac, algorithm: args.algorithm || 'sha256' };
25
+ },
26
+ },
27
+ {
28
+ name: 'crypto_random',
29
+ description: 'Generate random bytes, UUID, or random number',
30
+ inputSchema: { type: 'object', properties: { type: { type: 'string', enum: ['bytes', 'uuid', 'number'], default: 'uuid' }, length: { type: 'number', default: 32 }, min: { type: 'number' }, max: { type: 'number' } }, required: [] },
31
+ handler: async (args: { type?: string; length?: number; min?: number; max?: number }) => {
32
+ switch (args.type || 'uuid') {
33
+ case 'bytes': return { value: crypto.randomBytes(args.length || 32).toString('hex') };
34
+ case 'uuid': return { value: crypto.randomUUID() };
35
+ case 'number': {
36
+ const min = args.min ?? 0;
37
+ const max = args.max ?? 100;
38
+ return { value: min + Math.floor(Math.random() * (max - min + 1)) };
39
+ }
40
+ default: throw new Error('Unknown type');
41
+ }
42
+ },
43
+ },
44
+ {
45
+ name: 'crypto_encrypt',
46
+ description: 'Encrypt text with AES-256-GCM',
47
+ inputSchema: { type: 'object', properties: { text: { type: 'string' }, password: { type: 'string' } }, required: ['text', 'password'] },
48
+ handler: async (args: { text: string; password: string }) => {
49
+ const key = crypto.scryptSync(args.password, 'opc-salt', 32);
50
+ const iv = crypto.randomBytes(16);
51
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
52
+ let encrypted = cipher.update(args.text, 'utf8', 'hex');
53
+ encrypted += cipher.final('hex');
54
+ const tag = cipher.getAuthTag().toString('hex');
55
+ return { encrypted, iv: iv.toString('hex'), tag };
56
+ },
57
+ },
58
+ {
59
+ name: 'crypto_decrypt',
60
+ description: 'Decrypt AES-256-GCM encrypted text',
61
+ inputSchema: { type: 'object', properties: { encrypted: { type: 'string' }, password: { type: 'string' }, iv: { type: 'string' }, tag: { type: 'string' } }, required: ['encrypted', 'password', 'iv', 'tag'] },
62
+ handler: async (args: { encrypted: string; password: string; iv: string; tag: string }) => {
63
+ const key = crypto.scryptSync(args.password, 'opc-salt', 32);
64
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, Buffer.from(args.iv, 'hex'));
65
+ decipher.setAuthTag(Buffer.from(args.tag, 'hex'));
66
+ let decrypted = decipher.update(args.encrypted, 'hex', 'utf8');
67
+ decrypted += decipher.final('utf8');
68
+ return { decrypted };
69
+ },
70
+ },
71
+ ],
72
+ };
73
+ }
@@ -0,0 +1,72 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+
3
+ // In-memory SQL-like database (no external deps)
4
+ interface Table { columns: string[]; rows: any[][] }
5
+
6
+ export function createDatabaseServer(): MCPServerConfig {
7
+ const tables = new Map<string, Table>();
8
+
9
+ return {
10
+ name: 'database',
11
+ version: '1.0.0',
12
+ tools: [
13
+ {
14
+ name: 'db_create_table',
15
+ description: 'Create a table with specified columns',
16
+ inputSchema: { type: 'object', properties: { table: { type: 'string' }, columns: { type: 'array', items: { type: 'string' } } }, required: ['table', 'columns'] },
17
+ handler: async (args: { table: string; columns: string[] }) => {
18
+ tables.set(args.table, { columns: args.columns, rows: [] });
19
+ return { created: args.table, columns: args.columns };
20
+ },
21
+ },
22
+ {
23
+ name: 'db_insert',
24
+ description: 'Insert a row into a table',
25
+ inputSchema: { type: 'object', properties: { table: { type: 'string' }, values: { type: 'object' } }, required: ['table', 'values'] },
26
+ handler: async (args: { table: string; values: Record<string, any> }) => {
27
+ const t = tables.get(args.table);
28
+ if (!t) throw new Error(`Table ${args.table} not found`);
29
+ const row = t.columns.map(c => args.values[c] ?? null);
30
+ t.rows.push(row);
31
+ return { inserted: true, rowIndex: t.rows.length - 1 };
32
+ },
33
+ },
34
+ {
35
+ name: 'db_query',
36
+ description: 'Query a table with optional where clause',
37
+ inputSchema: { type: 'object', properties: { table: { type: 'string' }, where: { type: 'object' }, limit: { type: 'number' } }, required: ['table'] },
38
+ handler: async (args: { table: string; where?: Record<string, any>; limit?: number }) => {
39
+ const t = tables.get(args.table);
40
+ if (!t) throw new Error(`Table ${args.table} not found`);
41
+ let results = t.rows.map(row => {
42
+ const obj: Record<string, any> = {};
43
+ t.columns.forEach((c, i) => obj[c] = row[i]);
44
+ return obj;
45
+ });
46
+ if (args.where) {
47
+ results = results.filter(row => Object.entries(args.where!).every(([k, v]) => row[k] === v));
48
+ }
49
+ if (args.limit) results = results.slice(0, args.limit);
50
+ return { rows: results, count: results.length };
51
+ },
52
+ },
53
+ {
54
+ name: 'db_list_tables',
55
+ description: 'List all tables',
56
+ inputSchema: { type: 'object', properties: {} },
57
+ handler: async () => {
58
+ return { tables: Array.from(tables.entries()).map(([name, t]) => ({ name, columns: t.columns, rowCount: t.rows.length })) };
59
+ },
60
+ },
61
+ {
62
+ name: 'db_drop_table',
63
+ description: 'Drop a table',
64
+ inputSchema: { type: 'object', properties: { table: { type: 'string' } }, required: ['table'] },
65
+ handler: async (args: { table: string }) => {
66
+ const existed = tables.delete(args.table);
67
+ return { dropped: existed };
68
+ },
69
+ },
70
+ ],
71
+ };
72
+ }
@@ -0,0 +1,69 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+
3
+ const TIMEZONE_OFFSETS: Record<string, number> = {
4
+ 'UTC': 0, 'GMT': 0, 'EST': -5, 'EDT': -4, 'CST': -6, 'CDT': -5,
5
+ 'MST': -7, 'MDT': -6, 'PST': -8, 'PDT': -7, 'JST': 9, 'KST': 9,
6
+ 'CST8': 8, 'IST': 5.5, 'CET': 1, 'CEST': 2, 'AEST': 10, 'AEDT': 11,
7
+ 'Asia/Shanghai': 8, 'Asia/Tokyo': 9, 'America/New_York': -4,
8
+ 'America/Los_Angeles': -7, 'Europe/London': 1, 'Europe/Berlin': 2,
9
+ };
10
+
11
+ export function createDateTimeServer(): MCPServerConfig {
12
+ return {
13
+ name: 'datetime',
14
+ version: '1.0.0',
15
+ tools: [
16
+ {
17
+ name: 'dt_now',
18
+ description: 'Get current date/time in a timezone',
19
+ inputSchema: { type: 'object', properties: { timezone: { type: 'string', default: 'UTC' }, format: { type: 'string', enum: ['iso', 'unix', 'human'], default: 'iso' } } },
20
+ handler: async (args: { timezone?: string; format?: string }) => {
21
+ const offset = TIMEZONE_OFFSETS[args.timezone || 'UTC'] ?? 0;
22
+ const now = new Date(Date.now() + offset * 3600000);
23
+ const fmt = args.format || 'iso';
24
+ return {
25
+ iso: now.toISOString(),
26
+ unix: Math.floor(now.getTime() / 1000),
27
+ human: now.toUTCString(),
28
+ timezone: args.timezone || 'UTC',
29
+ offset,
30
+ };
31
+ },
32
+ },
33
+ {
34
+ name: 'dt_diff',
35
+ description: 'Calculate difference between two dates',
36
+ inputSchema: { type: 'object', properties: { from: { type: 'string' }, to: { type: 'string' }, unit: { type: 'string', enum: ['days', 'hours', 'minutes', 'seconds'], default: 'days' } }, required: ['from', 'to'] },
37
+ handler: async (args: { from: string; to: string; unit?: string }) => {
38
+ const d1 = new Date(args.from).getTime();
39
+ const d2 = new Date(args.to).getTime();
40
+ const diffMs = d2 - d1;
41
+ const divisors: Record<string, number> = { seconds: 1000, minutes: 60000, hours: 3600000, days: 86400000 };
42
+ const unit = args.unit || 'days';
43
+ return { from: args.from, to: args.to, difference: diffMs / divisors[unit], unit };
44
+ },
45
+ },
46
+ {
47
+ name: 'dt_add',
48
+ description: 'Add duration to a date',
49
+ inputSchema: { type: 'object', properties: { date: { type: 'string' }, amount: { type: 'number' }, unit: { type: 'string', enum: ['days', 'hours', 'minutes', 'seconds'] } }, required: ['date', 'amount', 'unit'] },
50
+ handler: async (args: { date: string; amount: number; unit: string }) => {
51
+ const d = new Date(args.date);
52
+ const ms: Record<string, number> = { seconds: 1000, minutes: 60000, hours: 3600000, days: 86400000 };
53
+ const result = new Date(d.getTime() + args.amount * ms[args.unit]);
54
+ return { original: args.date, result: result.toISOString(), added: `${args.amount} ${args.unit}` };
55
+ },
56
+ },
57
+ {
58
+ name: 'dt_parse',
59
+ description: 'Parse a date string and return components',
60
+ inputSchema: { type: 'object', properties: { date: { type: 'string' } }, required: ['date'] },
61
+ handler: async (args: { date: string }) => {
62
+ const d = new Date(args.date);
63
+ if (isNaN(d.getTime())) throw new Error('Invalid date');
64
+ return { iso: d.toISOString(), year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate(), dayOfWeek: d.toLocaleDateString('en', { weekday: 'long' }), unix: Math.floor(d.getTime() / 1000) };
65
+ },
66
+ },
67
+ ],
68
+ };
69
+ }
@@ -0,0 +1,66 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
4
+
5
+ export function createFilesystemServer(rootDir: string = process.cwd()): MCPServerConfig {
6
+ const resolve = (p: string) => {
7
+ const resolved = path.resolve(rootDir, p);
8
+ if (!resolved.startsWith(path.resolve(rootDir))) throw new Error('Path traversal not allowed');
9
+ return resolved;
10
+ };
11
+
12
+ return {
13
+ name: 'filesystem',
14
+ version: '1.0.0',
15
+ tools: [
16
+ {
17
+ name: 'fs_read',
18
+ description: 'Read file contents as UTF-8 text',
19
+ inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'File path relative to root' } }, required: ['path'] },
20
+ handler: async (args: { path: string }) => {
21
+ return { content: fs.readFileSync(resolve(args.path), 'utf-8') };
22
+ },
23
+ },
24
+ {
25
+ name: 'fs_write',
26
+ description: 'Write content to a file (creates directories as needed)',
27
+ inputSchema: { type: 'object', properties: { path: { type: 'string' }, content: { type: 'string' } }, required: ['path', 'content'] },
28
+ handler: async (args: { path: string; content: string }) => {
29
+ const target = resolve(args.path);
30
+ fs.mkdirSync(path.dirname(target), { recursive: true });
31
+ fs.writeFileSync(target, args.content, 'utf-8');
32
+ return { written: target };
33
+ },
34
+ },
35
+ {
36
+ name: 'fs_list',
37
+ description: 'List files and directories',
38
+ inputSchema: { type: 'object', properties: { path: { type: 'string', default: '.' }, recursive: { type: 'boolean', default: false } }, required: [] },
39
+ handler: async (args: { path?: string; recursive?: boolean }) => {
40
+ const dir = resolve(args.path || '.');
41
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
42
+ const result = entries.map(e => ({ name: e.name, type: e.isDirectory() ? 'directory' : 'file' }));
43
+ return { entries: result };
44
+ },
45
+ },
46
+ {
47
+ name: 'fs_stat',
48
+ description: 'Get file/directory metadata',
49
+ inputSchema: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] },
50
+ handler: async (args: { path: string }) => {
51
+ const stat = fs.statSync(resolve(args.path));
52
+ return { size: stat.size, isFile: stat.isFile(), isDirectory: stat.isDirectory(), modified: stat.mtime.toISOString() };
53
+ },
54
+ },
55
+ {
56
+ name: 'fs_delete',
57
+ description: 'Delete a file',
58
+ inputSchema: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] },
59
+ handler: async (args: { path: string }) => {
60
+ fs.unlinkSync(resolve(args.path));
61
+ return { deleted: true };
62
+ },
63
+ },
64
+ ],
65
+ };
66
+ }
@@ -0,0 +1,58 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+
3
+ export function createGitHubServer(token?: string): MCPServerConfig {
4
+ const headers: Record<string, string> = {
5
+ 'Accept': 'application/vnd.github.v3+json',
6
+ 'User-Agent': 'opc-mcp-github/1.0',
7
+ };
8
+ if (token) headers['Authorization'] = `Bearer ${token}`;
9
+
10
+ const ghFetch = async (path: string, opts: any = {}) => {
11
+ const res = await fetch(`https://api.github.com${path}`, { ...opts, headers: { ...headers, ...opts.headers } });
12
+ if (!res.ok) throw new Error(`GitHub API ${res.status}: ${await res.text()}`);
13
+ return res.json();
14
+ };
15
+
16
+ return {
17
+ name: 'github',
18
+ version: '1.0.0',
19
+ tools: [
20
+ {
21
+ name: 'github_get_repo',
22
+ description: 'Get repository information',
23
+ inputSchema: { type: 'object', properties: { owner: { type: 'string' }, repo: { type: 'string' } }, required: ['owner', 'repo'] },
24
+ handler: async (args: { owner: string; repo: string }) => ghFetch(`/repos/${args.owner}/${args.repo}`),
25
+ },
26
+ {
27
+ name: 'github_list_issues',
28
+ description: 'List repository issues',
29
+ inputSchema: { type: 'object', properties: { owner: { type: 'string' }, repo: { type: 'string' }, state: { type: 'string', enum: ['open', 'closed', 'all'], default: 'open' } }, required: ['owner', 'repo'] },
30
+ handler: async (args: { owner: string; repo: string; state?: string }) => ghFetch(`/repos/${args.owner}/${args.repo}/issues?state=${args.state || 'open'}`),
31
+ },
32
+ {
33
+ name: 'github_create_issue',
34
+ description: 'Create a new issue',
35
+ inputSchema: { type: 'object', properties: { owner: { type: 'string' }, repo: { type: 'string' }, title: { type: 'string' }, body: { type: 'string' } }, required: ['owner', 'repo', 'title'] },
36
+ handler: async (args: { owner: string; repo: string; title: string; body?: string }) =>
37
+ ghFetch(`/repos/${args.owner}/${args.repo}/issues`, { method: 'POST', body: JSON.stringify({ title: args.title, body: args.body }), headers: { 'Content-Type': 'application/json' } }),
38
+ },
39
+ {
40
+ name: 'github_search_repos',
41
+ description: 'Search GitHub repositories',
42
+ inputSchema: { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] },
43
+ handler: async (args: { query: string }) => ghFetch(`/search/repositories?q=${encodeURIComponent(args.query)}`),
44
+ },
45
+ {
46
+ name: 'github_get_file',
47
+ description: 'Get file contents from a repository',
48
+ inputSchema: { type: 'object', properties: { owner: { type: 'string' }, repo: { type: 'string' }, path: { type: 'string' }, ref: { type: 'string' } }, required: ['owner', 'repo', 'path'] },
49
+ handler: async (args: { owner: string; repo: string; path: string; ref?: string }) => {
50
+ const q = args.ref ? `?ref=${args.ref}` : '';
51
+ const data: any = await ghFetch(`/repos/${args.owner}/${args.repo}/contents/${args.path}${q}`);
52
+ if (data.content) data.decoded = Buffer.from(data.content, 'base64').toString('utf-8');
53
+ return data;
54
+ },
55
+ },
56
+ ],
57
+ };
58
+ }
@@ -0,0 +1,63 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+ import { createFilesystemServer } from './filesystem';
3
+ import { createGitHubServer } from './github-mcp';
4
+ import { createDatabaseServer } from './database-mcp';
5
+ import { createWebServer } from './web-mcp';
6
+ import { createMemoryServer } from './memory-mcp';
7
+ import { createCalculatorServer } from './calculator-mcp';
8
+ import { createDateTimeServer } from './datetime-mcp';
9
+ import { createJsonServer } from './json-mcp';
10
+ import { createRegexServer } from './regex-mcp';
11
+ import { createCryptoServer } from './crypto-mcp';
12
+
13
+ export interface MCPServerInfo {
14
+ name: string;
15
+ description: string;
16
+ version: string;
17
+ toolCount: number;
18
+ }
19
+
20
+ interface ServerEntry {
21
+ name: string;
22
+ description: string;
23
+ factory: () => MCPServerConfig;
24
+ }
25
+
26
+ const SERVERS: ServerEntry[] = [
27
+ { name: 'filesystem', description: 'Read/write/list files in a sandboxed directory', factory: () => createFilesystemServer() },
28
+ { name: 'github', description: 'GitHub API — repos, issues, files via fetch', factory: () => createGitHubServer() },
29
+ { name: 'database', description: 'In-memory SQL-like database with tables and queries', factory: () => createDatabaseServer() },
30
+ { name: 'web', description: 'Web fetch, text extraction, and search', factory: () => createWebServer() },
31
+ { name: 'memory', description: 'Key-value memory store with tags and search', factory: () => createMemoryServer() },
32
+ { name: 'calculator', description: 'Math evaluation, unit conversion, percentages', factory: () => createCalculatorServer() },
33
+ { name: 'datetime', description: 'Time zones, date math, parsing, and formatting', factory: () => createDateTimeServer() },
34
+ { name: 'json', description: 'JSON path query, transform, validate, and diff', factory: () => createJsonServer() },
35
+ { name: 'regex', description: 'Regex test, match, replace, and split', factory: () => createRegexServer() },
36
+ { name: 'crypto', description: 'Hash, HMAC, encrypt/decrypt, random generation', factory: () => createCryptoServer() },
37
+ ];
38
+
39
+ export function getMCPServer(name: string): MCPServerConfig {
40
+ const entry = SERVERS.find(s => s.name === name);
41
+ if (!entry) throw new Error(`MCP server '${name}' not found. Available: ${SERVERS.map(s => s.name).join(', ')}`);
42
+ return entry.factory();
43
+ }
44
+
45
+ export function listMCPServers(): MCPServerInfo[] {
46
+ return SERVERS.map(s => {
47
+ const config = s.factory();
48
+ return { name: s.name, description: s.description, version: config.version, toolCount: config.tools?.length || 0 };
49
+ });
50
+ }
51
+
52
+ export {
53
+ createFilesystemServer,
54
+ createGitHubServer,
55
+ createDatabaseServer,
56
+ createWebServer,
57
+ createMemoryServer,
58
+ createCalculatorServer,
59
+ createDateTimeServer,
60
+ createJsonServer,
61
+ createRegexServer,
62
+ createCryptoServer,
63
+ };
@@ -0,0 +1,102 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+
3
+ function jsonPathQuery(obj: any, path: string): any[] {
4
+ const parts = path.replace(/^\$\.?/, '').split('.');
5
+ let current: any[] = [obj];
6
+ for (const part of parts) {
7
+ if (!part) continue;
8
+ const next: any[] = [];
9
+ for (const item of current) {
10
+ if (part === '*') {
11
+ if (Array.isArray(item)) next.push(...item);
12
+ else if (typeof item === 'object' && item) next.push(...Object.values(item));
13
+ } else if (part.match(/^\[(\d+)\]$/)) {
14
+ const idx = parseInt(part.slice(1, -1));
15
+ if (Array.isArray(item) && item[idx] !== undefined) next.push(item[idx]);
16
+ } else {
17
+ if (item && typeof item === 'object' && part in item) next.push(item[part]);
18
+ }
19
+ }
20
+ current = next;
21
+ }
22
+ return current;
23
+ }
24
+
25
+ export function createJsonServer(): MCPServerConfig {
26
+ return {
27
+ name: 'json',
28
+ version: '1.0.0',
29
+ tools: [
30
+ {
31
+ name: 'json_query',
32
+ description: 'Query JSON data using dot-notation path (e.g. "users.0.name", "items.*")',
33
+ inputSchema: { type: 'object', properties: { data: { description: 'JSON string or object' }, path: { type: 'string', description: 'Dot-notation path' } }, required: ['data', 'path'] },
34
+ handler: async (args: { data: any; path: string }) => {
35
+ const obj = typeof args.data === 'string' ? JSON.parse(args.data) : args.data;
36
+ return { results: jsonPathQuery(obj, args.path) };
37
+ },
38
+ },
39
+ {
40
+ name: 'json_transform',
41
+ description: 'Transform JSON: pick fields, rename keys, flatten',
42
+ inputSchema: { type: 'object', properties: { data: {}, operation: { type: 'string', enum: ['pick', 'omit', 'flatten', 'keys', 'values'] }, fields: { type: 'array', items: { type: 'string' } } }, required: ['data', 'operation'] },
43
+ handler: async (args: { data: any; operation: string; fields?: string[] }) => {
44
+ const obj = typeof args.data === 'string' ? JSON.parse(args.data) : args.data;
45
+ switch (args.operation) {
46
+ case 'pick': {
47
+ const result: any = {};
48
+ for (const f of args.fields || []) if (f in obj) result[f] = obj[f];
49
+ return { result };
50
+ }
51
+ case 'omit': {
52
+ const result = { ...obj };
53
+ for (const f of args.fields || []) delete result[f];
54
+ return { result };
55
+ }
56
+ case 'flatten': {
57
+ const result: Record<string, any> = {};
58
+ const recurse = (o: any, prefix: string) => {
59
+ for (const [k, v] of Object.entries(o)) {
60
+ const key = prefix ? `${prefix}.${k}` : k;
61
+ if (v && typeof v === 'object' && !Array.isArray(v)) recurse(v, key);
62
+ else result[key] = v;
63
+ }
64
+ };
65
+ recurse(obj, '');
66
+ return { result };
67
+ }
68
+ case 'keys': return { result: Object.keys(obj) };
69
+ case 'values': return { result: Object.values(obj) };
70
+ default: throw new Error(`Unknown operation: ${args.operation}`);
71
+ }
72
+ },
73
+ },
74
+ {
75
+ name: 'json_validate',
76
+ description: 'Check if a string is valid JSON',
77
+ inputSchema: { type: 'object', properties: { data: { type: 'string' } }, required: ['data'] },
78
+ handler: async (args: { data: string }) => {
79
+ try { JSON.parse(args.data); return { valid: true }; } catch (e: any) { return { valid: false, error: e.message }; }
80
+ },
81
+ },
82
+ {
83
+ name: 'json_diff',
84
+ description: 'Compare two JSON objects and return differences',
85
+ inputSchema: { type: 'object', properties: { a: {}, b: {} }, required: ['a', 'b'] },
86
+ handler: async (args: { a: any; b: any }) => {
87
+ const a = typeof args.a === 'string' ? JSON.parse(args.a) : args.a;
88
+ const b = typeof args.b === 'string' ? JSON.parse(args.b) : args.b;
89
+ const diffs: { path: string; a: any; b: any }[] = [];
90
+ const compare = (x: any, y: any, path: string) => {
91
+ if (x === y) return;
92
+ if (typeof x !== typeof y || typeof x !== 'object' || !x || !y) { diffs.push({ path, a: x, b: y }); return; }
93
+ const keys = new Set([...Object.keys(x), ...Object.keys(y)]);
94
+ for (const k of keys) compare(x[k], y[k], path ? `${path}.${k}` : k);
95
+ };
96
+ compare(a, b, '');
97
+ return { equal: diffs.length === 0, differences: diffs };
98
+ },
99
+ },
100
+ ],
101
+ };
102
+ }
@@ -0,0 +1,56 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+
3
+ export function createMemoryServer(): MCPServerConfig {
4
+ const store = new Map<string, { value: any; tags: string[]; created: string; updated: string }>();
5
+
6
+ return {
7
+ name: 'memory',
8
+ version: '1.0.0',
9
+ tools: [
10
+ {
11
+ name: 'memory_store',
12
+ description: 'Store a key-value pair in memory with optional tags',
13
+ inputSchema: { type: 'object', properties: { key: { type: 'string' }, value: { type: 'any' }, tags: { type: 'array', items: { type: 'string' } } }, required: ['key', 'value'] },
14
+ handler: async (args: { key: string; value: any; tags?: string[] }) => {
15
+ const now = new Date().toISOString();
16
+ const existing = store.get(args.key);
17
+ store.set(args.key, { value: args.value, tags: args.tags || [], created: existing?.created || now, updated: now });
18
+ return { stored: args.key };
19
+ },
20
+ },
21
+ {
22
+ name: 'memory_recall',
23
+ description: 'Recall a value by key',
24
+ inputSchema: { type: 'object', properties: { key: { type: 'string' } }, required: ['key'] },
25
+ handler: async (args: { key: string }) => {
26
+ const entry = store.get(args.key);
27
+ if (!entry) return { found: false };
28
+ return { found: true, ...entry };
29
+ },
30
+ },
31
+ {
32
+ name: 'memory_search',
33
+ description: 'Search memory entries by tag or substring in key',
34
+ inputSchema: { type: 'object', properties: { query: { type: 'string' }, tag: { type: 'string' } }, required: [] },
35
+ handler: async (args: { query?: string; tag?: string }) => {
36
+ let results = Array.from(store.entries()).map(([k, v]) => ({ key: k, ...v }));
37
+ if (args.tag) results = results.filter(r => r.tags.includes(args.tag!));
38
+ if (args.query) results = results.filter(r => r.key.includes(args.query!) || JSON.stringify(r.value).includes(args.query!));
39
+ return { results, count: results.length };
40
+ },
41
+ },
42
+ {
43
+ name: 'memory_delete',
44
+ description: 'Delete a memory entry',
45
+ inputSchema: { type: 'object', properties: { key: { type: 'string' } }, required: ['key'] },
46
+ handler: async (args: { key: string }) => ({ deleted: store.delete(args.key) }),
47
+ },
48
+ {
49
+ name: 'memory_list',
50
+ description: 'List all memory keys',
51
+ inputSchema: { type: 'object', properties: {} },
52
+ handler: async () => ({ keys: Array.from(store.keys()), count: store.size }),
53
+ },
54
+ ],
55
+ };
56
+ }
@@ -0,0 +1,53 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+
3
+ export function createRegexServer(): MCPServerConfig {
4
+ return {
5
+ name: 'regex',
6
+ version: '1.0.0',
7
+ tools: [
8
+ {
9
+ name: 'regex_test',
10
+ description: 'Test if a string matches a regex pattern',
11
+ inputSchema: { type: 'object', properties: { pattern: { type: 'string' }, flags: { type: 'string', default: '' }, text: { type: 'string' } }, required: ['pattern', 'text'] },
12
+ handler: async (args: { pattern: string; flags?: string; text: string }) => {
13
+ const re = new RegExp(args.pattern, args.flags || '');
14
+ return { matches: re.test(args.text), pattern: args.pattern };
15
+ },
16
+ },
17
+ {
18
+ name: 'regex_match',
19
+ description: 'Find all matches of a regex in text',
20
+ inputSchema: { type: 'object', properties: { pattern: { type: 'string' }, flags: { type: 'string', default: 'g' }, text: { type: 'string' } }, required: ['pattern', 'text'] },
21
+ handler: async (args: { pattern: string; flags?: string; text: string }) => {
22
+ const re = new RegExp(args.pattern, args.flags || 'g');
23
+ const matches: { match: string; index: number; groups?: Record<string, string> }[] = [];
24
+ let m;
25
+ while ((m = re.exec(args.text)) !== null) {
26
+ matches.push({ match: m[0], index: m.index, groups: m.groups });
27
+ if (!re.global) break;
28
+ }
29
+ return { matches, count: matches.length };
30
+ },
31
+ },
32
+ {
33
+ name: 'regex_replace',
34
+ description: 'Replace matches in text using regex',
35
+ inputSchema: { type: 'object', properties: { pattern: { type: 'string' }, flags: { type: 'string', default: 'g' }, text: { type: 'string' }, replacement: { type: 'string' } }, required: ['pattern', 'text', 'replacement'] },
36
+ handler: async (args: { pattern: string; flags?: string; text: string; replacement: string }) => {
37
+ const re = new RegExp(args.pattern, args.flags || 'g');
38
+ return { result: args.text.replace(re, args.replacement) };
39
+ },
40
+ },
41
+ {
42
+ name: 'regex_split',
43
+ description: 'Split text by regex pattern',
44
+ inputSchema: { type: 'object', properties: { pattern: { type: 'string' }, text: { type: 'string' }, limit: { type: 'number' } }, required: ['pattern', 'text'] },
45
+ handler: async (args: { pattern: string; text: string; limit?: number }) => {
46
+ const re = new RegExp(args.pattern);
47
+ const parts = args.text.split(re, args.limit);
48
+ return { parts, count: parts.length };
49
+ },
50
+ },
51
+ ],
52
+ };
53
+ }