opalserve 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/.env.example +19 -0
  2. package/AGENTS.md +23 -0
  3. package/README.md +109 -0
  4. package/config/servers.example.yaml +67 -0
  5. package/config/servers.yaml +2 -0
  6. package/dist/cli/discover.d.ts +3 -0
  7. package/dist/cli/discover.d.ts.map +1 -0
  8. package/dist/cli/discover.js +160 -0
  9. package/dist/cli/discover.js.map +1 -0
  10. package/dist/cli/index.d.ts +3 -0
  11. package/dist/cli/index.d.ts.map +1 -0
  12. package/dist/cli/index.js +32 -0
  13. package/dist/cli/index.js.map +1 -0
  14. package/dist/connectors/base.d.ts +49 -0
  15. package/dist/connectors/base.d.ts.map +1 -0
  16. package/dist/connectors/base.js +45 -0
  17. package/dist/connectors/base.js.map +1 -0
  18. package/dist/connectors/custom.d.ts +19 -0
  19. package/dist/connectors/custom.d.ts.map +1 -0
  20. package/dist/connectors/custom.js +129 -0
  21. package/dist/connectors/custom.js.map +1 -0
  22. package/dist/connectors/github.d.ts +18 -0
  23. package/dist/connectors/github.d.ts.map +1 -0
  24. package/dist/connectors/github.js +188 -0
  25. package/dist/connectors/github.js.map +1 -0
  26. package/dist/connectors/google-drive.d.ts +18 -0
  27. package/dist/connectors/google-drive.d.ts.map +1 -0
  28. package/dist/connectors/google-drive.js +209 -0
  29. package/dist/connectors/google-drive.js.map +1 -0
  30. package/dist/connectors/index.d.ts +11 -0
  31. package/dist/connectors/index.d.ts.map +1 -0
  32. package/dist/connectors/index.js +76 -0
  33. package/dist/connectors/index.js.map +1 -0
  34. package/dist/connectors/postgres.d.ts +18 -0
  35. package/dist/connectors/postgres.d.ts.map +1 -0
  36. package/dist/connectors/postgres.js +140 -0
  37. package/dist/connectors/postgres.js.map +1 -0
  38. package/dist/connectors/slack.d.ts +18 -0
  39. package/dist/connectors/slack.d.ts.map +1 -0
  40. package/dist/connectors/slack.js +181 -0
  41. package/dist/connectors/slack.js.map +1 -0
  42. package/dist/core/auth.d.ts +26 -0
  43. package/dist/core/auth.d.ts.map +1 -0
  44. package/dist/core/auth.js +81 -0
  45. package/dist/core/auth.js.map +1 -0
  46. package/dist/core/registry.d.ts +33 -0
  47. package/dist/core/registry.d.ts.map +1 -0
  48. package/dist/core/registry.js +237 -0
  49. package/dist/core/registry.js.map +1 -0
  50. package/dist/core/tokenizer.d.ts +16 -0
  51. package/dist/core/tokenizer.d.ts.map +1 -0
  52. package/dist/core/tokenizer.js +29 -0
  53. package/dist/core/tokenizer.js.map +1 -0
  54. package/dist/governance/audit.d.ts +27 -0
  55. package/dist/governance/audit.d.ts.map +1 -0
  56. package/dist/governance/audit.js +149 -0
  57. package/dist/governance/audit.js.map +1 -0
  58. package/dist/governance/index.d.ts +5 -0
  59. package/dist/governance/index.d.ts.map +1 -0
  60. package/dist/governance/index.js +5 -0
  61. package/dist/governance/index.js.map +1 -0
  62. package/dist/governance/policy.d.ts +20 -0
  63. package/dist/governance/policy.d.ts.map +1 -0
  64. package/dist/governance/policy.js +162 -0
  65. package/dist/governance/policy.js.map +1 -0
  66. package/dist/governance/rate-limiter.d.ts +20 -0
  67. package/dist/governance/rate-limiter.d.ts.map +1 -0
  68. package/dist/governance/rate-limiter.js +73 -0
  69. package/dist/governance/rate-limiter.js.map +1 -0
  70. package/dist/governance/types.d.ts +246 -0
  71. package/dist/governance/types.d.ts.map +1 -0
  72. package/dist/governance/types.js +72 -0
  73. package/dist/governance/types.js.map +1 -0
  74. package/dist/identity/access-control.d.ts +15 -0
  75. package/dist/identity/access-control.d.ts.map +1 -0
  76. package/dist/identity/access-control.js +81 -0
  77. package/dist/identity/access-control.js.map +1 -0
  78. package/dist/identity/index.d.ts +4 -0
  79. package/dist/identity/index.d.ts.map +1 -0
  80. package/dist/identity/index.js +4 -0
  81. package/dist/identity/index.js.map +1 -0
  82. package/dist/identity/manager.d.ts +29 -0
  83. package/dist/identity/manager.d.ts.map +1 -0
  84. package/dist/identity/manager.js +167 -0
  85. package/dist/identity/manager.js.map +1 -0
  86. package/dist/identity/types.d.ts +237 -0
  87. package/dist/identity/types.d.ts.map +1 -0
  88. package/dist/identity/types.js +80 -0
  89. package/dist/identity/types.js.map +1 -0
  90. package/dist/index.d.ts +13 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +10 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/registry/server.d.ts +14 -0
  95. package/dist/registry/server.d.ts.map +1 -0
  96. package/dist/registry/server.js +173 -0
  97. package/dist/registry/server.js.map +1 -0
  98. package/dist/types/index.d.ts +639 -0
  99. package/dist/types/index.d.ts.map +1 -0
  100. package/dist/types/index.js +76 -0
  101. package/dist/types/index.js.map +1 -0
  102. package/dist/utils/config.d.ts +29 -0
  103. package/dist/utils/config.d.ts.map +1 -0
  104. package/dist/utils/config.js +47 -0
  105. package/dist/utils/config.js.map +1 -0
  106. package/dist/utils/index.d.ts +7 -0
  107. package/dist/utils/index.d.ts.map +1 -0
  108. package/dist/utils/index.js +44 -0
  109. package/dist/utils/index.js.map +1 -0
  110. package/dist/workflow/engine.d.ts +18 -0
  111. package/dist/workflow/engine.d.ts.map +1 -0
  112. package/dist/workflow/engine.js +155 -0
  113. package/dist/workflow/engine.js.map +1 -0
  114. package/dist/workflow/index.d.ts +4 -0
  115. package/dist/workflow/index.d.ts.map +1 -0
  116. package/dist/workflow/index.js +4 -0
  117. package/dist/workflow/index.js.map +1 -0
  118. package/dist/workflow/templates.d.ts +4 -0
  119. package/dist/workflow/templates.d.ts.map +1 -0
  120. package/dist/workflow/templates.js +218 -0
  121. package/dist/workflow/templates.js.map +1 -0
  122. package/dist/workflow/types.d.ts +255 -0
  123. package/dist/workflow/types.d.ts.map +1 -0
  124. package/dist/workflow/types.js +48 -0
  125. package/dist/workflow/types.js.map +1 -0
  126. package/eslint.config.js +25 -0
  127. package/package.json +78 -0
  128. package/src/cli/discover.ts +223 -0
  129. package/src/cli/index.ts +40 -0
  130. package/src/connectors/base.ts +75 -0
  131. package/src/connectors/custom.ts +139 -0
  132. package/src/connectors/github.ts +195 -0
  133. package/src/connectors/google-drive.ts +217 -0
  134. package/src/connectors/index.ts +86 -0
  135. package/src/connectors/postgres.ts +148 -0
  136. package/src/connectors/slack.ts +188 -0
  137. package/src/core/auth.ts +109 -0
  138. package/src/core/registry.ts +301 -0
  139. package/src/core/tokenizer.ts +40 -0
  140. package/src/governance/audit.ts +182 -0
  141. package/src/governance/index.ts +4 -0
  142. package/src/governance/policy.ts +187 -0
  143. package/src/governance/rate-limiter.ts +95 -0
  144. package/src/governance/types.ts +100 -0
  145. package/src/identity/access-control.ts +119 -0
  146. package/src/identity/index.ts +3 -0
  147. package/src/identity/manager.ts +207 -0
  148. package/src/identity/types.ts +91 -0
  149. package/src/index.ts +16 -0
  150. package/src/registry/server.ts +195 -0
  151. package/src/types/index.ts +128 -0
  152. package/src/utils/config.ts +78 -0
  153. package/src/utils/index.ts +47 -0
  154. package/src/workflow/engine.ts +187 -0
  155. package/src/workflow/index.ts +3 -0
  156. package/src/workflow/templates.ts +220 -0
  157. package/src/workflow/types.ts +89 -0
  158. package/tsconfig.json +25 -0
