@dotsetlabs/tollgate 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 (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +885 -0
  3. package/dist/analyzers/filesystem.d.ts +26 -0
  4. package/dist/analyzers/filesystem.d.ts.map +1 -0
  5. package/dist/analyzers/filesystem.js +284 -0
  6. package/dist/analyzers/filesystem.js.map +1 -0
  7. package/dist/analyzers/http.d.ts +90 -0
  8. package/dist/analyzers/http.d.ts.map +1 -0
  9. package/dist/analyzers/http.js +433 -0
  10. package/dist/analyzers/http.js.map +1 -0
  11. package/dist/analyzers/index.d.ts +101 -0
  12. package/dist/analyzers/index.d.ts.map +1 -0
  13. package/dist/analyzers/index.js +342 -0
  14. package/dist/analyzers/index.js.map +1 -0
  15. package/dist/analyzers/loader.d.ts +114 -0
  16. package/dist/analyzers/loader.d.ts.map +1 -0
  17. package/dist/analyzers/loader.js +184 -0
  18. package/dist/analyzers/loader.js.map +1 -0
  19. package/dist/analyzers/prompt-injection.d.ts +95 -0
  20. package/dist/analyzers/prompt-injection.d.ts.map +1 -0
  21. package/dist/analyzers/prompt-injection.js +725 -0
  22. package/dist/analyzers/prompt-injection.js.map +1 -0
  23. package/dist/analyzers/sdk.d.ts +230 -0
  24. package/dist/analyzers/sdk.d.ts.map +1 -0
  25. package/dist/analyzers/sdk.js +283 -0
  26. package/dist/analyzers/sdk.js.map +1 -0
  27. package/dist/analyzers/shell.d.ts +20 -0
  28. package/dist/analyzers/shell.d.ts.map +1 -0
  29. package/dist/analyzers/shell.js +297 -0
  30. package/dist/analyzers/shell.js.map +1 -0
  31. package/dist/analyzers/sql.d.ts +37 -0
  32. package/dist/analyzers/sql.d.ts.map +1 -0
  33. package/dist/analyzers/sql.js +455 -0
  34. package/dist/analyzers/sql.js.map +1 -0
  35. package/dist/analyzers/types.d.ts +117 -0
  36. package/dist/analyzers/types.d.ts.map +1 -0
  37. package/dist/analyzers/types.js +46 -0
  38. package/dist/analyzers/types.js.map +1 -0
  39. package/dist/approval/interactive.d.ts +72 -0
  40. package/dist/approval/interactive.d.ts.map +1 -0
  41. package/dist/approval/interactive.js +550 -0
  42. package/dist/approval/interactive.js.map +1 -0
  43. package/dist/approval/terminal.d.ts +59 -0
  44. package/dist/approval/terminal.d.ts.map +1 -0
  45. package/dist/approval/terminal.js +238 -0
  46. package/dist/approval/terminal.js.map +1 -0
  47. package/dist/approval/types.d.ts +66 -0
  48. package/dist/approval/types.d.ts.map +1 -0
  49. package/dist/approval/types.js +2 -0
  50. package/dist/approval/types.js.map +1 -0
  51. package/dist/audit/exporter.d.ts +138 -0
  52. package/dist/audit/exporter.d.ts.map +1 -0
  53. package/dist/audit/exporter.js +366 -0
  54. package/dist/audit/exporter.js.map +1 -0
  55. package/dist/audit/logger.d.ts +156 -0
  56. package/dist/audit/logger.d.ts.map +1 -0
  57. package/dist/audit/logger.js +406 -0
  58. package/dist/audit/logger.js.map +1 -0
  59. package/dist/audit/redaction.d.ts +110 -0
  60. package/dist/audit/redaction.d.ts.map +1 -0
  61. package/dist/audit/redaction.js +307 -0
  62. package/dist/audit/redaction.js.map +1 -0
  63. package/dist/audit/schema.d.ts +76 -0
  64. package/dist/audit/schema.d.ts.map +1 -0
  65. package/dist/audit/schema.js +122 -0
  66. package/dist/audit/schema.js.map +1 -0
  67. package/dist/cli/commands/doctor.d.ts +34 -0
  68. package/dist/cli/commands/doctor.d.ts.map +1 -0
  69. package/dist/cli/commands/doctor.js +431 -0
  70. package/dist/cli/commands/doctor.js.map +1 -0
  71. package/dist/cli/commands/export.d.ts +18 -0
  72. package/dist/cli/commands/export.d.ts.map +1 -0
  73. package/dist/cli/commands/export.js +63 -0
  74. package/dist/cli/commands/export.js.map +1 -0
  75. package/dist/cli/commands/init.d.ts +12 -0
  76. package/dist/cli/commands/init.d.ts.map +1 -0
  77. package/dist/cli/commands/init.js +102 -0
  78. package/dist/cli/commands/init.js.map +1 -0
  79. package/dist/cli/commands/logs.d.ts +11 -0
  80. package/dist/cli/commands/logs.d.ts.map +1 -0
  81. package/dist/cli/commands/logs.js +60 -0
  82. package/dist/cli/commands/logs.js.map +1 -0
  83. package/dist/cli/commands/scan.d.ts +29 -0
  84. package/dist/cli/commands/scan.d.ts.map +1 -0
  85. package/dist/cli/commands/scan.js +251 -0
  86. package/dist/cli/commands/scan.js.map +1 -0
  87. package/dist/cli/commands/serve.d.ts +26 -0
  88. package/dist/cli/commands/serve.d.ts.map +1 -0
  89. package/dist/cli/commands/serve.js +424 -0
  90. package/dist/cli/commands/serve.js.map +1 -0
  91. package/dist/cli/commands/start.d.ts +20 -0
  92. package/dist/cli/commands/start.d.ts.map +1 -0
  93. package/dist/cli/commands/start.js +82 -0
  94. package/dist/cli/commands/start.js.map +1 -0
  95. package/dist/cli/commands/stats.d.ts +10 -0
  96. package/dist/cli/commands/stats.d.ts.map +1 -0
  97. package/dist/cli/commands/stats.js +42 -0
  98. package/dist/cli/commands/stats.js.map +1 -0
  99. package/dist/cli/commands/templates.d.ts +26 -0
  100. package/dist/cli/commands/templates.d.ts.map +1 -0
  101. package/dist/cli/commands/templates.js +221 -0
  102. package/dist/cli/commands/templates.js.map +1 -0
  103. package/dist/cli/commands/validate.d.ts +12 -0
  104. package/dist/cli/commands/validate.d.ts.map +1 -0
  105. package/dist/cli/commands/validate.js +107 -0
  106. package/dist/cli/commands/validate.js.map +1 -0
  107. package/dist/cli/commands/wrap.d.ts +19 -0
  108. package/dist/cli/commands/wrap.d.ts.map +1 -0
  109. package/dist/cli/commands/wrap.js +59 -0
  110. package/dist/cli/commands/wrap.js.map +1 -0
  111. package/dist/cli/index.d.ts +17 -0
  112. package/dist/cli/index.d.ts.map +1 -0
  113. package/dist/cli/index.js +202 -0
  114. package/dist/cli/index.js.map +1 -0
  115. package/dist/cli/ui.d.ts +139 -0
  116. package/dist/cli/ui.d.ts.map +1 -0
  117. package/dist/cli/ui.js +271 -0
  118. package/dist/cli/ui.js.map +1 -0
  119. package/dist/constants.d.ts +33 -0
  120. package/dist/constants.d.ts.map +1 -0
  121. package/dist/constants.js +54 -0
  122. package/dist/constants.js.map +1 -0
  123. package/dist/errors.d.ts +28 -0
  124. package/dist/errors.d.ts.map +1 -0
  125. package/dist/errors.js +37 -0
  126. package/dist/errors.js.map +1 -0
  127. package/dist/index.d.ts +49 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +82 -0
  130. package/dist/index.js.map +1 -0
  131. package/dist/orchestrator/index.d.ts +11 -0
  132. package/dist/orchestrator/index.d.ts.map +1 -0
  133. package/dist/orchestrator/index.js +10 -0
  134. package/dist/orchestrator/index.js.map +1 -0
  135. package/dist/orchestrator/manager.d.ts +127 -0
  136. package/dist/orchestrator/manager.d.ts.map +1 -0
  137. package/dist/orchestrator/manager.js +498 -0
  138. package/dist/orchestrator/manager.js.map +1 -0
  139. package/dist/orchestrator/types.d.ts +141 -0
  140. package/dist/orchestrator/types.d.ts.map +1 -0
  141. package/dist/orchestrator/types.js +9 -0
  142. package/dist/orchestrator/types.js.map +1 -0
  143. package/dist/policy/engine.d.ts +55 -0
  144. package/dist/policy/engine.d.ts.map +1 -0
  145. package/dist/policy/engine.js +288 -0
  146. package/dist/policy/engine.js.map +1 -0
  147. package/dist/policy/natural-language.d.ts +141 -0
  148. package/dist/policy/natural-language.d.ts.map +1 -0
  149. package/dist/policy/natural-language.js +552 -0
  150. package/dist/policy/natural-language.js.map +1 -0
  151. package/dist/policy/parser.d.ts +141 -0
  152. package/dist/policy/parser.d.ts.map +1 -0
  153. package/dist/policy/parser.js +314 -0
  154. package/dist/policy/parser.js.map +1 -0
  155. package/dist/policy/types.d.ts +428 -0
  156. package/dist/policy/types.d.ts.map +1 -0
  157. package/dist/policy/types.js +32 -0
  158. package/dist/policy/types.js.map +1 -0
  159. package/dist/policy/validator.d.ts +72 -0
  160. package/dist/policy/validator.d.ts.map +1 -0
  161. package/dist/policy/validator.js +453 -0
  162. package/dist/policy/validator.js.map +1 -0
  163. package/dist/proxy/bridge.d.ts +84 -0
  164. package/dist/proxy/bridge.d.ts.map +1 -0
  165. package/dist/proxy/bridge.js +217 -0
  166. package/dist/proxy/bridge.js.map +1 -0
  167. package/dist/proxy/client.d.ts +130 -0
  168. package/dist/proxy/client.d.ts.map +1 -0
  169. package/dist/proxy/client.js +290 -0
  170. package/dist/proxy/client.js.map +1 -0
  171. package/dist/proxy/server.d.ts +111 -0
  172. package/dist/proxy/server.d.ts.map +1 -0
  173. package/dist/proxy/server.js +444 -0
  174. package/dist/proxy/server.js.map +1 -0
  175. package/dist/scanner.d.ts +91 -0
  176. package/dist/scanner.d.ts.map +1 -0
  177. package/dist/scanner.js +373 -0
  178. package/dist/scanner.js.map +1 -0
  179. package/dist/session/index.d.ts +32 -0
  180. package/dist/session/index.d.ts.map +1 -0
  181. package/dist/session/index.js +31 -0
  182. package/dist/session/index.js.map +1 -0
  183. package/dist/session/manager.d.ts +166 -0
  184. package/dist/session/manager.d.ts.map +1 -0
  185. package/dist/session/manager.js +454 -0
  186. package/dist/session/manager.js.map +1 -0
  187. package/dist/session/sqlite-store.d.ts +54 -0
  188. package/dist/session/sqlite-store.d.ts.map +1 -0
  189. package/dist/session/sqlite-store.js +209 -0
  190. package/dist/session/sqlite-store.js.map +1 -0
  191. package/dist/session/types.d.ts +179 -0
  192. package/dist/session/types.d.ts.map +1 -0
  193. package/dist/session/types.js +38 -0
  194. package/dist/session/types.js.map +1 -0
  195. package/dist/templates.d.ts +64 -0
  196. package/dist/templates.d.ts.map +1 -0
  197. package/dist/templates.js +451 -0
  198. package/dist/templates.js.map +1 -0
  199. package/dist/utils/config.d.ts +57 -0
  200. package/dist/utils/config.d.ts.map +1 -0
  201. package/dist/utils/config.js +104 -0
  202. package/dist/utils/config.js.map +1 -0
  203. package/dist/utils/errors.d.ts +18 -0
  204. package/dist/utils/errors.d.ts.map +1 -0
  205. package/dist/utils/errors.js +35 -0
  206. package/dist/utils/errors.js.map +1 -0
  207. package/dist/utils/logger.d.ts +144 -0
  208. package/dist/utils/logger.d.ts.map +1 -0
  209. package/dist/utils/logger.js +300 -0
  210. package/dist/utils/logger.js.map +1 -0
  211. package/dist/wizard.d.ts +68 -0
  212. package/dist/wizard.d.ts.map +1 -0
  213. package/dist/wizard.js +395 -0
  214. package/dist/wizard.js.map +1 -0
  215. package/package.json +99 -0
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Tollgate Bridge
3
+ *
4
+ * Orchestrates the proxy components: policy engine, session manager,
5
+ * audit logger, approval handler, and upstream client.
6
+ *
7
+ * Resilience features:
8
+ * - Graceful shutdown with configurable timeout
9
+ * - Force exit after graceful shutdown timeout
10
+ * - Health status monitoring
11
+ */
12
+ import { homedir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ import { PolicyEngine } from '../policy/engine.js';
15
+ import { AuditLogger } from '../audit/logger.js';
16
+ import { TerminalApprovalHandler } from '../approval/terminal.js';
17
+ import { InteractiveApprovalHandler } from '../approval/interactive.js';
18
+ import { TollgateServer } from './server.js';
19
+ import { UpstreamClient } from './client.js';
20
+ import { SessionManager } from '../session/manager.js';
21
+ import { SqliteSessionStore } from '../session/sqlite-store.js';
22
+ import { ConfigError } from '../utils/errors.js';
23
+ import { getServerConfig, validateConfig } from '../policy/parser.js';
24
+ import { proxyLogger as logger } from '../utils/logger.js';
25
+ import { DEFAULT_RESILIENCE } from '../constants.js';
26
+ export class TollgateBridge {
27
+ server = null;
28
+ options;
29
+ resilience;
30
+ isShuttingDown = false;
31
+ forceExitTimeout = null;
32
+ constructor(options) {
33
+ this.options = options;
34
+ // Merge resilience configuration with defaults
35
+ const configResilience = options.config.resilience ?? {};
36
+ this.resilience = {
37
+ failureMode: options.failureMode ?? configResilience.failureMode ?? DEFAULT_RESILIENCE.failureMode,
38
+ upstreamTimeoutMs: configResilience.upstreamTimeoutMs ?? DEFAULT_RESILIENCE.upstreamTimeoutMs,
39
+ healthCheck: {
40
+ enabled: configResilience.healthCheck?.enabled ?? DEFAULT_RESILIENCE.healthCheck.enabled,
41
+ intervalMs: configResilience.healthCheck?.intervalMs ?? DEFAULT_RESILIENCE.healthCheck.intervalMs,
42
+ timeoutMs: configResilience.healthCheck?.timeoutMs ?? DEFAULT_RESILIENCE.healthCheck.timeoutMs,
43
+ failureThreshold: configResilience.healthCheck?.failureThreshold ?? DEFAULT_RESILIENCE.healthCheck.failureThreshold,
44
+ },
45
+ shutdown: {
46
+ timeoutMs: configResilience.shutdown?.timeoutMs ?? DEFAULT_RESILIENCE.shutdown.timeoutMs,
47
+ drainTimeoutMs: configResilience.shutdown?.drainTimeoutMs ?? DEFAULT_RESILIENCE.shutdown.drainTimeoutMs,
48
+ },
49
+ };
50
+ }
51
+ async start() {
52
+ const { config, serverName } = this.options;
53
+ // Validate configuration
54
+ validateConfig(config);
55
+ // Get server configuration
56
+ const serverConfig = getServerConfig(config, serverName);
57
+ if (!serverConfig) {
58
+ throw new ConfigError(`Server "${serverName}" not found in configuration`, {
59
+ availableServers: Object.keys(config.servers ?? {}),
60
+ });
61
+ }
62
+ // Initialize components
63
+ const policyEngine = new PolicyEngine(config);
64
+ const auditLogger = new AuditLogger(this.options.auditPath);
65
+ const approvalHandler = this.createApprovalHandler(config);
66
+ // Create upstream client with resilience configuration
67
+ const upstreamClient = new UpstreamClient({
68
+ config: serverConfig,
69
+ callTimeoutMs: this.resilience.upstreamTimeoutMs,
70
+ healthCheck: this.resilience.healthCheck,
71
+ onHealthChange: this.handleHealthChange.bind(this),
72
+ });
73
+ // Create session manager unless disabled
74
+ const sessionManager = this.options.disableSessions
75
+ ? undefined
76
+ : new SessionManager(this.createSessionStore(config));
77
+ // Create and start the server
78
+ this.server = new TollgateServer({
79
+ serverName,
80
+ policyEngine,
81
+ auditLogger,
82
+ approvalHandler,
83
+ upstreamClient,
84
+ sessionManager,
85
+ dryRun: this.options.dryRun,
86
+ failureMode: this.resilience.failureMode,
87
+ });
88
+ // Handle shutdown signals
89
+ const shutdown = async (signal) => {
90
+ if (this.isShuttingDown) {
91
+ logger.warn('Force exit requested');
92
+ process.exit(1);
93
+ }
94
+ this.isShuttingDown = true;
95
+ logger.info('Shutting down gracefully', { signal });
96
+ // Set up force exit timeout
97
+ this.forceExitTimeout = setTimeout(() => {
98
+ logger.error('Graceful shutdown timeout - forcing exit');
99
+ process.exit(1);
100
+ }, this.resilience.shutdown.timeoutMs);
101
+ // Unref so it doesn't prevent exit if we finish early
102
+ this.forceExitTimeout.unref();
103
+ try {
104
+ await this.stop();
105
+ if (this.forceExitTimeout) {
106
+ clearTimeout(this.forceExitTimeout);
107
+ }
108
+ logger.info('Shutdown complete');
109
+ process.exit(0);
110
+ }
111
+ catch (error) {
112
+ logger.error('Error during shutdown', {
113
+ error: error instanceof Error ? error.message : String(error),
114
+ });
115
+ process.exit(1);
116
+ }
117
+ };
118
+ process.on('SIGINT', () => shutdown('SIGINT'));
119
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
120
+ await this.server.start();
121
+ }
122
+ /**
123
+ * Stop the bridge and all components.
124
+ * Waits for in-flight requests to complete before closing.
125
+ */
126
+ async stop() {
127
+ if (this.server) {
128
+ await this.server.close(this.resilience.shutdown.drainTimeoutMs);
129
+ this.server = null;
130
+ }
131
+ }
132
+ /**
133
+ * Handle upstream health status changes.
134
+ */
135
+ handleHealthChange(status, previousStatus) {
136
+ if (status === 'unhealthy') {
137
+ logger.warn('Upstream server became unhealthy', {
138
+ previousStatus,
139
+ failureMode: this.resilience.failureMode,
140
+ });
141
+ }
142
+ else if (status === 'healthy' && previousStatus === 'unhealthy') {
143
+ logger.info('Upstream server recovered and is now healthy');
144
+ }
145
+ }
146
+ /**
147
+ * Creates the appropriate approval handler based on configuration.
148
+ */
149
+ createApprovalHandler(config) {
150
+ const method = config.approval?.method ?? 'terminal';
151
+ const timeoutMs = this.options.approvalTimeout ?? config.approval?.timeout ?? 60000;
152
+ switch (method) {
153
+ case 'interactive':
154
+ return new InteractiveApprovalHandler({
155
+ port: config.approval?.port,
156
+ timeoutMs,
157
+ });
158
+ case 'webhook':
159
+ // Webhook not yet implemented - fall back to terminal with warning
160
+ logger.warn('Webhook approval method not yet implemented, using terminal');
161
+ return new TerminalApprovalHandler(timeoutMs);
162
+ case 'terminal':
163
+ default:
164
+ return new TerminalApprovalHandler(timeoutMs);
165
+ }
166
+ }
167
+ /**
168
+ * Creates the appropriate session store based on configuration.
169
+ */
170
+ createSessionStore(config) {
171
+ const persist = config.session?.persist ?? false;
172
+ if (!persist) {
173
+ // Use in-memory store (default)
174
+ return undefined;
175
+ }
176
+ // Use SQLite persistent store
177
+ const defaultPath = join(homedir(), '.tollgate', 'sessions.db');
178
+ const dbPath = config.session?.path ?? defaultPath;
179
+ logger.info('Using persistent session store', { path: dbPath });
180
+ return new SqliteSessionStore(dbPath);
181
+ }
182
+ }
183
+ export async function startWrapMode(options) {
184
+ // Create an inline config for wrap mode
185
+ const config = {
186
+ version: '1',
187
+ defaults: {
188
+ action: options.defaultAction ?? 'prompt',
189
+ },
190
+ servers: {
191
+ wrapped: {
192
+ command: options.command,
193
+ args: options.args,
194
+ env: options.env,
195
+ },
196
+ },
197
+ approval: {
198
+ method: options.approvalMethod ?? 'terminal',
199
+ port: options.approvalPort,
200
+ timeout: options.approvalTimeout,
201
+ },
202
+ session: {
203
+ persist: options.persistSessions ?? false,
204
+ path: options.sessionPath,
205
+ },
206
+ };
207
+ const bridge = new TollgateBridge({
208
+ config,
209
+ serverName: 'wrapped',
210
+ auditPath: options.auditPath,
211
+ approvalTimeout: options.approvalTimeout,
212
+ dryRun: options.dryRun,
213
+ failureMode: options.failureMode,
214
+ });
215
+ await bridge.start();
216
+ }
217
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Upstream MCP Client
3
+ *
4
+ * Manages connection to the upstream MCP server with:
5
+ * - Health checking and status monitoring
6
+ * - Timeout support for tool calls
7
+ * - Connection state tracking
8
+ */
9
+ import type { CallToolResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js';
10
+ import type { ServerConfig, HealthCheckConfig } from '../policy/types.js';
11
+ /**
12
+ * Health status of the upstream server.
13
+ */
14
+ export type HealthStatus = 'healthy' | 'unhealthy' | 'unknown';
15
+ /**
16
+ * Result of a health check operation.
17
+ */
18
+ export interface HealthCheckResult {
19
+ status: HealthStatus;
20
+ lastCheck: Date;
21
+ consecutiveFailures: number;
22
+ error?: string;
23
+ }
24
+ /**
25
+ * Options for the upstream client.
26
+ */
27
+ export interface UpstreamClientOptions {
28
+ /** Server configuration */
29
+ config: ServerConfig;
30
+ /** Timeout for tool calls in ms (default: 30000) */
31
+ callTimeoutMs?: number;
32
+ /** Health check configuration */
33
+ healthCheck?: HealthCheckConfig;
34
+ /** Callback when health status changes */
35
+ onHealthChange?: (status: HealthStatus, previousStatus: HealthStatus) => void;
36
+ }
37
+ /**
38
+ * Upstream MCP client with health monitoring and resilience features.
39
+ */
40
+ export declare class UpstreamClient {
41
+ private client;
42
+ private transport;
43
+ private config;
44
+ private initialized;
45
+ private callTimeoutMs;
46
+ private healthCheckConfig;
47
+ private healthCheckInterval;
48
+ private healthStatus;
49
+ private lastHealthCheck;
50
+ private consecutiveFailures;
51
+ private lastHealthError?;
52
+ private onHealthChange?;
53
+ private isClosing;
54
+ /** Mutex to prevent concurrent initialization */
55
+ private initializePromise;
56
+ constructor(options: UpstreamClientOptions | ServerConfig);
57
+ /**
58
+ * Initialize the upstream connection.
59
+ * Spawns the upstream MCP server process and establishes connection.
60
+ * Thread-safe: concurrent calls will wait for the first initialization to complete.
61
+ */
62
+ initialize(): Promise<void>;
63
+ /**
64
+ * Internal initialization logic.
65
+ */
66
+ private doInitialize;
67
+ /**
68
+ * List available tools from the upstream server.
69
+ */
70
+ listTools(): Promise<ListToolsResult>;
71
+ /**
72
+ * Call a tool on the upstream server with timeout support.
73
+ *
74
+ * @param name - Tool name
75
+ * @param args - Tool arguments
76
+ * @returns Tool call result
77
+ * @throws UpstreamError if timeout or upstream error occurs
78
+ */
79
+ callTool(name: string, args?: Record<string, unknown>): Promise<CallToolResult>;
80
+ /**
81
+ * Perform a health check on the upstream server.
82
+ * Tests connectivity by calling listTools().
83
+ *
84
+ * @returns Health check result
85
+ */
86
+ healthCheck(): Promise<HealthCheckResult>;
87
+ /**
88
+ * Get the current health status.
89
+ */
90
+ getHealthStatus(): HealthCheckResult;
91
+ /**
92
+ * Check if the upstream server is healthy.
93
+ */
94
+ isHealthy(): boolean;
95
+ /**
96
+ * Check if the client is initialized and connected.
97
+ */
98
+ isConnected(): boolean;
99
+ /**
100
+ * Close the upstream connection and stop health checks.
101
+ */
102
+ close(): Promise<void>;
103
+ /**
104
+ * Start periodic health checks.
105
+ */
106
+ private startHealthChecks;
107
+ /**
108
+ * Stop periodic health checks.
109
+ */
110
+ private stopHealthChecks;
111
+ /**
112
+ * Update health status and notify listeners.
113
+ */
114
+ private updateHealthStatus;
115
+ /**
116
+ * Ensure the client is initialized before operations.
117
+ */
118
+ private ensureInitialized;
119
+ /**
120
+ * Wrap a promise with a timeout.
121
+ *
122
+ * @param promise - Promise to wrap
123
+ * @param timeoutMs - Timeout in milliseconds
124
+ * @param operation - Description for error message
125
+ * @returns Promise result
126
+ * @throws UpstreamError on timeout
127
+ */
128
+ private withTimeout;
129
+ }
130
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/proxy/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAE1F,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAI1E;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,2BAA2B;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,0CAA0C;IAC1C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/E;AAeD;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAS;IAG9B,OAAO,CAAC,iBAAiB,CAA8B;IACvD,OAAO,CAAC,mBAAmB,CAA+B;IAC1D,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,cAAc,CAAC,CAA+D;IAGtF,OAAO,CAAC,SAAS,CAAS;IAC1B,iDAAiD;IACjD,OAAO,CAAC,iBAAiB,CAA8B;gBAE3C,OAAO,EAAE,qBAAqB,GAAG,YAAY;IA6BzD;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWjC;;OAEG;YACW,YAAY;IA0B1B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IAK3C;;;;;;;OAOG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,cAAc,CAAC;IAU1B;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAgD/C;;OAEG;IACH,eAAe,IAAI,iBAAiB;IASpC;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;OAQG;YACW,WAAW;CAsB1B"}
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Upstream MCP Client
3
+ *
4
+ * Manages connection to the upstream MCP server with:
5
+ * - Health checking and status monitoring
6
+ * - Timeout support for tool calls
7
+ * - Connection state tracking
8
+ */
9
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
10
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
11
+ import { UpstreamError } from '../utils/errors.js';
12
+ import { resolveServerEnv } from '../policy/parser.js';
13
+ import { upstreamLogger as logger } from '../utils/logger.js';
14
+ /**
15
+ * Default configuration values.
16
+ */
17
+ const DEFAULTS = {
18
+ callTimeoutMs: 30000,
19
+ healthCheck: {
20
+ enabled: true,
21
+ intervalMs: 30000,
22
+ timeoutMs: 5000,
23
+ failureThreshold: 3,
24
+ },
25
+ };
26
+ /**
27
+ * Upstream MCP client with health monitoring and resilience features.
28
+ */
29
+ export class UpstreamClient {
30
+ client;
31
+ transport = null;
32
+ config;
33
+ initialized = false;
34
+ callTimeoutMs;
35
+ // Health monitoring state
36
+ healthCheckConfig;
37
+ healthCheckInterval = null;
38
+ healthStatus = 'unknown';
39
+ lastHealthCheck = null;
40
+ consecutiveFailures = 0;
41
+ lastHealthError;
42
+ onHealthChange;
43
+ // Connection state tracking
44
+ isClosing = false;
45
+ /** Mutex to prevent concurrent initialization */
46
+ initializePromise = null;
47
+ constructor(options) {
48
+ // Support legacy constructor signature
49
+ if ('command' in options) {
50
+ this.config = options;
51
+ this.callTimeoutMs = DEFAULTS.callTimeoutMs;
52
+ this.healthCheckConfig = { ...DEFAULTS.healthCheck };
53
+ }
54
+ else {
55
+ this.config = options.config;
56
+ this.callTimeoutMs = options.callTimeoutMs ?? DEFAULTS.callTimeoutMs;
57
+ this.healthCheckConfig = {
58
+ enabled: options.healthCheck?.enabled ?? DEFAULTS.healthCheck.enabled,
59
+ intervalMs: options.healthCheck?.intervalMs ?? DEFAULTS.healthCheck.intervalMs,
60
+ timeoutMs: options.healthCheck?.timeoutMs ?? DEFAULTS.healthCheck.timeoutMs,
61
+ failureThreshold: options.healthCheck?.failureThreshold ?? DEFAULTS.healthCheck.failureThreshold,
62
+ };
63
+ this.onHealthChange = options.onHealthChange;
64
+ }
65
+ this.client = new Client({
66
+ name: 'tollgate-client',
67
+ version: '0.1.0',
68
+ }, {
69
+ capabilities: {},
70
+ });
71
+ }
72
+ /**
73
+ * Initialize the upstream connection.
74
+ * Spawns the upstream MCP server process and establishes connection.
75
+ * Thread-safe: concurrent calls will wait for the first initialization to complete.
76
+ */
77
+ async initialize() {
78
+ // Already initialized
79
+ if (this.initialized)
80
+ return;
81
+ // Use mutex pattern to prevent concurrent initialization
82
+ if (!this.initializePromise) {
83
+ this.initializePromise = this.doInitialize();
84
+ }
85
+ return this.initializePromise;
86
+ }
87
+ /**
88
+ * Internal initialization logic.
89
+ */
90
+ async doInitialize() {
91
+ if (this.initialized)
92
+ return;
93
+ const resolvedEnv = resolveServerEnv(this.config.env);
94
+ // StdioClientTransport spawns the process internally
95
+ this.transport = new StdioClientTransport({
96
+ command: this.config.command,
97
+ args: this.config.args,
98
+ env: resolvedEnv,
99
+ cwd: this.config.cwd,
100
+ });
101
+ // Connect the client
102
+ await this.client.connect(this.transport);
103
+ this.initialized = true;
104
+ // Start health checking if enabled
105
+ if (this.healthCheckConfig.enabled) {
106
+ this.startHealthChecks();
107
+ }
108
+ // Mark as healthy after successful initialization
109
+ this.updateHealthStatus('healthy');
110
+ }
111
+ /**
112
+ * List available tools from the upstream server.
113
+ */
114
+ async listTools() {
115
+ this.ensureInitialized();
116
+ return await this.client.listTools();
117
+ }
118
+ /**
119
+ * Call a tool on the upstream server with timeout support.
120
+ *
121
+ * @param name - Tool name
122
+ * @param args - Tool arguments
123
+ * @returns Tool call result
124
+ * @throws UpstreamError if timeout or upstream error occurs
125
+ */
126
+ async callTool(name, args) {
127
+ this.ensureInitialized();
128
+ return await this.withTimeout(this.client.callTool({ name, arguments: args }), this.callTimeoutMs, `Tool call '${name}'`);
129
+ }
130
+ /**
131
+ * Perform a health check on the upstream server.
132
+ * Tests connectivity by calling listTools().
133
+ *
134
+ * @returns Health check result
135
+ */
136
+ async healthCheck() {
137
+ if (!this.initialized) {
138
+ return {
139
+ status: 'unknown',
140
+ lastCheck: new Date(),
141
+ consecutiveFailures: 0,
142
+ error: 'Client not initialized',
143
+ };
144
+ }
145
+ try {
146
+ // Use listTools as a ping - it's lightweight and always available
147
+ await this.withTimeout(this.client.listTools(), this.healthCheckConfig.timeoutMs, 'Health check');
148
+ // Success - reset failure count
149
+ this.consecutiveFailures = 0;
150
+ this.lastHealthError = undefined;
151
+ this.updateHealthStatus('healthy');
152
+ return {
153
+ status: 'healthy',
154
+ lastCheck: new Date(),
155
+ consecutiveFailures: 0,
156
+ };
157
+ }
158
+ catch (error) {
159
+ this.consecutiveFailures++;
160
+ this.lastHealthError = error instanceof Error ? error.message : String(error);
161
+ const isUnhealthy = this.consecutiveFailures >= this.healthCheckConfig.failureThreshold;
162
+ if (isUnhealthy) {
163
+ this.updateHealthStatus('unhealthy');
164
+ }
165
+ return {
166
+ status: isUnhealthy ? 'unhealthy' : this.healthStatus,
167
+ lastCheck: new Date(),
168
+ consecutiveFailures: this.consecutiveFailures,
169
+ error: this.lastHealthError,
170
+ };
171
+ }
172
+ finally {
173
+ this.lastHealthCheck = new Date();
174
+ }
175
+ }
176
+ /**
177
+ * Get the current health status.
178
+ */
179
+ getHealthStatus() {
180
+ return {
181
+ status: this.healthStatus,
182
+ lastCheck: this.lastHealthCheck ?? new Date(),
183
+ consecutiveFailures: this.consecutiveFailures,
184
+ error: this.lastHealthError,
185
+ };
186
+ }
187
+ /**
188
+ * Check if the upstream server is healthy.
189
+ */
190
+ isHealthy() {
191
+ return this.healthStatus === 'healthy';
192
+ }
193
+ /**
194
+ * Check if the client is initialized and connected.
195
+ */
196
+ isConnected() {
197
+ return this.initialized && !this.isClosing;
198
+ }
199
+ /**
200
+ * Close the upstream connection and stop health checks.
201
+ */
202
+ async close() {
203
+ this.isClosing = true;
204
+ this.stopHealthChecks();
205
+ if (this.transport) {
206
+ await this.transport.close();
207
+ this.transport = null;
208
+ }
209
+ this.initialized = false;
210
+ }
211
+ /**
212
+ * Start periodic health checks.
213
+ */
214
+ startHealthChecks() {
215
+ if (this.healthCheckInterval)
216
+ return;
217
+ this.healthCheckInterval = setInterval(async () => {
218
+ if (this.initialized && !this.isClosing) {
219
+ try {
220
+ await this.healthCheck();
221
+ }
222
+ catch (error) {
223
+ // Log health check errors but don't crash
224
+ logger.error('Health check error', {
225
+ error: error instanceof Error ? error.message : String(error),
226
+ });
227
+ }
228
+ }
229
+ }, this.healthCheckConfig.intervalMs);
230
+ // Don't prevent process exit
231
+ this.healthCheckInterval.unref();
232
+ }
233
+ /**
234
+ * Stop periodic health checks.
235
+ */
236
+ stopHealthChecks() {
237
+ if (this.healthCheckInterval) {
238
+ clearInterval(this.healthCheckInterval);
239
+ this.healthCheckInterval = null;
240
+ }
241
+ }
242
+ /**
243
+ * Update health status and notify listeners.
244
+ */
245
+ updateHealthStatus(newStatus) {
246
+ const previousStatus = this.healthStatus;
247
+ this.healthStatus = newStatus;
248
+ if (previousStatus !== newStatus && this.onHealthChange) {
249
+ this.onHealthChange(newStatus, previousStatus);
250
+ }
251
+ }
252
+ /**
253
+ * Ensure the client is initialized before operations.
254
+ */
255
+ ensureInitialized() {
256
+ if (!this.initialized) {
257
+ throw new UpstreamError('Client not initialized');
258
+ }
259
+ if (this.isClosing) {
260
+ throw new UpstreamError('Client is closing');
261
+ }
262
+ }
263
+ /**
264
+ * Wrap a promise with a timeout.
265
+ *
266
+ * @param promise - Promise to wrap
267
+ * @param timeoutMs - Timeout in milliseconds
268
+ * @param operation - Description for error message
269
+ * @returns Promise result
270
+ * @throws UpstreamError on timeout
271
+ */
272
+ async withTimeout(promise, timeoutMs, operation) {
273
+ let timeoutId;
274
+ const timeoutPromise = new Promise((_, reject) => {
275
+ timeoutId = setTimeout(() => {
276
+ reject(new UpstreamError(`${operation} timed out after ${timeoutMs}ms`));
277
+ }, timeoutMs);
278
+ });
279
+ try {
280
+ const result = await Promise.race([promise, timeoutPromise]);
281
+ return result;
282
+ }
283
+ finally {
284
+ if (timeoutId) {
285
+ clearTimeout(timeoutId);
286
+ }
287
+ }
288
+ }
289
+ }
290
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/proxy/client.ts"],"names":[],"mappings":"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"}