@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,111 @@
1
+ /**
2
+ * Tollgate MCP Server
3
+ *
4
+ * Acts as a proxy between Claude Desktop and upstream MCP servers,
5
+ * intercepting tool calls and applying policy-based access control.
6
+ *
7
+ * Resilience features:
8
+ * - Failure modes: fail-closed, fail-open, fail-readonly
9
+ * - Health-aware request routing
10
+ * - In-flight request tracking for graceful shutdown
11
+ */
12
+ import type { PolicyEngine } from '../policy/engine.js';
13
+ import type { AuditLogger } from '../audit/logger.js';
14
+ import type { ApprovalHandler } from '../approval/types.js';
15
+ import type { UpstreamClient } from './client.js';
16
+ import type { SessionManager } from '../session/manager.js';
17
+ import type { FailureMode } from '../policy/types.js';
18
+ export interface TollgateServerOptions {
19
+ serverName: string;
20
+ policyEngine: PolicyEngine;
21
+ auditLogger: AuditLogger;
22
+ approvalHandler: ApprovalHandler;
23
+ upstreamClient: UpstreamClient;
24
+ /** Session manager for time-bounded approvals */
25
+ sessionManager?: SessionManager;
26
+ /**
27
+ * Enable dry-run mode.
28
+ * When true, tool calls are logged and policies evaluated,
29
+ * but calls are NOT forwarded to the upstream server.
30
+ */
31
+ dryRun?: boolean;
32
+ /**
33
+ * Failure mode when upstream is unavailable.
34
+ * - 'fail-closed': Deny all requests (default, most secure)
35
+ * - 'fail-open': Allow all requests (logged, for development)
36
+ * - 'fail-readonly': Only allow read operations (balanced)
37
+ */
38
+ failureMode?: FailureMode;
39
+ }
40
+ export declare class TollgateServer {
41
+ private server;
42
+ private transport;
43
+ private options;
44
+ private upstreamTools;
45
+ private failureMode;
46
+ /** In-flight request tracking for graceful shutdown */
47
+ private inFlightRequests;
48
+ /** Flag indicating shutdown is in progress */
49
+ private isShuttingDown;
50
+ constructor(options: TollgateServerOptions);
51
+ /**
52
+ * Check if the upstream server is available.
53
+ * Used to apply failure mode policies.
54
+ */
55
+ private isUpstreamHealthy;
56
+ /**
57
+ * Check if a tool name matches read-only patterns.
58
+ * Used for fail-readonly mode.
59
+ */
60
+ private isReadOnlyTool;
61
+ /**
62
+ * Apply failure mode policy when upstream is unavailable.
63
+ * Returns null if the request should proceed, or a CallToolResult to return immediately.
64
+ */
65
+ private applyFailureMode;
66
+ /**
67
+ * Get the number of in-flight requests.
68
+ */
69
+ getInFlightCount(): number;
70
+ /**
71
+ * Check if the server is currently shutting down.
72
+ */
73
+ isClosing(): boolean;
74
+ /**
75
+ * Wait for all in-flight requests to complete.
76
+ * @param timeoutMs Maximum time to wait in milliseconds
77
+ * @returns true if all requests completed, false if timed out
78
+ */
79
+ waitForInFlightRequests(timeoutMs: number): Promise<boolean>;
80
+ /** Promise to prevent concurrent ListTools initialization */
81
+ private listToolsPromise;
82
+ private setupHandlers;
83
+ /**
84
+ * Handles a tool call from the downstream client (Claude).
85
+ *
86
+ * Flow:
87
+ * 1. Check if shutting down (reject new requests)
88
+ * 2. Track request as in-flight
89
+ * 3. Check upstream health and apply failure mode
90
+ * 4. Evaluate policy to get decision (allow/deny/prompt)
91
+ * 5. If 'prompt', check for existing session grant
92
+ * 6. If no grant, prompt user (with session duration options)
93
+ * 7. If approved with session, create grant for future calls
94
+ * 8. Forward to upstream if allowed/approved
95
+ * 9. Log everything to audit
96
+ */
97
+ private handleToolCall;
98
+ /**
99
+ * Process a tool call after in-flight tracking is set up.
100
+ */
101
+ private processToolCall;
102
+ start(): Promise<void>;
103
+ /**
104
+ * Gracefully close the server.
105
+ * Waits for in-flight requests to complete before closing components.
106
+ *
107
+ * @param drainTimeoutMs - Time to wait for in-flight requests (default: 5000)
108
+ */
109
+ close(drainTimeoutMs?: number): Promise<void>;
110
+ }
111
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,iDAAiD;IACjD,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAiBD,qBAAa,cAAc;IAKzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,WAAW,CAAc;IAEjC,uDAAuD;IACvD,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,8CAA8C;IAC9C,OAAO,CAAC,cAAc,CAAS;gBAMnB,OAAO,EAAE,qBAAqB;IAyB1C;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAuExB;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;OAIG;IACG,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmClE,6DAA6D;IAC7D,OAAO,CAAC,gBAAgB,CAA8B;IAEtD,OAAO,CAAC,aAAa;IA0BrB;;;;;;;;;;;;;OAaG;YACW,cAAc;IA+B5B;;OAEG;YACW,eAAe;IA+OvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;;;;OAKG;IACG,KAAK,CAAC,cAAc,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBlD"}
@@ -0,0 +1,444 @@
1
+ /**
2
+ * Tollgate MCP Server
3
+ *
4
+ * Acts as a proxy between Claude Desktop and upstream MCP servers,
5
+ * intercepting tool calls and applying policy-based access control.
6
+ *
7
+ * Resilience features:
8
+ * - Failure modes: fail-closed, fail-open, fail-readonly
9
+ * - Health-aware request routing
10
+ * - In-flight request tracking for graceful shutdown
11
+ */
12
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
13
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
14
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
15
+ import { v4 as uuidv4 } from 'uuid';
16
+ import { proxyLogger as logger } from '../utils/logger.js';
17
+ /**
18
+ * Read-only tool name patterns for fail-readonly mode.
19
+ */
20
+ const READ_ONLY_PATTERNS = [
21
+ /^read/i,
22
+ /^get/i,
23
+ /^list/i,
24
+ /^query$/i,
25
+ /^search/i,
26
+ /^find/i,
27
+ /^describe/i,
28
+ /^show/i,
29
+ /^select/i,
30
+ ];
31
+ export class TollgateServer {
32
+ // ---------------------------------------------------------------------------
33
+ // Private State
34
+ // ---------------------------------------------------------------------------
35
+ server;
36
+ transport;
37
+ options;
38
+ upstreamTools = [];
39
+ failureMode;
40
+ /** In-flight request tracking for graceful shutdown */
41
+ inFlightRequests = new Set();
42
+ /** Flag indicating shutdown is in progress */
43
+ isShuttingDown = false;
44
+ // ---------------------------------------------------------------------------
45
+ // Constructor
46
+ // ---------------------------------------------------------------------------
47
+ constructor(options) {
48
+ this.options = options;
49
+ this.failureMode = options.failureMode ?? 'fail-closed';
50
+ this.server = new Server({
51
+ name: 'tollgate',
52
+ version: '0.1.0',
53
+ }, {
54
+ capabilities: {
55
+ tools: {},
56
+ },
57
+ });
58
+ this.transport = new StdioServerTransport();
59
+ this.setupHandlers();
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // Health & Failure Mode
63
+ // ---------------------------------------------------------------------------
64
+ /**
65
+ * Check if the upstream server is available.
66
+ * Used to apply failure mode policies.
67
+ */
68
+ isUpstreamHealthy() {
69
+ return this.options.upstreamClient.isHealthy();
70
+ }
71
+ /**
72
+ * Check if a tool name matches read-only patterns.
73
+ * Used for fail-readonly mode.
74
+ */
75
+ isReadOnlyTool(toolName) {
76
+ return READ_ONLY_PATTERNS.some((pattern) => pattern.test(toolName));
77
+ }
78
+ /**
79
+ * Apply failure mode policy when upstream is unavailable.
80
+ * Returns null if the request should proceed, or a CallToolResult to return immediately.
81
+ */
82
+ applyFailureMode(toolName, _args, auditId) {
83
+ // If upstream is healthy, no failure mode needed
84
+ if (this.isUpstreamHealthy()) {
85
+ return null;
86
+ }
87
+ const healthStatus = this.options.upstreamClient.getHealthStatus();
88
+ const errorDetail = healthStatus.error ? `: ${healthStatus.error}` : '';
89
+ switch (this.failureMode) {
90
+ case 'fail-closed':
91
+ // Deny all requests when upstream is down
92
+ this.options.auditLogger.logResult(auditId, null, 'error', `Upstream unavailable (fail-closed mode)${errorDetail}`, 0);
93
+ return {
94
+ content: [
95
+ {
96
+ type: 'text',
97
+ text: `Service temporarily unavailable: upstream server is not responding. Please try again later.`,
98
+ },
99
+ ],
100
+ isError: true,
101
+ };
102
+ case 'fail-open':
103
+ // Log warning but proceed (will likely fail at upstream call)
104
+ logger.warn(`Upstream unhealthy but proceeding (fail-open mode)`, { error: errorDetail || undefined });
105
+ return null;
106
+ case 'fail-readonly':
107
+ // Only allow read operations
108
+ if (this.isReadOnlyTool(toolName)) {
109
+ logger.warn('Upstream unhealthy, allowing read-only operation (fail-readonly mode)');
110
+ return null;
111
+ }
112
+ this.options.auditLogger.logResult(auditId, null, 'error', `Upstream unavailable - only read operations allowed (fail-readonly mode)${errorDetail}`, 0);
113
+ return {
114
+ content: [
115
+ {
116
+ type: 'text',
117
+ text: `Service degraded: upstream server is not responding. Only read operations are currently available.`,
118
+ },
119
+ ],
120
+ isError: true,
121
+ };
122
+ default:
123
+ return null;
124
+ }
125
+ }
126
+ // ---------------------------------------------------------------------------
127
+ // Request Tracking & Shutdown
128
+ // ---------------------------------------------------------------------------
129
+ /**
130
+ * Get the number of in-flight requests.
131
+ */
132
+ getInFlightCount() {
133
+ return this.inFlightRequests.size;
134
+ }
135
+ /**
136
+ * Check if the server is currently shutting down.
137
+ */
138
+ isClosing() {
139
+ return this.isShuttingDown;
140
+ }
141
+ /**
142
+ * Wait for all in-flight requests to complete.
143
+ * @param timeoutMs Maximum time to wait in milliseconds
144
+ * @returns true if all requests completed, false if timed out
145
+ */
146
+ async waitForInFlightRequests(timeoutMs) {
147
+ if (this.inFlightRequests.size === 0) {
148
+ return true;
149
+ }
150
+ const startTime = Date.now();
151
+ const checkInterval = 100;
152
+ return new Promise((resolve) => {
153
+ const check = () => {
154
+ if (this.inFlightRequests.size === 0) {
155
+ resolve(true);
156
+ return;
157
+ }
158
+ if (Date.now() - startTime >= timeoutMs) {
159
+ logger.warn('Requests still in-flight after timeout', {
160
+ count: this.inFlightRequests.size,
161
+ timeoutMs,
162
+ });
163
+ resolve(false);
164
+ return;
165
+ }
166
+ setTimeout(check, checkInterval);
167
+ };
168
+ check();
169
+ });
170
+ }
171
+ // ---------------------------------------------------------------------------
172
+ // MCP Protocol Handlers
173
+ // ---------------------------------------------------------------------------
174
+ /** Promise to prevent concurrent ListTools initialization */
175
+ listToolsPromise = null;
176
+ setupHandlers() {
177
+ // List tools - forward from upstream with initialization mutex
178
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
179
+ if (this.upstreamTools.length === 0) {
180
+ // Use a mutex pattern to prevent concurrent ListTools calls
181
+ if (!this.listToolsPromise) {
182
+ this.listToolsPromise = (async () => {
183
+ const result = await this.options.upstreamClient.listTools();
184
+ this.upstreamTools = result.tools;
185
+ })();
186
+ }
187
+ await this.listToolsPromise;
188
+ }
189
+ return { tools: this.upstreamTools };
190
+ });
191
+ // Call tool - intercept and apply policy
192
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
193
+ return this.handleToolCall(request.params.name, request.params.arguments ?? {});
194
+ });
195
+ }
196
+ // ---------------------------------------------------------------------------
197
+ // Tool Call Processing
198
+ // ---------------------------------------------------------------------------
199
+ /**
200
+ * Handles a tool call from the downstream client (Claude).
201
+ *
202
+ * Flow:
203
+ * 1. Check if shutting down (reject new requests)
204
+ * 2. Track request as in-flight
205
+ * 3. Check upstream health and apply failure mode
206
+ * 4. Evaluate policy to get decision (allow/deny/prompt)
207
+ * 5. If 'prompt', check for existing session grant
208
+ * 6. If no grant, prompt user (with session duration options)
209
+ * 7. If approved with session, create grant for future calls
210
+ * 8. Forward to upstream if allowed/approved
211
+ * 9. Log everything to audit
212
+ */
213
+ async handleToolCall(toolName, args) {
214
+ // Generate unique request ID for tracking
215
+ const requestId = uuidv4();
216
+ // Reject new requests during shutdown
217
+ if (this.isShuttingDown) {
218
+ return {
219
+ content: [
220
+ {
221
+ type: 'text',
222
+ text: 'Server is shutting down. Please retry later.',
223
+ },
224
+ ],
225
+ isError: true,
226
+ };
227
+ }
228
+ // Track this request as in-flight
229
+ this.inFlightRequests.add(requestId);
230
+ try {
231
+ return await this.processToolCall(toolName, args, requestId);
232
+ }
233
+ finally {
234
+ // Remove from in-flight tracking
235
+ this.inFlightRequests.delete(requestId);
236
+ }
237
+ }
238
+ /**
239
+ * Process a tool call after in-flight tracking is set up.
240
+ */
241
+ async processToolCall(toolName, args, _requestId) {
242
+ const startTime = Date.now();
243
+ const context = {
244
+ server: this.options.serverName,
245
+ tool: toolName,
246
+ args,
247
+ timestamp: new Date(),
248
+ };
249
+ // Evaluate policy
250
+ const decision = this.options.policyEngine.evaluate(context);
251
+ // Check if there's an active session grant that covers this call
252
+ let sessionGrantId;
253
+ const sessionManager = this.options.sessionManager;
254
+ if (decision.action === 'prompt' && sessionManager) {
255
+ const sessionCheck = sessionManager.checkGrant(context);
256
+ if (sessionCheck.granted && sessionCheck.grant) {
257
+ // Session grant found - skip prompting
258
+ sessionGrantId = sessionCheck.grant.id;
259
+ // Log session grant usage
260
+ this.options.auditLogger.logSessionGrantUsage(sessionGrantId);
261
+ // Log the attempt with session grant reference
262
+ const auditId = this.options.auditLogger.logAttempt(context, decision, sessionGrantId);
263
+ // Check upstream health and apply failure mode if needed
264
+ const failureModeResult = this.applyFailureMode(toolName, args, auditId);
265
+ if (failureModeResult) {
266
+ return failureModeResult;
267
+ }
268
+ // In dry-run mode, skip the actual upstream call
269
+ if (this.options.dryRun) {
270
+ const duration = Date.now() - startTime;
271
+ this.options.auditLogger.logResult(auditId, 'approved', 'success', '[DRY RUN] Tool call simulated (session grant)', duration);
272
+ return {
273
+ content: [
274
+ {
275
+ type: 'text',
276
+ text: `[DRY RUN] Would have executed (via session): ${toolName}(${JSON.stringify(args)})`,
277
+ },
278
+ ],
279
+ isError: false,
280
+ };
281
+ }
282
+ try {
283
+ // Forward directly to upstream
284
+ const result = await this.options.upstreamClient.callTool(toolName, args);
285
+ const duration = Date.now() - startTime;
286
+ this.options.auditLogger.logResult(auditId, 'approved', // Implicitly approved by session
287
+ 'success', undefined, duration);
288
+ return result;
289
+ }
290
+ catch (error) {
291
+ const duration = Date.now() - startTime;
292
+ const errorMessage = error instanceof Error ? error.message : String(error);
293
+ this.options.auditLogger.logResult(auditId, 'approved', 'error', errorMessage, duration);
294
+ return {
295
+ content: [
296
+ {
297
+ type: 'text',
298
+ text: `Error executing tool: ${errorMessage}`,
299
+ },
300
+ ],
301
+ isError: true,
302
+ };
303
+ }
304
+ }
305
+ }
306
+ // Log the attempt (without session grant - not covered or policy allows/denies)
307
+ const auditId = this.options.auditLogger.logAttempt(context, decision);
308
+ // Check upstream health and apply failure mode if needed (for non-session path)
309
+ const failureModeResult = this.applyFailureMode(toolName, args, auditId);
310
+ if (failureModeResult) {
311
+ return failureModeResult;
312
+ }
313
+ try {
314
+ let userDecision = null;
315
+ switch (decision.action) {
316
+ case 'allow':
317
+ // Forward directly to upstream
318
+ break;
319
+ case 'deny': {
320
+ const denyDuration = Date.now() - startTime;
321
+ this.options.auditLogger.logResult(auditId, null, 'error', decision.reason, denyDuration);
322
+ return {
323
+ content: [
324
+ {
325
+ type: 'text',
326
+ text: `Action denied by policy: ${decision.reason ?? 'No reason provided'}`,
327
+ },
328
+ ],
329
+ isError: true,
330
+ };
331
+ }
332
+ case 'prompt': {
333
+ const requestId = uuidv4();
334
+ const approvalResponse = await this.options.approvalHandler.prompt({
335
+ id: requestId,
336
+ context,
337
+ decision,
338
+ timestamp: new Date(),
339
+ // Session config would come from policy in future
340
+ sessionConfig: undefined,
341
+ });
342
+ userDecision = approvalResponse.result;
343
+ if (approvalResponse.result !== 'approved') {
344
+ const promptDuration = Date.now() - startTime;
345
+ this.options.auditLogger.logResult(auditId, userDecision, 'error', `User ${approvalResponse.result}`, promptDuration);
346
+ return {
347
+ content: [
348
+ {
349
+ type: 'text',
350
+ text: `Action ${approvalResponse.result} by user`,
351
+ },
352
+ ],
353
+ isError: true,
354
+ };
355
+ }
356
+ // If user approved with a session grant, create it
357
+ if (approvalResponse.sessionGrant && sessionManager) {
358
+ const grant = sessionManager.createGrant({
359
+ context,
360
+ scope: approvalResponse.sessionGrant.scope,
361
+ duration: approvalResponse.sessionGrant.duration,
362
+ grantedBy: 'terminal',
363
+ pattern: approvalResponse.sessionGrant.pattern,
364
+ originalRequestId: requestId,
365
+ });
366
+ // Log the session grant
367
+ this.options.auditLogger.logSessionGrant(grant);
368
+ sessionGrantId = grant.id;
369
+ }
370
+ break;
371
+ }
372
+ }
373
+ // In dry-run mode, skip the actual upstream call
374
+ if (this.options.dryRun) {
375
+ const duration = Date.now() - startTime;
376
+ this.options.auditLogger.logResult(auditId, userDecision, 'success', '[DRY RUN] Tool call simulated', duration);
377
+ return {
378
+ content: [
379
+ {
380
+ type: 'text',
381
+ text: `[DRY RUN] Would have executed: ${toolName}(${JSON.stringify(args)})`,
382
+ },
383
+ ],
384
+ isError: false,
385
+ };
386
+ }
387
+ // Forward to upstream
388
+ const result = await this.options.upstreamClient.callTool(toolName, args);
389
+ const duration = Date.now() - startTime;
390
+ this.options.auditLogger.logResult(auditId, userDecision, 'success', undefined, duration);
391
+ return result;
392
+ }
393
+ catch (error) {
394
+ const duration = Date.now() - startTime;
395
+ const errorMessage = error instanceof Error ? error.message : String(error);
396
+ this.options.auditLogger.logResult(auditId, null, 'error', errorMessage, duration);
397
+ return {
398
+ content: [
399
+ {
400
+ type: 'text',
401
+ text: `Error executing tool: ${errorMessage}`,
402
+ },
403
+ ],
404
+ isError: true,
405
+ };
406
+ }
407
+ }
408
+ // ---------------------------------------------------------------------------
409
+ // Lifecycle Methods
410
+ // ---------------------------------------------------------------------------
411
+ async start() {
412
+ // Wait for upstream client to be ready
413
+ await this.options.upstreamClient.initialize();
414
+ // Pre-fetch tools
415
+ const result = await this.options.upstreamClient.listTools();
416
+ this.upstreamTools = result.tools;
417
+ // Connect to Claude Desktop via stdio
418
+ await this.server.connect(this.transport);
419
+ }
420
+ /**
421
+ * Gracefully close the server.
422
+ * Waits for in-flight requests to complete before closing components.
423
+ *
424
+ * @param drainTimeoutMs - Time to wait for in-flight requests (default: 5000)
425
+ */
426
+ async close(drainTimeoutMs = 5000) {
427
+ // Mark as shutting down to reject new requests
428
+ this.isShuttingDown = true;
429
+ // Wait for in-flight requests to complete
430
+ if (this.inFlightRequests.size > 0) {
431
+ logger.info('Waiting for in-flight requests to complete', {
432
+ count: this.inFlightRequests.size,
433
+ });
434
+ await this.waitForInFlightRequests(drainTimeoutMs);
435
+ }
436
+ // Close all components
437
+ await this.server.close();
438
+ this.options.approvalHandler.close();
439
+ this.options.auditLogger.close();
440
+ this.options.sessionManager?.close();
441
+ await this.options.upstreamClient.close();
442
+ }
443
+ }
444
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * MCP Server Scanner
3
+ *
4
+ * Scans MCP servers to discover tools and assess security risks.
5
+ * Spawns the server, calls tools/list, analyzes tool definitions,
6
+ * and generates recommended security policies.
7
+ *
8
+ * Usage:
9
+ * tollgate scan @modelcontextprotocol/server-postgres
10
+ * tollgate scan npx -y @anthropic/mcp-server-filesystem ./
11
+ *
12
+ * @module scanner
13
+ */
14
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
15
+ /**
16
+ * Risk level for a tool.
17
+ */
18
+ export type ToolRiskLevel = 'safe' | 'read' | 'write' | 'destructive' | 'dangerous';
19
+ /**
20
+ * Risk indicator found in a tool definition.
21
+ */
22
+ export interface RiskIndicator {
23
+ type: 'keyword' | 'parameter' | 'pattern' | 'capability';
24
+ value: string;
25
+ risk: ToolRiskLevel;
26
+ description: string;
27
+ }
28
+ /**
29
+ * Analyzed tool with risk assessment.
30
+ */
31
+ export interface AnalyzedTool {
32
+ name: string;
33
+ description: string;
34
+ risk: ToolRiskLevel;
35
+ category: 'read' | 'write' | 'admin' | 'unknown';
36
+ indicators: RiskIndicator[];
37
+ recommendedAction: 'allow' | 'prompt' | 'deny' | 'smart';
38
+ recommendedAnalyzer?: 'sql' | 'filesystem' | 'shell' | 'http';
39
+ inputSchema?: Record<string, unknown>;
40
+ }
41
+ /**
42
+ * Complete scan result for an MCP server.
43
+ */
44
+ export interface ScanResult {
45
+ serverCommand: string;
46
+ serverArgs: string[];
47
+ scanTime: Date;
48
+ toolCount: number;
49
+ tools: AnalyzedTool[];
50
+ overallRisk: ToolRiskLevel;
51
+ summary: {
52
+ safe: number;
53
+ read: number;
54
+ write: number;
55
+ destructive: number;
56
+ dangerous: number;
57
+ };
58
+ }
59
+ /**
60
+ * Options for the scanner.
61
+ */
62
+ export interface ScannerOptions {
63
+ /** Connection timeout in milliseconds */
64
+ timeoutMs?: number;
65
+ /** Environment variables to pass to the server */
66
+ env?: Record<string, string>;
67
+ /** Whether to skip the actual server spawn (for testing) */
68
+ dryRun?: boolean;
69
+ }
70
+ /**
71
+ * Analyze a single tool definition to assess its risk.
72
+ */
73
+ export declare function analyzeTool(tool: Tool): AnalyzedTool;
74
+ /**
75
+ * Scan an MCP server to discover tools and assess security risks.
76
+ *
77
+ * @param command - Server command (e.g., "npx")
78
+ * @param args - Server arguments (e.g., ["-y", "@modelcontextprotocol/server-postgres"])
79
+ * @param options - Scanner options
80
+ * @returns Scan result with tool analysis
81
+ */
82
+ export declare function scanServer(command: string, args: string[], options?: ScannerOptions): Promise<ScanResult>;
83
+ /**
84
+ * Generate a tollgate.yaml policy configuration from scan results.
85
+ */
86
+ export declare function generatePolicy(scanResult: ScanResult, serverName?: string): string;
87
+ /**
88
+ * Generate a partial config to append to existing tollgate.yaml.
89
+ */
90
+ export declare function generateServerConfig(scanResult: ScanResult, serverName?: string): string;
91
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAM/D;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,WAAW,CAAC;AAEpF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IACjD,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,iBAAiB,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IACzD,mBAAmB,CAAC,EAAE,KAAK,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,aAAa,CAAC;IAC3B,OAAO,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;CACL;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAyDD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAgJpD;AAsBD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,cAAmB,GAC7B,OAAO,CAAC,UAAU,CAAC,CA+CrB;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,GAAE,MAAyB,GACtC,MAAM,CA+FR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAChC,UAAU,EAAE,UAAU,EACtB,UAAU,GAAE,MAAyB,GACtC,MAAM,CAUR"}