@@ -0,0 +1,217 @@
1
+ import { BaseConnector } from './base.js';
2
+ import { ConnectorConfig, Tool, ToolDefinition } from '../types/index.js';
3
+
4
+ const GOOGLE_DRIVE_TOOL_DEFS: ToolDefinition[] = [
5
+ {
6
+ name: 'drive_list_files',
7
+ description: 'List files in Google Drive with optional filters',
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ folderId: { type: 'string', description: 'Parent folder ID' },
12
+ mimeType: { type: 'string', description: 'Filter by MIME type' },
13
+ query: { type: 'string', description: 'Search query' },
14
+ pageSize: { type: 'number', default: 100 },
15
+ orderBy: { type: 'string', description: 'Sort order' },
16
+ },
17
+ },
18
+ tags: ['files', 'drive', 'google', 'list'],
19
+ capabilities: ['read', 'list'],
20
+ authRequirements: { required: ['google_service_account'] },
21
+ contextRequirements: { minTokens: 30, maxTokens: 400 },
22
+ },
23
+ {
24
+ name: 'drive_get_file',
25
+ description: 'Get metadata for a specific file',
26
+ inputSchema: {
27
+ type: 'object',
28
+ properties: {
29
+ fileId: { type: 'string', description: 'File ID' },
30
+ fields: { type: 'string', description: 'Fields to return' },
31
+ },
32
+ required: ['fileId'],
33
+ },
34
+ tags: ['files', 'drive', 'google', 'metadata'],
35
+ capabilities: ['read', 'metadata'],
36
+ authRequirements: { required: ['google_service_account'] },
37
+ contextRequirements: { minTokens: 30, maxTokens: 200 },
38
+ },
39
+ {
40
+ name: 'drive_download_file',
41
+ description: 'Download file content from Google Drive',
42
+ inputSchema: {
43
+ type: 'object',
44
+ properties: {
45
+ fileId: { type: 'string', description: 'File ID' },
46
+ mimeType: { type: 'string', description: 'Expected MIME type' },
47
+ },
48
+ required: ['fileId'],
49
+ },
50
+ tags: ['files', 'drive', 'google', 'download'],
51
+ capabilities: ['read', 'download'],
52
+ authRequirements: { required: ['google_service_account'] },
53
+ contextRequirements: { minTokens: 30, maxTokens: 500 },
54
+ },
55
+ {
56
+ name: 'drive_create_file',
57
+ description: 'Create a new file in Google Drive',
58
+ inputSchema: {
59
+ type: 'object',
60
+ properties: {
61
+ name: { type: 'string', description: 'File name' },
62
+ mimeType: { type: 'string', description: 'MIME type' },
63
+ parentFolderId: { type: 'string', description: 'Parent folder ID' },
64
+ content: { type: 'string', description: 'File content' },
65
+ },
66
+ required: ['name', 'mimeType'],
67
+ },
68
+ tags: ['files', 'drive', 'google', 'create'],
69
+ capabilities: ['write', 'create'],
70
+ authRequirements: { required: ['google_service_account'] },
71
+ contextRequirements: { minTokens: 30, maxTokens: 300 },
72
+ },
73
+ {
74
+ name: 'drive_update_file',
75
+ description: 'Update file metadata or content',
76
+ inputSchema: {
77
+ type: 'object',
78
+ properties: {
79
+ fileId: { type: 'string', description: 'File ID' },
80
+ name: { type: 'string', description: 'New file name' },
81
+ content: { type: 'string', description: 'New content' },
82
+ addParents: { type: 'array', items: { type: 'string' }, description: 'Parent folder IDs to add' },
83
+ removeParents: { type: 'array', items: { type: 'string' }, description: 'Parent folder IDs to remove' },
84
+ },
85
+ required: ['fileId'],
86
+ },
87
+ tags: ['files', 'drive', 'google', 'update'],
88
+ capabilities: ['write', 'update'],
89
+ authRequirements: { required: ['google_service_account'] },
90
+ contextRequirements: { minTokens: 30, maxTokens: 300 },
91
+ },
92
+ {
93
+ name: 'drive_delete_file',
94
+ description: 'Move a file to trash or permanently delete it',
95
+ inputSchema: {
96
+ type: 'object',
97
+ properties: {
98
+ fileId: { type: 'string', description: 'File ID' },
99
+ permanent: { type: 'boolean', default: false, description: 'Permanently delete vs trash' },
100
+ },
101
+ required: ['fileId'],
102
+ },
103
+ tags: ['files', 'drive', 'google', 'delete'],
104
+ capabilities: ['write', 'delete'],
105
+ authRequirements: { required: ['google_service_account'] },
106
+ contextRequirements: { minTokens: 30, maxTokens: 100 },
107
+ },
108
+ {
109
+ name: 'drive_list_folders',
110
+ description: 'List folders in Google Drive',
111
+ inputSchema: {
112
+ type: 'object',
113
+ properties: {
114
+ folderId: { type: 'string', description: 'Parent folder ID' },
115
+ query: { type: 'string', description: 'Search query' },
116
+ },
117
+ },
118
+ tags: ['folders', 'drive', 'google', 'list'],
119
+ capabilities: ['read', 'list'],
120
+ authRequirements: { required: ['google_service_account'] },
121
+ contextRequirements: { minTokens: 30, maxTokens: 300 },
122
+ },
123
+ {
124
+ name: 'drive_create_folder',
125
+ description: 'Create a new folder in Google Drive',
126
+ inputSchema: {
127
+ type: 'object',
128
+ properties: {
129
+ name: { type: 'string', description: 'Folder name' },
130
+ parentFolderId: { type: 'string', description: 'Parent folder ID' },
131
+ },
132
+ required: ['name'],
133
+ },
134
+ tags: ['folders', 'drive', 'google', 'create'],
135
+ capabilities: ['write', 'create'],
136
+ authRequirements: { required: ['google_service_account'] },
137
+ contextRequirements: { minTokens: 30, maxTokens: 100 },
138
+ },
139
+ {
140
+ name: 'drive_share_file',
141
+ description: 'Share a file with specific users or make it public',
142
+ inputSchema: {
143
+ type: 'object',
144
+ properties: {
145
+ fileId: { type: 'string', description: 'File ID' },
146
+ role: { type: 'string', enum: ['reader', 'commenter', 'writer', 'owner'] },
147
+ type: { type: 'string', enum: ['user', 'group', 'domain', 'anyone'] },
148
+ email: { type: 'string', description: 'Email for user/group type' },
149
+ domain: { type: 'string', description: 'Domain for domain type' },
150
+ transferOwnership: { type: 'boolean', default: false },
151
+ },
152
+ required: ['fileId', 'role', 'type'],
153
+ },
154
+ tags: ['files', 'drive', 'google', 'sharing', 'permissions'],
155
+ capabilities: ['write', 'share'],
156
+ authRequirements: { required: ['google_service_account'] },
157
+ contextRequirements: { minTokens: 30, maxTokens: 200 },
158
+ },
159
+ {
160
+ name: 'drive_search_files',
161
+ description: 'Search for files using Google Drive query syntax',
162
+ inputSchema: {
163
+ type: 'object',
164
+ properties: {
165
+ query: { type: 'string', description: 'Search query (Drive query syntax)' },
166
+ pageSize: { type: 'number', default: 100 },
167
+ orderBy: { type: 'string' },
168
+ },
169
+ required: ['query'],
170
+ },
171
+ tags: ['search', 'files', 'drive', 'google'],
172
+ capabilities: ['read', 'search'],
173
+ authRequirements: { required: ['google_service_account'] },
174
+ contextRequirements: { minTokens: 30, maxTokens: 400 },
175
+ },
176
+ ];
177
+
178
+ export class GoogleDriveConnector extends BaseConnector {
179
+ id = 'google-drive';
180
+ name = 'Google Drive';
181
+ type = 'google-drive';
182
+ private serviceAccountPath?: string;
183
+
184
+ constructor(config: ConnectorConfig) {
185
+ super(config);
186
+ this.serviceAccountPath = config.auth?.credentials?.service_account_path;
187
+ this.tools = this.buildTools();
188
+ }
189
+
190
+ async connect(): Promise<void> {
191
+ if (!this.serviceAccountPath) {
192
+ console.warn('Google service account not configured');
193
+ this.connected = true;
194
+ return;
195
+ }
196
+ this.connected = true;
197
+ }
198
+
199
+ async disconnect(): Promise<void> {
200
+ this.connected = false;
201
+ }
202
+
203
+ async healthCheck(): Promise<{ healthy: boolean; latencyMs?: number }> {
204
+ const { result, latencyMs } = await this.measureLatency(async () => {
205
+ return this.connected;
206
+ });
207
+ return { healthy: result, latencyMs };
208
+ }
209
+
210
+ async refreshTools(): Promise<Tool[]> {
211
+ return this.tools;
212
+ }
213
+
214
+ private buildTools(): Tool[] {
215
+ return GOOGLE_DRIVE_TOOL_DEFS.map(def => this.createTool(def));
216
+ }
217
+ }
@@ -0,0 +1,86 @@
1
+ export { BaseConnector, Connector } from './base.js';
2
+ export { GitHubConnector } from './github.js';
3
+ export { SlackConnector } from './slack.js';
4
+ export { PostgresConnector } from './postgres.js';
5
+ export { GoogleDriveConnector } from './google-drive.js';
6
+ export { CustomConnector } from './custom.js';
7
+
8
+ import { GitHubConnector } from './github.js';
9
+ import { SlackConnector } from './slack.js';
10
+ import { PostgresConnector } from './postgres.js';
11
+ import { GoogleDriveConnector } from './google-drive.js';
12
+ import { CustomConnector } from './custom.js';
13
+ import type { ConnectorConfig, MCPServer, Server } from '../types/index.js';
14
+
15
+ export function createConnector(type: string, config: ConnectorConfig): MCPServer {
16
+ switch (type) {
17
+ case 'github':
18
+ return new GitHubConnector(config);
19
+ case 'slack':
20
+ return new SlackConnector(config);
21
+ case 'postgres':
22
+ return new PostgresConnector(config);
23
+ case 'google-drive':
24
+ return new GoogleDriveConnector(config);
25
+ case 'custom':
26
+ return new CustomConnector(config);
27
+ default:
28
+ throw new Error(`Unknown connector type: ${type}`);
29
+ }
30
+ }
31
+
32
+ export function createAllConnectors(): Map<string, MCPServer> {
33
+ const connectors = new Map<string, MCPServer>();
34
+
35
+ connectors.set('github', new GitHubConnector({
36
+ serverId: 'github',
37
+ auth: { type: 'api-key' },
38
+ }));
39
+
40
+ connectors.set('slack', new SlackConnector({
41
+ serverId: 'slack',
42
+ auth: { type: 'api-key' },
43
+ }));
44
+
45
+ connectors.set('postgres', new PostgresConnector({
46
+ serverId: 'postgres',
47
+ auth: { type: 'none' },
48
+ }));
49
+
50
+ connectors.set('google-drive', new GoogleDriveConnector({
51
+ serverId: 'google-drive',
52
+ auth: { type: 'oauth' },
53
+ }));
54
+
55
+ connectors.set('custom', new CustomConnector({
56
+ serverId: 'custom',
57
+ auth: { type: 'none' },
58
+ }));
59
+
60
+ return connectors;
61
+ }
62
+
63
+ export function createServerFromConnector(connector: MCPServer): Server {
64
+ return {
65
+ id: connector.id,
66
+ name: connector.name,
67
+ type: connector.type as Server['type'],
68
+ status: 'active',
69
+ description: `MCP server for ${connector.name}`,
70
+ version: '1.0.0',
71
+ capabilities: ['read', 'write'],
72
+ tags: [connector.type, 'mcp'],
73
+ health: {
74
+ status: 'healthy',
75
+ lastChecked: new Date().toISOString(),
76
+ errorCount: 0,
77
+ },
78
+ auth: {
79
+ type: 'none',
80
+ configured: false,
81
+ },
82
+ metadata: {},
83
+ registeredAt: new Date().toISOString(),
84
+ lastSeen: new Date().toISOString(),
85
+ };
86
+ }
@@ -0,0 +1,148 @@
1
+ import { BaseConnector } from './base.js';
2
+ import { ConnectorConfig, Tool, ToolDefinition } from '../types/index.js';
3
+
4
+ const POSTGRES_TOOL_DEFS: ToolDefinition[] = [
5
+ {
6
+ name: 'postgres_query',
7
+ description: 'Execute a SQL query against the PostgreSQL database',
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ sql: { type: 'string', description: 'SQL query to execute' },
12
+ params: { type: 'array', description: 'Query parameters' },
13
+ timeout: { type: 'number', description: 'Query timeout in milliseconds' },
14
+ },
15
+ required: ['sql'],
16
+ },
17
+ tags: ['database', 'sql', 'postgres', 'query'],
18
+ capabilities: ['read', 'write', 'query'],
19
+ authRequirements: { required: ['postgres_url'] },
20
+ contextRequirements: { minTokens: 50, maxTokens: 500 },
21
+ },
22
+ {
23
+ name: 'postgres_list_tables',
24
+ description: 'List all tables in the database schema',
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ schema: { type: 'string', default: 'public', description: 'Database schema name' },
29
+ },
30
+ },
31
+ tags: ['database', 'schema', 'postgres', 'tables'],
32
+ capabilities: ['read', 'metadata'],
33
+ authRequirements: { required: ['postgres_url'] },
34
+ contextRequirements: { minTokens: 30, maxTokens: 300 },
35
+ },
36
+ {
37
+ name: 'postgres_describe_table',
38
+ description: 'Get the schema/structure of a specific table',
39
+ inputSchema: {
40
+ type: 'object',
41
+ properties: {
42
+ table: { type: 'string', description: 'Table name' },
43
+ schema: { type: 'string', default: 'public', description: 'Schema name' },
44
+ },
45
+ required: ['table'],
46
+ },
47
+ tags: ['database', 'schema', 'postgres', 'structure'],
48
+ capabilities: ['read', 'metadata'],
49
+ authRequirements: { required: ['postgres_url'] },
50
+ contextRequirements: { minTokens: 30, maxTokens: 200 },
51
+ },
52
+ {
53
+ name: 'postgres_execute_transaction',
54
+ description: 'Execute multiple SQL statements as a transaction',
55
+ inputSchema: {
56
+ type: 'object',
57
+ properties: {
58
+ statements: {
59
+ type: 'array',
60
+ items: {
61
+ type: 'object',
62
+ properties: {
63
+ sql: { type: 'string' },
64
+ params: { type: 'array' },
65
+ },
66
+ },
67
+ description: 'Array of SQL statements to execute',
68
+ },
69
+ rollbackOnError: { type: 'boolean', default: true },
70
+ },
71
+ required: ['statements'],
72
+ },
73
+ tags: ['database', 'transaction', 'postgres'],
74
+ capabilities: ['write', 'transaction'],
75
+ authRequirements: { required: ['postgres_url'] },
76
+ contextRequirements: { minTokens: 50, maxTokens: 500 },
77
+ },
78
+ {
79
+ name: 'postgres_list_databases',
80
+ description: 'List all accessible databases',
81
+ inputSchema: {
82
+ type: 'object',
83
+ properties: {},
84
+ },
85
+ tags: ['database', 'postgres', 'list'],
86
+ capabilities: ['read', 'metadata'],
87
+ authRequirements: { required: ['postgres_url'] },
88
+ contextRequirements: { minTokens: 30, maxTokens: 200 },
89
+ },
90
+ {
91
+ name: 'postgres_explain_query',
92
+ description: 'Get the query execution plan without running the query',
93
+ inputSchema: {
94
+ type: 'object',
95
+ properties: {
96
+ sql: { type: 'string', description: 'SQL query to explain' },
97
+ analyze: { type: 'boolean', default: false, description: 'Run the query and show actual timings' },
98
+ verbose: { type: 'boolean', default: false },
99
+ },
100
+ required: ['sql'],
101
+ },
102
+ tags: ['database', 'postgres', 'optimization', 'explain'],
103
+ capabilities: ['read', 'analyze'],
104
+ authRequirements: { required: ['postgres_url'] },
105
+ contextRequirements: { minTokens: 50, maxTokens: 400 },
106
+ },
107
+ ];
108
+
109
+ export class PostgresConnector extends BaseConnector {
110
+ id = 'postgres';
111
+ name = 'PostgreSQL';
112
+ type = 'postgres';
113
+ private connectionUrl?: string;
114
+
115
+ constructor(config: ConnectorConfig) {
116
+ super(config);
117
+ this.connectionUrl = config.auth?.credentials?.url;
118
+ this.tools = this.buildTools();
119
+ }
120
+
121
+ async connect(): Promise<void> {
122
+ if (!this.connectionUrl) {
123
+ console.warn('PostgreSQL connection URL not configured');
124
+ this.connected = true;
125
+ return;
126
+ }
127
+ this.connected = true;
128
+ }
129
+
130
+ async disconnect(): Promise<void> {
131
+ this.connected = false;
132
+ }
133
+
134
+ async healthCheck(): Promise<{ healthy: boolean; latencyMs?: number }> {
135
+ const { result, latencyMs } = await this.measureLatency(async () => {
136
+ return this.connected && !!this.connectionUrl;
137
+ });
138
+ return { healthy: result, latencyMs };
139
+ }
140
+
141
+ async refreshTools(): Promise<Tool[]> {
142
+ return this.tools;
143
+ }
144
+
145
+ private buildTools(): Tool[] {
146
+ return POSTGRES_TOOL_DEFS.map(def => this.createTool(def));
147
+ }
148
+ }
@@ -0,0 +1,188 @@
1
+ import { BaseConnector } from './base.js';
2
+ import { ConnectorConfig, Tool, ToolDefinition } from '../types/index.js';
3
+
4
+ const SLACK_TOOL_DEFS: ToolDefinition[] = [
5
+ {
6
+ name: 'slack_post_message',
7
+ description: 'Post a message to a Slack channel',
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ channel: { type: 'string', description: 'Channel ID or name' },
12
+ text: { type: 'string', description: 'Message text' },
13
+ blocks: { type: 'array', description: 'Slack Block Kit blocks' },
14
+ thread_ts: { type: 'string', description: 'Parent message timestamp for threads' },
15
+ },
16
+ required: ['channel', 'text'],
17
+ },
18
+ tags: ['messaging', 'slack', 'post'],
19
+ capabilities: ['write', 'messaging'],
20
+ authRequirements: { required: ['slack_bot_token'] },
21
+ contextRequirements: { minTokens: 30, maxTokens: 200 },
22
+ },
23
+ {
24
+ name: 'slack_list_channels',
25
+ description: 'List all channels in the workspace',
26
+ inputSchema: {
27
+ type: 'object',
28
+ properties: {
29
+ types: { type: 'array', items: { type: 'string' }, description: 'Channel types: public_channel, private_channel, im, mpim' },
30
+ exclude_archived: { type: 'boolean', default: true },
31
+ limit: { type: 'number', default: 100 },
32
+ },
33
+ },
34
+ tags: ['channels', 'slack', 'list'],
35
+ capabilities: ['read', 'list'],
36
+ authRequirements: { required: ['slack_bot_token'] },
37
+ contextRequirements: { minTokens: 30, maxTokens: 300 },
38
+ },
39
+ {
40
+ name: 'slack_get_messages',
41
+ description: 'Retrieve messages from a Slack channel',
42
+ inputSchema: {
43
+ type: 'object',
44
+ properties: {
45
+ channel: { type: 'string', description: 'Channel ID' },
46
+ latest: { type: 'string', description: 'Most recent message timestamp' },
47
+ oldest: { type: 'string', description: 'Oldest message timestamp' },
48
+ limit: { type: 'number', default: 100 },
49
+ inclusive: { type: 'boolean', default: false },
50
+ },
51
+ required: ['channel'],
52
+ },
53
+ tags: ['messages', 'slack', 'read'],
54
+ capabilities: ['read', 'messaging'],
55
+ authRequirements: { required: ['slack_bot_token'] },
56
+ contextRequirements: { minTokens: 30, maxTokens: 500 },
57
+ },
58
+ {
59
+ name: 'slack_create_channel',
60
+ description: 'Create a new Slack channel',
61
+ inputSchema: {
62
+ type: 'object',
63
+ properties: {
64
+ name: { type: 'string', description: 'Channel name' },
65
+ is_private: { type: 'boolean', default: false },
66
+ team_id: { type: 'string', description: 'Team to create channel in' },
67
+ },
68
+ required: ['name'],
69
+ },
70
+ tags: ['channels', 'slack', 'create'],
71
+ capabilities: ['write', 'create'],
72
+ authRequirements: { required: ['slack_bot_token'] },
73
+ contextRequirements: { minTokens: 30, maxTokens: 100 },
74
+ },
75
+ {
76
+ name: 'slack_invite_users',
77
+ description: 'Invite users to a Slack channel',
78
+ inputSchema: {
79
+ type: 'object',
80
+ properties: {
81
+ channel: { type: 'string', description: 'Channel ID' },
82
+ users: { type: 'array', items: { type: 'string' }, description: 'User IDs to invite' },
83
+ },
84
+ required: ['channel', 'users'],
85
+ },
86
+ tags: ['users', 'slack', 'invite'],
87
+ capabilities: ['write', 'admin'],
88
+ authRequirements: { required: ['slack_bot_token'] },
89
+ contextRequirements: { minTokens: 30, maxTokens: 100 },
90
+ },
91
+ {
92
+ name: 'slack_search_messages',
93
+ description: 'Search for messages across Slack',
94
+ inputSchema: {
95
+ type: 'object',
96
+ properties: {
97
+ query: { type: 'string', description: 'Search query' },
98
+ count: { type: 'number', default: 20 },
99
+ highlight: { type: 'boolean', default: true },
100
+ },
101
+ required: ['query'],
102
+ },
103
+ tags: ['search', 'slack', 'messages'],
104
+ capabilities: ['read', 'search'],
105
+ authRequirements: { required: ['slack_bot_token'] },
106
+ contextRequirements: { minTokens: 30, maxTokens: 400 },
107
+ },
108
+ {
109
+ name: 'slack_upload_file',
110
+ description: 'Upload a file to Slack',
111
+ inputSchema: {
112
+ type: 'object',
113
+ properties: {
114
+ channels: { type: 'array', items: { type: 'string' }, description: 'Channel IDs' },
115
+ file: { type: 'string', description: 'File content or URL' },
116
+ filename: { type: 'string', description: 'File name' },
117
+ title: { type: 'string', description: 'File title' },
118
+ initial_comment: { type: 'string', description: 'Initial comment' },
119
+ },
120
+ required: ['channels', 'file', 'filename'],
121
+ },
122
+ tags: ['files', 'slack', 'upload'],
123
+ capabilities: ['write', 'upload'],
124
+ authRequirements: { required: ['slack_bot_token'] },
125
+ contextRequirements: { minTokens: 30, maxTokens: 200 },
126
+ },
127
+ {
128
+ name: 'slack_get_user_info',
129
+ description: 'Get information about a Slack user',
130
+ inputSchema: {
131
+ type: 'object',
132
+ properties: {
133
+ user: { type: 'string', description: 'User ID' },
134
+ },
135
+ required: ['user'],
136
+ },
137
+ tags: ['users', 'slack', 'info'],
138
+ capabilities: ['read', 'users'],
139
+ authRequirements: { required: ['slack_bot_token'] },
140
+ contextRequirements: { minTokens: 30, maxTokens: 200 },
141
+ },
142
+ ];
143
+
144
+ export class SlackConnector extends BaseConnector {
145
+ id = 'slack';
146
+ name = 'Slack';
147
+ type = 'slack';
148
+ private token?: string;
149
+
150
+ constructor(config: ConnectorConfig) {
151
+ super(config);
152
+ this.token = config.auth?.credentials?.token;
153
+ this.tools = this.buildTools();
154
+ }
155
+
156
+ async connect(): Promise<void> {
157
+ if (!this.token) {
158
+ console.warn('Slack bot token not configured');
159
+ this.connected = true;
160
+ return;
161
+ }
162
+ this.connected = true;
163
+ }
164
+
165
+ async disconnect(): Promise<void> {
166
+ this.connected = false;
167
+ }
168
+
169
+ async healthCheck(): Promise<{ healthy: boolean; latencyMs?: number }> {
170
+ const { result, latencyMs } = await this.measureLatency(async () => {
171
+ if (!this.token) return false;
172
+ const response = await fetch('https://slack.com/api/auth.test', {
173
+ headers: { Authorization: `Bearer ${this.token}` },
174
+ });
175
+ const data = await response.json() as { ok: boolean };
176
+ return data.ok === true;
177
+ });
178
+ return { healthy: result, latencyMs };
179
+ }
180
+
181
+ async refreshTools(): Promise<Tool[]> {
182
+ return this.tools;
183
+ }
184
+
185
+ private buildTools(): Tool[] {
186
+ return SLACK_TOOL_DEFS.map(def => this.createTool(def));
187
+ }
188
+ }