opalserve 0.1.2 → 2.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 (223) hide show
  1. package/README.md +112 -116
  2. package/assets/logo.svg +54 -0
  3. package/dist/cli/commands/health.d.ts +4 -0
  4. package/dist/cli/commands/health.d.ts.map +1 -0
  5. package/dist/cli/commands/health.js +36 -0
  6. package/dist/cli/commands/health.js.map +1 -0
  7. package/dist/cli/commands/init.d.ts +2 -0
  8. package/dist/cli/commands/init.d.ts.map +1 -0
  9. package/dist/cli/commands/init.js +81 -0
  10. package/dist/cli/commands/init.js.map +1 -0
  11. package/dist/cli/commands/server.d.ts +10 -0
  12. package/dist/cli/commands/server.d.ts.map +1 -0
  13. package/dist/cli/commands/server.js +108 -0
  14. package/dist/cli/commands/server.js.map +1 -0
  15. package/dist/cli/commands/start.d.ts +6 -0
  16. package/dist/cli/commands/start.d.ts.map +1 -0
  17. package/dist/cli/commands/start.js +63 -0
  18. package/dist/cli/commands/start.js.map +1 -0
  19. package/dist/cli/commands/status.d.ts +2 -0
  20. package/dist/cli/commands/status.d.ts.map +1 -0
  21. package/dist/cli/commands/status.js +21 -0
  22. package/dist/cli/commands/status.js.map +1 -0
  23. package/dist/cli/commands/tools.d.ts +8 -0
  24. package/dist/cli/commands/tools.d.ts.map +1 -0
  25. package/dist/cli/commands/tools.js +28 -0
  26. package/dist/cli/commands/tools.js.map +1 -0
  27. package/dist/cli/index.d.ts +1 -1
  28. package/dist/cli/index.d.ts.map +1 -1
  29. package/dist/cli/index.js +82 -30
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/ui/banner.d.ts +8 -0
  32. package/dist/cli/ui/banner.d.ts.map +1 -0
  33. package/dist/cli/ui/banner.js +54 -0
  34. package/dist/cli/ui/banner.js.map +1 -0
  35. package/dist/cli/ui/prompts.d.ts +11 -0
  36. package/dist/cli/ui/prompts.d.ts.map +1 -0
  37. package/dist/cli/ui/prompts.js +74 -0
  38. package/dist/cli/ui/prompts.js.map +1 -0
  39. package/dist/cli/ui/table.d.ts +5 -0
  40. package/dist/cli/ui/table.d.ts.map +1 -0
  41. package/dist/cli/ui/table.js +103 -0
  42. package/dist/cli/ui/table.js.map +1 -0
  43. package/dist/config/defaults.d.ts +5 -0
  44. package/dist/config/defaults.d.ts.map +1 -0
  45. package/dist/config/defaults.js +18 -0
  46. package/dist/config/defaults.js.map +1 -0
  47. package/dist/config/loader.d.ts +4 -0
  48. package/dist/config/loader.d.ts.map +1 -0
  49. package/dist/config/loader.js +57 -0
  50. package/dist/config/loader.js.map +1 -0
  51. package/dist/config/schema.d.ts +2 -0
  52. package/dist/config/schema.d.ts.map +1 -0
  53. package/dist/config/schema.js +2 -0
  54. package/dist/config/schema.js.map +1 -0
  55. package/dist/core/discovery.d.ts +17 -0
  56. package/dist/core/discovery.d.ts.map +1 -0
  57. package/dist/core/discovery.js +31 -0
  58. package/dist/core/discovery.js.map +1 -0
  59. package/dist/core/proxy.d.ts +14 -0
  60. package/dist/core/proxy.d.ts.map +1 -0
  61. package/dist/core/proxy.js +36 -0
  62. package/dist/core/proxy.js.map +1 -0
  63. package/dist/core/registry.d.ts +28 -31
  64. package/dist/core/registry.d.ts.map +1 -1
  65. package/dist/core/registry.js +90 -234
  66. package/dist/core/registry.js.map +1 -1
  67. package/dist/core/server-manager.d.ts +18 -0
  68. package/dist/core/server-manager.d.ts.map +1 -0
  69. package/dist/core/server-manager.js +120 -0
  70. package/dist/core/server-manager.js.map +1 -0
  71. package/dist/index.d.ts +11 -12
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +14 -9
  74. package/dist/index.js.map +1 -1
  75. package/dist/server/app.d.ts +8 -0
  76. package/dist/server/app.d.ts.map +1 -0
  77. package/dist/server/app.js +35 -0
  78. package/dist/server/app.js.map +1 -0
  79. package/dist/server/mcp-gateway.d.ts +12 -0
  80. package/dist/server/mcp-gateway.d.ts.map +1 -0
  81. package/dist/server/mcp-gateway.js +91 -0
  82. package/dist/server/mcp-gateway.js.map +1 -0
  83. package/dist/server/routes/health.d.ts +4 -0
  84. package/dist/server/routes/health.d.ts.map +1 -0
  85. package/dist/server/routes/health.js +22 -0
  86. package/dist/server/routes/health.js.map +1 -0
  87. package/dist/server/routes/servers.d.ts +4 -0
  88. package/dist/server/routes/servers.d.ts.map +1 -0
  89. package/dist/server/routes/servers.js +47 -0
  90. package/dist/server/routes/servers.js.map +1 -0
  91. package/dist/server/routes/tools.d.ts +4 -0
  92. package/dist/server/routes/tools.d.ts.map +1 -0
  93. package/dist/server/routes/tools.js +44 -0
  94. package/dist/server/routes/tools.js.map +1 -0
  95. package/dist/storage/database.d.ts +41 -0
  96. package/dist/storage/database.d.ts.map +1 -0
  97. package/dist/storage/database.js +195 -0
  98. package/dist/storage/database.js.map +1 -0
  99. package/dist/storage/repositories/server-repo.d.ts +2 -0
  100. package/dist/storage/repositories/server-repo.d.ts.map +1 -0
  101. package/dist/storage/repositories/server-repo.js +3 -0
  102. package/dist/storage/repositories/server-repo.js.map +1 -0
  103. package/dist/storage/repositories/tool-repo.d.ts +2 -0
  104. package/dist/storage/repositories/tool-repo.d.ts.map +1 -0
  105. package/dist/storage/repositories/tool-repo.js +3 -0
  106. package/dist/storage/repositories/tool-repo.js.map +1 -0
  107. package/dist/types/index.d.ts +384 -591
  108. package/dist/types/index.d.ts.map +1 -1
  109. package/dist/types/index.js +44 -69
  110. package/dist/types/index.js.map +1 -1
  111. package/dist/utils/logger.d.ts +7 -0
  112. package/dist/utils/logger.d.ts.map +1 -0
  113. package/dist/utils/logger.js +23 -0
  114. package/dist/utils/logger.js.map +1 -0
  115. package/package.json +65 -56
  116. package/.env.example +0 -19
  117. package/config/servers.example.yaml +0 -67
  118. package/config/servers.yaml +0 -2
  119. package/dist/cli/discover.d.ts +0 -3
  120. package/dist/cli/discover.d.ts.map +0 -1
  121. package/dist/cli/discover.js +0 -160
  122. package/dist/cli/discover.js.map +0 -1
  123. package/dist/connectors/base.d.ts +0 -49
  124. package/dist/connectors/base.d.ts.map +0 -1
  125. package/dist/connectors/base.js +0 -45
  126. package/dist/connectors/base.js.map +0 -1
  127. package/dist/connectors/custom.d.ts +0 -19
  128. package/dist/connectors/custom.d.ts.map +0 -1
  129. package/dist/connectors/custom.js +0 -129
  130. package/dist/connectors/custom.js.map +0 -1
  131. package/dist/connectors/github.d.ts +0 -18
  132. package/dist/connectors/github.d.ts.map +0 -1
  133. package/dist/connectors/github.js +0 -188
  134. package/dist/connectors/github.js.map +0 -1
  135. package/dist/connectors/google-drive.d.ts +0 -18
  136. package/dist/connectors/google-drive.d.ts.map +0 -1
  137. package/dist/connectors/google-drive.js +0 -209
  138. package/dist/connectors/google-drive.js.map +0 -1
  139. package/dist/connectors/index.d.ts +0 -11
  140. package/dist/connectors/index.d.ts.map +0 -1
  141. package/dist/connectors/index.js +0 -76
  142. package/dist/connectors/index.js.map +0 -1
  143. package/dist/connectors/postgres.d.ts +0 -18
  144. package/dist/connectors/postgres.d.ts.map +0 -1
  145. package/dist/connectors/postgres.js +0 -140
  146. package/dist/connectors/postgres.js.map +0 -1
  147. package/dist/connectors/slack.d.ts +0 -18
  148. package/dist/connectors/slack.d.ts.map +0 -1
  149. package/dist/connectors/slack.js +0 -181
  150. package/dist/connectors/slack.js.map +0 -1
  151. package/dist/core/auth.d.ts +0 -26
  152. package/dist/core/auth.d.ts.map +0 -1
  153. package/dist/core/auth.js +0 -81
  154. package/dist/core/auth.js.map +0 -1
  155. package/dist/core/tokenizer.d.ts +0 -16
  156. package/dist/core/tokenizer.d.ts.map +0 -1
  157. package/dist/core/tokenizer.js +0 -29
  158. package/dist/core/tokenizer.js.map +0 -1
  159. package/dist/governance/audit.d.ts +0 -27
  160. package/dist/governance/audit.d.ts.map +0 -1
  161. package/dist/governance/audit.js +0 -149
  162. package/dist/governance/audit.js.map +0 -1
  163. package/dist/governance/index.d.ts +0 -5
  164. package/dist/governance/index.d.ts.map +0 -1
  165. package/dist/governance/index.js +0 -5
  166. package/dist/governance/index.js.map +0 -1
  167. package/dist/governance/policy.d.ts +0 -20
  168. package/dist/governance/policy.d.ts.map +0 -1
  169. package/dist/governance/policy.js +0 -162
  170. package/dist/governance/policy.js.map +0 -1
  171. package/dist/governance/rate-limiter.d.ts +0 -20
  172. package/dist/governance/rate-limiter.d.ts.map +0 -1
  173. package/dist/governance/rate-limiter.js +0 -73
  174. package/dist/governance/rate-limiter.js.map +0 -1
  175. package/dist/governance/types.d.ts +0 -246
  176. package/dist/governance/types.d.ts.map +0 -1
  177. package/dist/governance/types.js +0 -72
  178. package/dist/governance/types.js.map +0 -1
  179. package/dist/identity/access-control.d.ts +0 -15
  180. package/dist/identity/access-control.d.ts.map +0 -1
  181. package/dist/identity/access-control.js +0 -81
  182. package/dist/identity/access-control.js.map +0 -1
  183. package/dist/identity/index.d.ts +0 -4
  184. package/dist/identity/index.d.ts.map +0 -1
  185. package/dist/identity/index.js +0 -4
  186. package/dist/identity/index.js.map +0 -1
  187. package/dist/identity/manager.d.ts +0 -29
  188. package/dist/identity/manager.d.ts.map +0 -1
  189. package/dist/identity/manager.js +0 -167
  190. package/dist/identity/manager.js.map +0 -1
  191. package/dist/identity/types.d.ts +0 -237
  192. package/dist/identity/types.d.ts.map +0 -1
  193. package/dist/identity/types.js +0 -80
  194. package/dist/identity/types.js.map +0 -1
  195. package/dist/registry/server.d.ts +0 -14
  196. package/dist/registry/server.d.ts.map +0 -1
  197. package/dist/registry/server.js +0 -177
  198. package/dist/registry/server.js.map +0 -1
  199. package/dist/utils/config.d.ts +0 -29
  200. package/dist/utils/config.d.ts.map +0 -1
  201. package/dist/utils/config.js +0 -47
  202. package/dist/utils/config.js.map +0 -1
  203. package/dist/utils/index.d.ts +0 -7
  204. package/dist/utils/index.d.ts.map +0 -1
  205. package/dist/utils/index.js +0 -44
  206. package/dist/utils/index.js.map +0 -1
  207. package/dist/workflow/engine.d.ts +0 -18
  208. package/dist/workflow/engine.d.ts.map +0 -1
  209. package/dist/workflow/engine.js +0 -155
  210. package/dist/workflow/engine.js.map +0 -1
  211. package/dist/workflow/index.d.ts +0 -4
  212. package/dist/workflow/index.d.ts.map +0 -1
  213. package/dist/workflow/index.js +0 -4
  214. package/dist/workflow/index.js.map +0 -1
  215. package/dist/workflow/templates.d.ts +0 -4
  216. package/dist/workflow/templates.d.ts.map +0 -1
  217. package/dist/workflow/templates.js +0 -218
  218. package/dist/workflow/templates.js.map +0 -1
  219. package/dist/workflow/types.d.ts +0 -255
  220. package/dist/workflow/types.d.ts.map +0 -1
  221. package/dist/workflow/types.js +0 -48
  222. package/dist/workflow/types.js.map +0 -1
  223. package/eslint.config.js +0 -25
@@ -0,0 +1,4 @@
1
+ import type { OpalServeConfig } from '../types/index.js';
2
+ export declare function loadConfig(searchFrom?: string): Promise<OpalServeConfig>;
3
+ export declare function loadConfigFromPath(configPath: string): Promise<OpalServeConfig>;
4
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIzD,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA8C9E;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CASrF"}
@@ -0,0 +1,57 @@
1
+ import { cosmiconfig } from 'cosmiconfig';
2
+ import { OpalServeConfigSchema } from '../types/index.js';
3
+ import { getDefaultConfig } from './defaults.js';
4
+ const MODULE_NAME = 'opalserve';
5
+ export async function loadConfig(searchFrom) {
6
+ const explorer = cosmiconfig(MODULE_NAME, {
7
+ searchPlaces: [
8
+ 'opalserve.config.ts',
9
+ 'opalserve.config.js',
10
+ 'opalserve.config.mjs',
11
+ 'opalserve.config.cjs',
12
+ 'opalserve.config.json',
13
+ '.opalserverc',
14
+ '.opalserverc.json',
15
+ '.opalserverc.yaml',
16
+ '.opalserverc.yml',
17
+ 'package.json',
18
+ ],
19
+ });
20
+ try {
21
+ const result = await explorer.search(searchFrom);
22
+ if (!result || result.isEmpty) {
23
+ return getDefaultConfig();
24
+ }
25
+ const envOverrides = {};
26
+ if (process.env.OPALSERVE_PORT) {
27
+ envOverrides.gateway = {
28
+ ...(result.config.gateway || {}),
29
+ port: parseInt(process.env.OPALSERVE_PORT, 10),
30
+ };
31
+ }
32
+ if (process.env.OPALSERVE_HOST) {
33
+ const gw = envOverrides.gateway || {};
34
+ envOverrides.gateway = { ...gw, host: process.env.OPALSERVE_HOST };
35
+ }
36
+ if (process.env.OPALSERVE_LOG_LEVEL) {
37
+ envOverrides.logging = { level: process.env.OPALSERVE_LOG_LEVEL };
38
+ }
39
+ const merged = { ...result.config, ...envOverrides };
40
+ return OpalServeConfigSchema.parse(merged);
41
+ }
42
+ catch (error) {
43
+ if (error instanceof Error && error.message.includes('no such file')) {
44
+ return getDefaultConfig();
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+ export async function loadConfigFromPath(configPath) {
50
+ const explorer = cosmiconfig(MODULE_NAME);
51
+ const result = await explorer.load(configPath);
52
+ if (!result || result.isEmpty) {
53
+ return getDefaultConfig();
54
+ }
55
+ return OpalServeConfigSchema.parse(result.config);
56
+ }
57
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD,MAAM,WAAW,GAAG,WAAW,CAAC;AAEhC,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAmB;IAClD,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE;QACxC,YAAY,EAAE;YACZ,qBAAqB;YACrB,qBAAqB;YACrB,sBAAsB;YACtB,sBAAsB;YACtB,uBAAuB;YACvB,cAAc;YACd,mBAAmB;YACnB,mBAAmB;YACnB,kBAAkB;YAClB,cAAc;SACf;KACF,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,OAAO,gBAAgB,EAAE,CAAC;QAC5B,CAAC;QAED,MAAM,YAAY,GAA4B,EAAE,CAAC;QACjD,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;YAC/B,YAAY,CAAC,OAAO,GAAG;gBACrB,GAAG,CAAE,MAAM,CAAC,MAAkC,CAAC,OAAkC,IAAI,EAAE,CAAC;gBACxF,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,CAAC;aAC/C,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;YAC/B,MAAM,EAAE,GAAG,YAAY,CAAC,OAAkC,IAAI,EAAE,CAAC;YACjE,YAAY,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;QACrE,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;YACpC,YAAY,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QACpE,CAAC;QAED,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;QACrD,OAAO,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACrE,OAAO,gBAAgB,EAAE,CAAC;QAC5B,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,UAAkB;IACzD,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAE/C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC9B,OAAO,gBAAgB,EAAE,CAAC;IAC5B,CAAC;IAED,OAAO,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { OpalServeConfigSchema, McpServerConfigSchema } from '../types/index.js';
2
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { OpalServeConfigSchema, McpServerConfigSchema } from '../types/index.js';
2
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { Database } from '../storage/database.js';
2
+ import type { IndexedTool, SearchResult } from '../types/index.js';
3
+ export declare class DiscoveryEngine {
4
+ private db;
5
+ constructor(db: Database);
6
+ search(query: string, options?: {
7
+ limit?: number;
8
+ serverFilter?: string[];
9
+ }): SearchResult[];
10
+ listAll(options?: {
11
+ serverFilter?: string[];
12
+ }): IndexedTool[];
13
+ getByServer(serverName: string): IndexedTool[];
14
+ getById(toolId: string): IndexedTool | null;
15
+ count(): number;
16
+ }
17
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/core/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEnE,qBAAa,eAAe;IACd,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEhC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,YAAY,EAAE;IAW5F,OAAO,CAAC,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,WAAW,EAAE;IAU7D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE;IAI9C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAI3C,KAAK,IAAI,MAAM;CAGhB"}
@@ -0,0 +1,31 @@
1
+ export class DiscoveryEngine {
2
+ db;
3
+ constructor(db) {
4
+ this.db = db;
5
+ }
6
+ search(query, options) {
7
+ const limit = options?.limit ?? 20;
8
+ let results = this.db.searchTools(query, limit);
9
+ if (options?.serverFilter?.length) {
10
+ results = results.filter(r => options.serverFilter.includes(r.tool.serverName));
11
+ }
12
+ return results;
13
+ }
14
+ listAll(options) {
15
+ const tools = this.db.getAllTools();
16
+ if (options?.serverFilter?.length) {
17
+ return tools.filter(t => options.serverFilter.includes(t.serverName));
18
+ }
19
+ return tools;
20
+ }
21
+ getByServer(serverName) {
22
+ return this.db.getToolsByServer(serverName);
23
+ }
24
+ getById(toolId) {
25
+ return this.db.getTool(toolId);
26
+ }
27
+ count() {
28
+ return this.db.toolCount();
29
+ }
30
+ }
31
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/core/discovery.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,EAAY;QAAZ,OAAE,GAAF,EAAE,CAAU;IAAG,CAAC;IAEpC,MAAM,CAAC,KAAa,EAAE,OAAqD;QACzE,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;QACnC,IAAI,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAEhD,IAAI,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;YAClC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,YAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACnF,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CAAC,OAAqC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;QAEpC,IAAI,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;YAClC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,YAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QACzE,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,WAAW,CAAC,UAAkB;QAC5B,OAAO,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,CAAC,MAAc;QACpB,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { ServerManager } from './server-manager.js';
3
+ import type { DiscoveryEngine } from './discovery.js';
4
+ export declare class ToolProxy {
5
+ private serverManager;
6
+ private discovery;
7
+ constructor(serverManager: ServerManager, discovery: DiscoveryEngine);
8
+ callTool(toolId: string, args?: Record<string, unknown>): Promise<CallToolResult>;
9
+ parseToolId(toolId: string): {
10
+ serverName: string;
11
+ toolName: string;
12
+ };
13
+ }
14
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/core/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,qBAAa,SAAS;IAElB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,SAAS;gBADT,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,eAAe;IAG9B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAsB3F,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;CAUtE"}
@@ -0,0 +1,36 @@
1
+ export class ToolProxy {
2
+ serverManager;
3
+ discovery;
4
+ constructor(serverManager, discovery) {
5
+ this.serverManager = serverManager;
6
+ this.discovery = discovery;
7
+ }
8
+ async callTool(toolId, args = {}) {
9
+ const separatorIndex = toolId.indexOf(':');
10
+ if (separatorIndex === -1) {
11
+ throw new Error(`Invalid tool ID "${toolId}". Expected format: "serverName:toolName"`);
12
+ }
13
+ const serverName = toolId.slice(0, separatorIndex);
14
+ const toolName = toolId.slice(separatorIndex + 1);
15
+ // Verify tool exists in our index
16
+ const tool = this.discovery.getById(toolId);
17
+ if (!tool) {
18
+ throw new Error(`Tool "${toolId}" not found in registry`);
19
+ }
20
+ if (!this.serverManager.isConnected(serverName)) {
21
+ throw new Error(`Server "${serverName}" is not connected`);
22
+ }
23
+ return this.serverManager.callTool(serverName, toolName, args);
24
+ }
25
+ parseToolId(toolId) {
26
+ const separatorIndex = toolId.indexOf(':');
27
+ if (separatorIndex === -1) {
28
+ throw new Error(`Invalid tool ID "${toolId}". Expected format: "serverName:toolName"`);
29
+ }
30
+ return {
31
+ serverName: toolId.slice(0, separatorIndex),
32
+ toolName: toolId.slice(separatorIndex + 1),
33
+ };
34
+ }
35
+ }
36
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/core/proxy.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,SAAS;IAEV;IACA;IAFV,YACU,aAA4B,EAC5B,SAA0B;QAD1B,kBAAa,GAAb,aAAa,CAAe;QAC5B,cAAS,GAAT,SAAS,CAAiB;IACjC,CAAC;IAEJ,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,OAAgC,EAAE;QAC/D,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,2CAA2C,CAAC,CAAC;QACzF,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;QAElD,kCAAkC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,SAAS,MAAM,yBAAyB,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,WAAW,UAAU,oBAAoB,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;IAED,WAAW,CAAC,MAAc;QACxB,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,2CAA2C,CAAC,CAAC;QACzF,CAAC;QACD,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC;YAC3C,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC;SAC3C,CAAC;IACJ,CAAC;CACF"}
@@ -1,33 +1,30 @@
1
- import type { Tool, Server, DiscoveryQuery, DiscoveryResult, MCPServer } from '../types/index.js';
2
- export declare class ToolRegistry {
3
- private tools;
4
- private servers;
5
- private serverInstances;
6
- private tokenCounter;
7
- constructor(contextBudget?: number);
8
- registerTool(tool: Tool): void;
9
- registerServer(server: Server): void;
10
- registerServerInstance(instance: MCPServer): void;
11
- removeTool(toolId: string): boolean;
12
- removeServer(serverId: string): boolean;
13
- getTool(toolId: string): Tool | undefined;
14
- getServer(serverId: string): Server | undefined;
15
- getAllTools(): Tool[];
16
- getAllServers(): Server[];
17
- getToolsByServer(serverId: string): Tool[];
18
- discover(query: DiscoveryQuery): Promise<DiscoveryResult>;
19
- private scoreAndFilterTools;
20
- private calculateRelevance;
21
- private getServersForTools;
22
- private calculateContextUsed;
23
- private findContextFitLimit;
24
- private interpretQuery;
25
- private generateSuggestions;
26
- private buildSearchableText;
27
- healthCheck(serverId: string): Promise<{
28
- healthy: boolean;
29
- latencyMs?: number;
30
- }>;
31
- refreshServer(serverId: string): Promise<void>;
1
+ import { Database } from '../storage/database.js';
2
+ import { ServerManager } from './server-manager.js';
3
+ import { DiscoveryEngine } from './discovery.js';
4
+ import { ToolProxy } from './proxy.js';
5
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
6
+ import type { OpalServeConfig, McpServerConfig, ConnectedServer, IndexedTool, SearchResult, HealthResult } from '../types/index.js';
7
+ export declare class OpalServeRegistry {
8
+ readonly serverManager: ServerManager;
9
+ readonly discovery: DiscoveryEngine;
10
+ readonly proxy: ToolProxy;
11
+ readonly config: OpalServeConfig;
12
+ private db;
13
+ private constructor();
14
+ static create(configOverrides?: Partial<OpalServeConfig>): Promise<OpalServeRegistry>;
15
+ static createWithDb(config: OpalServeConfig, db: Database): OpalServeRegistry;
16
+ start(): Promise<void>;
17
+ stop(): Promise<void>;
18
+ addServer(config: McpServerConfig): Promise<void>;
19
+ removeServer(name: string): Promise<void>;
20
+ listServers(): ConnectedServer[];
21
+ searchTools(query: string, options?: {
22
+ limit?: number;
23
+ serverFilter?: string[];
24
+ }): SearchResult[];
25
+ listTools(serverFilter?: string[]): IndexedTool[];
26
+ callTool(toolId: string, args?: Record<string, unknown>): Promise<CallToolResult>;
27
+ healthCheck(serverName?: string): Promise<HealthResult[]>;
28
+ getDatabase(): Database;
32
29
  }
33
30
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AASlG,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,YAAY,CAAe;gBAEvB,aAAa,GAAE,MAAe;IAI1C,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAU9B,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIpC,sBAAsB,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI;IAIjD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAInC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAWvC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIzC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI/C,WAAW,IAAI,IAAI,EAAE;IAIrB,aAAa,IAAI,MAAM,EAAE;IAIzB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE;IAMpC,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAsB/D,OAAO,CAAC,mBAAmB;IAqD3B,OAAO,CAAC,kBAAkB;IA6C1B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,mBAAmB;IAUrB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAQhF,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAcrD"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACb,MAAM,mBAAmB,CAAC;AAI3B,qBAAa,iBAAiB;IAC5B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IAEjC,OAAO,CAAC,EAAE,CAAW;IAErB,OAAO;WAQM,MAAM,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAa3F,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,EAAE,QAAQ,GAAG,iBAAiB;IAIvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IASrB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/C,WAAW,IAAI,eAAe,EAAE;IAMhC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,YAAY,EAAE;IAIjG,SAAS,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE;IAM3C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IAMjF,WAAW,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAa/D,WAAW,IAAI,QAAQ;CAGxB"}
@@ -1,237 +1,93 @@
1
- import { TokenCounter } from './tokenizer.js';
2
- export class ToolRegistry {
3
- tools = new Map();
4
- servers = new Map();
5
- serverInstances = new Map();
6
- tokenCounter;
7
- constructor(contextBudget = 128000) {
8
- this.tokenCounter = new TokenCounter(contextBudget);
9
- }
10
- registerTool(tool) {
11
- const searchableText = this.buildSearchableText(tool);
12
- const indexedTool = {
13
- tool,
14
- searchableText,
15
- tokenCount: this.tokenCounter.count(searchableText),
16
- };
17
- this.tools.set(tool.id, indexedTool);
18
- }
19
- registerServer(server) {
20
- this.servers.set(server.id, server);
21
- }
22
- registerServerInstance(instance) {
23
- this.serverInstances.set(instance.id, instance);
24
- }
25
- removeTool(toolId) {
26
- return this.tools.delete(toolId);
27
- }
28
- removeServer(serverId) {
29
- this.servers.delete(serverId);
30
- this.serverInstances.delete(serverId);
31
- for (const [toolId, indexed] of this.tools) {
32
- if (indexed.tool.serverId === serverId) {
33
- this.tools.delete(toolId);
34
- }
35
- }
36
- return true;
37
- }
38
- getTool(toolId) {
39
- return this.tools.get(toolId)?.tool;
40
- }
41
- getServer(serverId) {
42
- return this.servers.get(serverId);
43
- }
44
- getAllTools() {
45
- return Array.from(this.tools.values()).map(i => i.tool);
46
- }
47
- getAllServers() {
48
- return Array.from(this.servers.values());
49
- }
50
- getToolsByServer(serverId) {
51
- return Array.from(this.tools.values())
52
- .filter(i => i.tool.serverId === serverId)
53
- .map(i => i.tool);
54
- }
55
- async discover(query) {
56
- const tools = this.scoreAndFilterTools(query);
57
- const servers = this.getServersForTools(tools.map(t => t.tool.serverId));
58
- const contextUsed = this.calculateContextUsed(tools);
59
- const queryInterpretation = this.interpretQuery(query);
60
- return {
61
- tools: tools.map(({ tool, relevanceScore, matchReasons, tokenEstimate }) => ({
62
- tool,
63
- relevanceScore,
64
- matchReasons,
65
- tokenEstimate,
66
- })),
67
- servers,
68
- totalMatches: tools.length,
69
- contextUsed,
70
- contextBudget: query.contextBudget,
71
- suggestions: this.generateSuggestions(query),
72
- queryInterpretation,
73
- };
74
- }
75
- scoreAndFilterTools(query) {
76
- const scored = [];
77
- let contextUsed = 0;
78
- const headerTokens = 200;
79
- for (const indexed of this.tools.values()) {
80
- const { tool, tokenCount } = indexed;
81
- if (contextUsed + tokenCount + headerTokens > query.contextBudget && scored.length > 0) {
82
- break;
83
- }
84
- const { score, reasons } = this.calculateRelevance(tool, query);
85
- if (score > 0) {
86
- if (query.capabilities?.length) {
87
- const hasCapability = query.capabilities.some(cap => tool.capabilities.includes(cap));
88
- if (!hasCapability)
89
- continue;
90
- }
91
- if (query.tags?.length) {
92
- const hasTag = query.tags.some(tag => tool.tags.includes(tag));
93
- if (!hasTag)
94
- continue;
95
- }
96
- scored.push({
97
- tool,
98
- relevanceScore: score,
99
- matchReasons: reasons,
100
- tokenEstimate: tokenCount,
101
- });
102
- contextUsed += tokenCount;
103
- }
104
- }
105
- scored.sort((a, b) => b.relevanceScore - a.relevanceScore);
106
- const limit = Math.min(query.limit, this.findContextFitLimit(scored, query.contextBudget));
107
- return scored.slice(query.offset, query.offset + limit);
108
- }
109
- calculateRelevance(tool, query) {
110
- let score = 0;
111
- const reasons = [];
112
- if (query.query) {
113
- const q = query.query.toLowerCase();
114
- const words = q.split(/\s+/);
115
- for (const word of words) {
116
- if (tool.name.toLowerCase().includes(word)) {
117
- score += 0.4;
118
- reasons.push(`Name matches "${word}"`);
119
- }
120
- if (tool.description.toLowerCase().includes(word)) {
121
- score += 0.3;
122
- reasons.push(`Description matches "${word}"`);
123
- }
124
- for (const tag of tool.tags) {
125
- if (tag.toLowerCase().includes(word)) {
126
- score += 0.2;
127
- reasons.push(`Tag "${tag}" matches "${word}"`);
128
- }
129
- }
130
- for (const cap of tool.capabilities) {
131
- if (cap.toLowerCase().includes(word)) {
132
- score += 0.25;
133
- reasons.push(`Capability "${cap}" matches "${word}"`);
134
- }
135
- }
136
- }
137
- const allText = `${tool.name} ${tool.description} ${tool.tags.join(' ')} ${tool.capabilities.join(' ')}`.toLowerCase();
138
- const matchCount = words.filter(w => allText.includes(w)).length;
139
- if (matchCount === words.length) {
140
- score += 0.3;
141
- reasons.push('All query terms matched');
142
- }
143
- }
144
- return { score: Math.min(score, 1), reasons };
145
- }
146
- getServersForTools(serverIds) {
147
- const uniqueIds = [...new Set(serverIds)];
148
- return uniqueIds
149
- .map(id => this.servers.get(id))
150
- .filter((s) => s !== undefined);
151
- }
152
- calculateContextUsed(tools) {
153
- return tools.reduce((sum, t) => sum + t.tokenEstimate, 0) + 200;
154
- }
155
- findContextFitLimit(tools, budget) {
156
- let used = 200;
157
- for (let i = 0; i < tools.length; i++) {
158
- if (used + tools[i].tokenEstimate > budget) {
159
- return i;
160
- }
161
- used += tools[i].tokenEstimate;
162
- }
163
- return tools.length;
164
- }
165
- interpretQuery(query) {
166
- if (!query.query) {
167
- return 'Returning all available tools sorted by relevance';
168
- }
169
- const q = query.query.toLowerCase();
170
- const interpretations = [];
171
- if (q.includes('what can i do') || q.includes('available') || q.includes('list')) {
172
- interpretations.push('Listing available actions');
173
- }
174
- if (q.includes('github') || q.includes('repo') || q.includes('pr')) {
175
- interpretations.push('Looking for GitHub-related tools');
176
- }
177
- if (q.includes('slack') || q.includes('message') || q.includes('channel')) {
178
- interpretations.push('Looking for Slack/messaging tools');
179
- }
180
- if (q.includes('database') || q.includes('query') || q.includes('sql')) {
181
- interpretations.push('Looking for database tools');
182
- }
183
- if (q.includes('file') || q.includes('drive') || q.includes('document')) {
184
- interpretations.push('Looking for file/document tools');
185
- }
186
- if (interpretations.length === 0) {
187
- return `Searching for tools matching: "${query.query}"`;
188
- }
189
- return interpretations.join(', ');
190
- }
191
- generateSuggestions(query) {
192
- const suggestions = [];
193
- if (this.tools.size > 50 && query.limit && query.limit < 10) {
194
- suggestions.push('Try increasing the limit to see more tools');
195
- }
196
- if (!query.query && this.tools.size > 50) {
197
- suggestions.push('Use a query to filter tools by capability or name');
198
- }
199
- const hasGitHub = Array.from(this.tools.values()).some(i => i.tool.serverName.toLowerCase().includes('github'));
200
- if (!hasGitHub) {
201
- suggestions.push('Configure GitHub connector for repository management');
202
- }
203
- return suggestions;
204
- }
205
- buildSearchableText(tool) {
206
- return [
207
- tool.name,
208
- tool.description,
209
- ...tool.tags,
210
- ...tool.capabilities,
211
- tool.serverName,
212
- ].join(' ');
213
- }
214
- async healthCheck(serverId) {
215
- const instance = this.serverInstances.get(serverId);
216
- if (!instance) {
217
- return { healthy: false };
218
- }
219
- return instance.healthCheck();
220
- }
221
- async refreshServer(serverId) {
222
- const instance = this.serverInstances.get(serverId);
223
- const server = this.servers.get(serverId);
224
- if (!instance || !server)
225
- return;
226
- try {
227
- await instance.disconnect();
228
- await instance.connect();
229
- server.status = 'active';
230
- server.lastSeen = new Date().toISOString();
231
- }
232
- catch {
233
- server.status = 'error';
234
- }
1
+ import { Database } from '../storage/database.js';
2
+ import { ServerManager } from './server-manager.js';
3
+ import { DiscoveryEngine } from './discovery.js';
4
+ import { ToolProxy } from './proxy.js';
5
+ import { loadConfig } from '../config/loader.js';
6
+ import { getDefaultDbPath } from '../config/defaults.js';
7
+ import { setLogLevel, createLogger } from '../utils/logger.js';
8
+ const log = createLogger('registry');
9
+ export class OpalServeRegistry {
10
+ serverManager;
11
+ discovery;
12
+ proxy;
13
+ config;
14
+ db;
15
+ constructor(config, db) {
16
+ this.config = config;
17
+ this.db = db;
18
+ this.serverManager = new ServerManager(db);
19
+ this.discovery = new DiscoveryEngine(db);
20
+ this.proxy = new ToolProxy(this.serverManager, this.discovery);
21
+ }
22
+ static async create(configOverrides) {
23
+ const config = configOverrides
24
+ ? { ...(await loadConfig()), ...configOverrides }
25
+ : await loadConfig();
26
+ setLogLevel(config.logging.level);
27
+ const dbPath = config.storage.path || getDefaultDbPath();
28
+ const db = Database.open(dbPath);
29
+ return new OpalServeRegistry(config, db);
30
+ }
31
+ static createWithDb(config, db) {
32
+ return new OpalServeRegistry(config, db);
33
+ }
34
+ async start() {
35
+ log.info('Starting OpalServe registry...');
36
+ const serversToConnect = this.config.servers.filter(s => s.enabled && s.autoConnect);
37
+ const results = await Promise.allSettled(serversToConnect.map(config => this.serverManager.connectServer(config)));
38
+ let connected = 0;
39
+ let failed = 0;
40
+ for (const result of results) {
41
+ if (result.status === 'fulfilled')
42
+ connected++;
43
+ else
44
+ failed++;
45
+ }
46
+ log.info({ connected, failed, tools: this.discovery.count() }, 'Registry started');
47
+ }
48
+ async stop() {
49
+ log.info('Stopping OpalServe registry...');
50
+ await this.serverManager.disconnectAll();
51
+ this.db.close();
52
+ log.info('Registry stopped');
53
+ }
54
+ // --- Server Management ---
55
+ async addServer(config) {
56
+ await this.serverManager.connectServer(config);
57
+ }
58
+ async removeServer(name) {
59
+ await this.serverManager.disconnectServer(name);
60
+ this.db.removeToolsByServer(name);
61
+ this.db.removeServer(name);
62
+ }
63
+ listServers() {
64
+ return this.db.getAllServers().map(r => r.server);
65
+ }
66
+ // --- Tool Discovery ---
67
+ searchTools(query, options) {
68
+ return this.discovery.search(query, options);
69
+ }
70
+ listTools(serverFilter) {
71
+ return this.discovery.listAll({ serverFilter });
72
+ }
73
+ // --- Tool Execution ---
74
+ async callTool(toolId, args) {
75
+ return this.proxy.callTool(toolId, args);
76
+ }
77
+ // --- Health ---
78
+ async healthCheck(serverName) {
79
+ const servers = serverName
80
+ ? this.db.getAllServers().filter(s => s.server.name === serverName)
81
+ : this.db.getAllServers();
82
+ return servers.map(({ server }) => ({
83
+ serverName: server.name,
84
+ healthy: server.status === 'connected',
85
+ toolCount: server.toolCount,
86
+ error: server.error ?? undefined,
87
+ }));
88
+ }
89
+ getDatabase() {
90
+ return this.db;
235
91
  }
236
92
  }
237
93
  //# sourceMappingURL=registry.js.map