@mcp-rating/gateway 0.2.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 (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +130 -0
  3. package/dist/ads/ad-tracker.d.ts +63 -0
  4. package/dist/ads/ad-tracker.js +144 -0
  5. package/dist/ads/ad-tracker.js.map +1 -0
  6. package/dist/analytics/usage-tracker.d.ts +67 -0
  7. package/dist/analytics/usage-tracker.js +148 -0
  8. package/dist/analytics/usage-tracker.js.map +1 -0
  9. package/dist/audit/audit-log.d.ts +71 -0
  10. package/dist/audit/audit-log.js +72 -0
  11. package/dist/audit/audit-log.js.map +1 -0
  12. package/dist/config/gateway-config.d.ts +6 -0
  13. package/dist/config/gateway-config.js +135 -0
  14. package/dist/config/gateway-config.js.map +1 -0
  15. package/dist/config/groups.d.ts +29 -0
  16. package/dist/config/groups.js +102 -0
  17. package/dist/config/groups.js.map +1 -0
  18. package/dist/config/profiles.d.ts +42 -0
  19. package/dist/config/profiles.js +167 -0
  20. package/dist/config/profiles.js.map +1 -0
  21. package/dist/config/types.d.ts +76 -0
  22. package/dist/config/types.js +2 -0
  23. package/dist/config/types.js.map +1 -0
  24. package/dist/connection/auto-installer.d.ts +13 -0
  25. package/dist/connection/auto-installer.js +61 -0
  26. package/dist/connection/auto-installer.js.map +1 -0
  27. package/dist/connection/connection-manager.d.ts +106 -0
  28. package/dist/connection/connection-manager.js +845 -0
  29. package/dist/connection/connection-manager.js.map +1 -0
  30. package/dist/connection/downstream-client.d.ts +50 -0
  31. package/dist/connection/downstream-client.js +170 -0
  32. package/dist/connection/downstream-client.js.map +1 -0
  33. package/dist/connection/http-client.d.ts +12 -0
  34. package/dist/connection/http-client.js +26 -0
  35. package/dist/connection/http-client.js.map +1 -0
  36. package/dist/connection/sse-client.d.ts +12 -0
  37. package/dist/connection/sse-client.js +26 -0
  38. package/dist/connection/sse-client.js.map +1 -0
  39. package/dist/connection/transport-factory.d.ts +31 -0
  40. package/dist/connection/transport-factory.js +67 -0
  41. package/dist/connection/transport-factory.js.map +1 -0
  42. package/dist/connection/types.d.ts +134 -0
  43. package/dist/connection/types.js +5 -0
  44. package/dist/connection/types.js.map +1 -0
  45. package/dist/connection/ws-client.d.ts +12 -0
  46. package/dist/connection/ws-client.js +26 -0
  47. package/dist/connection/ws-client.js.map +1 -0
  48. package/dist/discovery/auto-recommender.d.ts +51 -0
  49. package/dist/discovery/auto-recommender.js +176 -0
  50. package/dist/discovery/auto-recommender.js.map +1 -0
  51. package/dist/gateway-server.d.ts +42 -0
  52. package/dist/gateway-server.js +135 -0
  53. package/dist/gateway-server.js.map +1 -0
  54. package/dist/http-daemon.d.ts +26 -0
  55. package/dist/http-daemon.js +302 -0
  56. package/dist/http-daemon.js.map +1 -0
  57. package/dist/index.d.ts +2 -0
  58. package/dist/index.js +83 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/meta-tools/ad-status.d.ts +8 -0
  61. package/dist/meta-tools/ad-status.js +41 -0
  62. package/dist/meta-tools/ad-status.js.map +1 -0
  63. package/dist/meta-tools/audit.d.ts +12 -0
  64. package/dist/meta-tools/audit.js +98 -0
  65. package/dist/meta-tools/audit.js.map +1 -0
  66. package/dist/meta-tools/call-tool.d.ts +11 -0
  67. package/dist/meta-tools/call-tool.js +65 -0
  68. package/dist/meta-tools/call-tool.js.map +1 -0
  69. package/dist/meta-tools/connect.d.ts +3 -0
  70. package/dist/meta-tools/connect.js +105 -0
  71. package/dist/meta-tools/connect.js.map +1 -0
  72. package/dist/meta-tools/disconnect.d.ts +3 -0
  73. package/dist/meta-tools/disconnect.js +30 -0
  74. package/dist/meta-tools/disconnect.js.map +1 -0
  75. package/dist/meta-tools/discover.d.ts +3 -0
  76. package/dist/meta-tools/discover.js +97 -0
  77. package/dist/meta-tools/discover.js.map +1 -0
  78. package/dist/meta-tools/groups.d.ts +7 -0
  79. package/dist/meta-tools/groups.js +237 -0
  80. package/dist/meta-tools/groups.js.map +1 -0
  81. package/dist/meta-tools/health.d.ts +4 -0
  82. package/dist/meta-tools/health.js +76 -0
  83. package/dist/meta-tools/health.js.map +1 -0
  84. package/dist/meta-tools/index.d.ts +28 -0
  85. package/dist/meta-tools/index.js +56 -0
  86. package/dist/meta-tools/index.js.map +1 -0
  87. package/dist/meta-tools/list-active.d.ts +3 -0
  88. package/dist/meta-tools/list-active.js +50 -0
  89. package/dist/meta-tools/list-active.js.map +1 -0
  90. package/dist/meta-tools/profiles.d.ts +6 -0
  91. package/dist/meta-tools/profiles.js +197 -0
  92. package/dist/meta-tools/profiles.js.map +1 -0
  93. package/dist/meta-tools/recommend.d.ts +14 -0
  94. package/dist/meta-tools/recommend.js +74 -0
  95. package/dist/meta-tools/recommend.js.map +1 -0
  96. package/dist/meta-tools/sandbox.d.ts +12 -0
  97. package/dist/meta-tools/sandbox.js +125 -0
  98. package/dist/meta-tools/sandbox.js.map +1 -0
  99. package/dist/meta-tools/server-info.d.ts +4 -0
  100. package/dist/meta-tools/server-info.js +156 -0
  101. package/dist/meta-tools/server-info.js.map +1 -0
  102. package/dist/meta-tools/usage.d.ts +6 -0
  103. package/dist/meta-tools/usage.js +149 -0
  104. package/dist/meta-tools/usage.js.map +1 -0
  105. package/dist/permissions/permission-manager.d.ts +26 -0
  106. package/dist/permissions/permission-manager.js +73 -0
  107. package/dist/permissions/permission-manager.js.map +1 -0
  108. package/dist/permissions/trust-tiers.d.ts +18 -0
  109. package/dist/permissions/trust-tiers.js +42 -0
  110. package/dist/permissions/trust-tiers.js.map +1 -0
  111. package/dist/plugins/builtin/logging-plugin.d.ts +6 -0
  112. package/dist/plugins/builtin/logging-plugin.js +41 -0
  113. package/dist/plugins/builtin/logging-plugin.js.map +1 -0
  114. package/dist/plugins/plugin-manager.d.ts +65 -0
  115. package/dist/plugins/plugin-manager.js +137 -0
  116. package/dist/plugins/plugin-manager.js.map +1 -0
  117. package/dist/proxy/prime-handlers.d.ts +27 -0
  118. package/dist/proxy/prime-handlers.js +47 -0
  119. package/dist/proxy/prime-handlers.js.map +1 -0
  120. package/dist/proxy/progress-forwarder.d.ts +44 -0
  121. package/dist/proxy/progress-forwarder.js +40 -0
  122. package/dist/proxy/progress-forwarder.js.map +1 -0
  123. package/dist/proxy/prompt-router.d.ts +25 -0
  124. package/dist/proxy/prompt-router.js +110 -0
  125. package/dist/proxy/prompt-router.js.map +1 -0
  126. package/dist/proxy/resource-router.d.ts +25 -0
  127. package/dist/proxy/resource-router.js +91 -0
  128. package/dist/proxy/resource-router.js.map +1 -0
  129. package/dist/proxy/schema-adapter.d.ts +11 -0
  130. package/dist/proxy/schema-adapter.js +36 -0
  131. package/dist/proxy/schema-adapter.js.map +1 -0
  132. package/dist/proxy/task-proxy.d.ts +28 -0
  133. package/dist/proxy/task-proxy.js +186 -0
  134. package/dist/proxy/task-proxy.js.map +1 -0
  135. package/dist/proxy/tool-router.d.ts +38 -0
  136. package/dist/proxy/tool-router.js +229 -0
  137. package/dist/proxy/tool-router.js.map +1 -0
  138. package/dist/proxy/ui-detect.d.ts +22 -0
  139. package/dist/proxy/ui-detect.js +30 -0
  140. package/dist/proxy/ui-detect.js.map +1 -0
  141. package/dist/registry/registry-client.d.ts +55 -0
  142. package/dist/registry/registry-client.js +211 -0
  143. package/dist/registry/registry-client.js.map +1 -0
  144. package/dist/registry/types.d.ts +69 -0
  145. package/dist/registry/types.js +2 -0
  146. package/dist/registry/types.js.map +1 -0
  147. package/dist/sandbox/container-runtime.d.ts +91 -0
  148. package/dist/sandbox/container-runtime.js +178 -0
  149. package/dist/sandbox/container-runtime.js.map +1 -0
  150. package/dist/sandbox/egress-proxy.d.ts +51 -0
  151. package/dist/sandbox/egress-proxy.js +146 -0
  152. package/dist/sandbox/egress-proxy.js.map +1 -0
  153. package/dist/sandbox/env-scoper.d.ts +29 -0
  154. package/dist/sandbox/env-scoper.js +60 -0
  155. package/dist/sandbox/env-scoper.js.map +1 -0
  156. package/dist/sandbox/manifest-resolver.d.ts +40 -0
  157. package/dist/sandbox/manifest-resolver.js +185 -0
  158. package/dist/sandbox/manifest-resolver.js.map +1 -0
  159. package/dist/sandbox/types.d.ts +88 -0
  160. package/dist/sandbox/types.js +21 -0
  161. package/dist/sandbox/types.js.map +1 -0
  162. package/dist/utils/errors.d.ts +39 -0
  163. package/dist/utils/errors.js +67 -0
  164. package/dist/utils/errors.js.map +1 -0
  165. package/dist/utils/logger.d.ts +16 -0
  166. package/dist/utils/logger.js +51 -0
  167. package/dist/utils/logger.js.map +1 -0
  168. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 [YOUR FULL NAME]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # @mcp-rating/gateway
2
+
3
+ **MCP Gateway** is a meta-MCP server that auto-discovers, connects, and proxies other MCP servers. Add one line to your AI desktop client config and get dynamic access to the entire MCP ecosystem.
4
+
5
+ ## How It Works
6
+
7
+ ```
8
+ ┌────────────────────┐ ┌──────────────┐ ┌──────────────────┐
9
+ │ Claude Desktop / │ stdio │ │ stdio │ MCP Server A │
10
+ │ Cursor / Windsurf │◄─────►│ MCP Gateway │◄──────►│ (e.g. filesystem)│
11
+ │ (host client) │ │ │◄──┐ └──────────────────┘
12
+ └────────────────────┘ └──────────────┘ │ ┌──────────────────┐
13
+ │ └───►│ MCP Server B │
14
+ ▼ │ (e.g. github) │
15
+ ┌──────────────┐ └──────────────────┘
16
+ │ MCP-Rating │
17
+ │ Registry API │
18
+ └──────────────┘
19
+ ```
20
+
21
+ Instead of manually configuring each MCP server in your client, the Gateway:
22
+
23
+ 1. **Discovers** servers via the MCP-Rating registry
24
+ 2. **Connects** to them on-demand (spawns as child processes)
25
+ 3. **Proxies** their tools through namespaced names (`servername__toolname`)
26
+ 4. **Notifies** your client when tools are added/removed
27
+
28
+ ## Quick Start
29
+
30
+ ### With Claude Desktop
31
+
32
+ Add to your `claude_desktop_config.json`:
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "gateway": {
38
+ "command": "npx",
39
+ "args": ["-y", "@mcp-rating/gateway"]
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ Then ask Claude:
46
+ - *"Search for MCP servers that work with databases"* (uses `mcp_discover`)
47
+ - *"Connect to the sqlite server"* (uses `mcp_connect`)
48
+ - *"Query my database"* (calls the proxied tool directly)
49
+
50
+ ### With Any MCP Client
51
+
52
+ ```json
53
+ {
54
+ "command": "npx",
55
+ "args": ["-y", "@mcp-rating/gateway"]
56
+ }
57
+ ```
58
+
59
+ ## Meta-Tools
60
+
61
+ The gateway exposes 5 built-in tools:
62
+
63
+ | Tool | Description |
64
+ |------|-------------|
65
+ | `mcp_discover` | Search the MCP-Rating registry for servers |
66
+ | `mcp_connect` | Connect to a server (by slug or explicit command) |
67
+ | `mcp_disconnect` | Disconnect a server and remove its tools |
68
+ | `mcp_list_active` | List all connected servers |
69
+ | `mcp_server_info` | Get detailed info about a server |
70
+
71
+ ## Trust Tiers
72
+
73
+ Every connected server is labeled with a trust tier based on its MCP-Rating quality score:
74
+
75
+ - **[Verified]** — High quality + officially verified
76
+ - **[Trusted]** — Good quality with repository and install command
77
+ - **[Community]** — Listed in registry with basic quality
78
+ - **[Unverified]** — Unknown origin (manually connected)
79
+
80
+ ## Configuration
81
+
82
+ The gateway reads config from `~/.mcp-gateway/config.json`:
83
+
84
+ ```json
85
+ {
86
+ "registryApiUrl": "https://mcp-rating.example.com/api/v1",
87
+ "proxyTimeoutMs": 30000,
88
+ "maxConnections": 10,
89
+ "logLevel": "info"
90
+ }
91
+ ```
92
+
93
+ ### Environment Variables
94
+
95
+ | Variable | Description | Default |
96
+ |----------|-------------|---------|
97
+ | `MCP_GATEWAY_REGISTRY_URL` | MCP-Rating API base URL | `https://mcprating.io/api/v1` |
98
+ | `MCP_GATEWAY_TIMEOUT` | Proxy timeout (ms) | `30000` |
99
+ | `MCP_GATEWAY_MAX_CONNECTIONS` | Max simultaneous connections | `10` |
100
+ | `MCP_GATEWAY_LOG_LEVEL` | Log level (debug/info/warn/error) | `info` |
101
+
102
+ ## Development
103
+
104
+ ```bash
105
+ # Install dependencies
106
+ pnpm install
107
+
108
+ # Run in development mode
109
+ pnpm dev
110
+
111
+ # Type check
112
+ pnpm typecheck
113
+
114
+ # Build
115
+ pnpm build
116
+ ```
117
+
118
+ ## Architecture
119
+
120
+ The gateway is built on the [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) and uses:
121
+
122
+ - **StdioServerTransport** — communicates with the host client
123
+ - **StdioClientTransport** — spawns and communicates with downstream servers
124
+ - **Dynamic tool registration** — `McpServer.registerTool()` + `sendToolListChanged()`
125
+ - **Tool namespacing** — `slug__toolname` pattern prevents collisions
126
+ - **Passthrough Zod schemas** — preserves parameter names for host client UI while letting downstream servers validate
127
+
128
+ ## License
129
+
130
+ ISC
@@ -0,0 +1,63 @@
1
+ export interface AdEvent {
2
+ serverSlug: string;
3
+ eventType: "connect" | "tool_usage";
4
+ toolName?: string;
5
+ sessionId: string;
6
+ timestamp: Date;
7
+ }
8
+ /**
9
+ * Tracks connect and tool-usage events for promoted servers.
10
+ * Reports events back to the MCP-Rating API via fire-and-forget HTTP POST.
11
+ */
12
+ export declare class AdTracker {
13
+ private readonly registryApiUrl;
14
+ private readonly partnerKey;
15
+ /** Unique session ID for this gateway instance */
16
+ readonly sessionId: string;
17
+ /** In-memory event log for diagnostics */
18
+ private events;
19
+ /** Count of tracked events by type */
20
+ private eventCounts;
21
+ constructor(registryApiUrl: string, partnerKey: string);
22
+ /**
23
+ * Track a server connect event.
24
+ * Records as high-value click (click_type: 'install') in the ad network.
25
+ */
26
+ trackConnect(serverSlug: string): Promise<void>;
27
+ /**
28
+ * Track a proxied tool usage event.
29
+ * Records as action (CPA event) in the ad network.
30
+ */
31
+ trackToolUsage(serverSlug: string, toolName: string): Promise<void>;
32
+ /**
33
+ * Get partner earnings from the registry API.
34
+ */
35
+ getPartnerEarnings(): Promise<{
36
+ totalGrossCents: number;
37
+ totalPartnerShareCents: number;
38
+ eventCount: number;
39
+ } | null>;
40
+ /**
41
+ * Get diagnostics info for the ad status meta-tool.
42
+ */
43
+ getStatus(): {
44
+ sessionId: string;
45
+ partnerKeyConfigured: boolean;
46
+ eventCounts: {
47
+ connect: number;
48
+ tool_usage: number;
49
+ };
50
+ totalEvents: number;
51
+ recentEvents: {
52
+ serverSlug: string;
53
+ eventType: "connect" | "tool_usage";
54
+ toolName: string | undefined;
55
+ timestamp: string;
56
+ }[];
57
+ };
58
+ /**
59
+ * Report an ad event to the MCP-Rating API.
60
+ * Fire-and-forget — errors are logged but don't propagate.
61
+ */
62
+ private reportEvent;
63
+ }
@@ -0,0 +1,144 @@
1
+ import { log } from "../utils/logger.js";
2
+ import { randomUUID } from "node:crypto";
3
+ /**
4
+ * Tracks connect and tool-usage events for promoted servers.
5
+ * Reports events back to the MCP-Rating API via fire-and-forget HTTP POST.
6
+ */
7
+ export class AdTracker {
8
+ registryApiUrl;
9
+ partnerKey;
10
+ /** Unique session ID for this gateway instance */
11
+ sessionId;
12
+ /** In-memory event log for diagnostics */
13
+ events = [];
14
+ /** Count of tracked events by type */
15
+ eventCounts = { connect: 0, tool_usage: 0 };
16
+ constructor(registryApiUrl, partnerKey) {
17
+ this.registryApiUrl = registryApiUrl;
18
+ this.partnerKey = partnerKey;
19
+ this.sessionId = randomUUID();
20
+ log.info("Ad tracker initialized", {
21
+ sessionId: this.sessionId,
22
+ registryApiUrl,
23
+ });
24
+ }
25
+ /**
26
+ * Track a server connect event.
27
+ * Records as high-value click (click_type: 'install') in the ad network.
28
+ */
29
+ async trackConnect(serverSlug) {
30
+ this.events.push({
31
+ serverSlug,
32
+ eventType: "connect",
33
+ sessionId: this.sessionId,
34
+ timestamp: new Date(),
35
+ });
36
+ this.eventCounts.connect++;
37
+ // Trim in-memory log to last 500 events
38
+ if (this.events.length > 500) {
39
+ this.events = this.events.slice(-500);
40
+ }
41
+ // Fire-and-forget report to API
42
+ this.reportEvent("install", serverSlug).catch((err) => {
43
+ log.debug("Failed to report connect event", {
44
+ serverSlug,
45
+ error: String(err),
46
+ });
47
+ });
48
+ }
49
+ /**
50
+ * Track a proxied tool usage event.
51
+ * Records as action (CPA event) in the ad network.
52
+ */
53
+ async trackToolUsage(serverSlug, toolName) {
54
+ this.events.push({
55
+ serverSlug,
56
+ eventType: "tool_usage",
57
+ toolName,
58
+ sessionId: this.sessionId,
59
+ timestamp: new Date(),
60
+ });
61
+ this.eventCounts.tool_usage++;
62
+ // Trim in-memory log
63
+ if (this.events.length > 500) {
64
+ this.events = this.events.slice(-500);
65
+ }
66
+ // Fire-and-forget report to API
67
+ this.reportEvent("action_completed", serverSlug).catch((err) => {
68
+ log.debug("Failed to report tool usage event", {
69
+ serverSlug,
70
+ toolName,
71
+ error: String(err),
72
+ });
73
+ });
74
+ }
75
+ /**
76
+ * Get partner earnings from the registry API.
77
+ */
78
+ async getPartnerEarnings() {
79
+ try {
80
+ const res = await fetch(`${this.registryApiUrl}/partners/me/revenue`, {
81
+ headers: {
82
+ "x-partner-key": this.partnerKey,
83
+ },
84
+ signal: AbortSignal.timeout(5_000),
85
+ });
86
+ if (!res.ok)
87
+ return null;
88
+ const data = (await res.json());
89
+ return {
90
+ totalGrossCents: data.totalGross,
91
+ totalPartnerShareCents: data.totalPartnerShare,
92
+ eventCount: data.count,
93
+ };
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ }
99
+ /**
100
+ * Get diagnostics info for the ad status meta-tool.
101
+ */
102
+ getStatus() {
103
+ return {
104
+ sessionId: this.sessionId,
105
+ partnerKeyConfigured: true,
106
+ eventCounts: { ...this.eventCounts },
107
+ totalEvents: this.events.length,
108
+ recentEvents: this.events.slice(-10).map((e) => ({
109
+ serverSlug: e.serverSlug,
110
+ eventType: e.eventType,
111
+ toolName: e.toolName,
112
+ timestamp: e.timestamp.toISOString(),
113
+ })),
114
+ };
115
+ }
116
+ /**
117
+ * Report an ad event to the MCP-Rating API.
118
+ * Fire-and-forget — errors are logged but don't propagate.
119
+ */
120
+ async reportEvent(clickType, serverSlug) {
121
+ const url = `${this.registryApiUrl}/partners/report-click`;
122
+ const res = await fetch(url, {
123
+ method: "POST",
124
+ headers: {
125
+ "Content-Type": "application/json",
126
+ "x-partner-key": this.partnerKey,
127
+ },
128
+ body: JSON.stringify({
129
+ serverSlug,
130
+ clickType,
131
+ sessionId: this.sessionId,
132
+ }),
133
+ signal: AbortSignal.timeout(5_000),
134
+ });
135
+ if (!res.ok) {
136
+ log.debug("Ad event report failed", {
137
+ status: res.status,
138
+ clickType,
139
+ serverSlug,
140
+ });
141
+ }
142
+ }
143
+ }
144
+ //# sourceMappingURL=ad-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ad-tracker.js","sourceRoot":"","sources":["../../src/ads/ad-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ export interface ToolCallEvent {
2
+ slug: string;
3
+ toolName: string;
4
+ startedAt: number;
5
+ durationMs: number;
6
+ success: boolean;
7
+ error?: string;
8
+ }
9
+ export interface ToolAggregates {
10
+ key: string;
11
+ callCount: number;
12
+ errorCount: number;
13
+ totalDurationMs: number;
14
+ avgLatencyMs: number;
15
+ p95LatencyMs: number;
16
+ lastCalledAt: number;
17
+ /** Recent latencies for p95 calculation (last 100) */
18
+ latencies: number[];
19
+ }
20
+ export interface ServerAggregates {
21
+ slug: string;
22
+ totalCalls: number;
23
+ totalErrors: number;
24
+ avgLatencyMs: number;
25
+ }
26
+ export interface UsageStats {
27
+ totalCalls: number;
28
+ totalErrors: number;
29
+ avgLatencyMs: number;
30
+ topToolsByCalls: ToolAggregates[];
31
+ slowestTools: ToolAggregates[];
32
+ perServer: ServerAggregates[];
33
+ recentCalls: ToolCallEvent[];
34
+ }
35
+ /**
36
+ * In-memory usage analytics tracker.
37
+ * Uses a ring buffer for events and maintains per-tool aggregates.
38
+ */
39
+ export declare class UsageTracker {
40
+ private events;
41
+ private maxEvents;
42
+ private insertIdx;
43
+ private totalInserted;
44
+ /** Per-tool aggregates keyed by "slug::toolName" */
45
+ private toolAggregates;
46
+ constructor(bufferSize?: number);
47
+ /**
48
+ * Record a completed tool call event.
49
+ */
50
+ recordCall(event: ToolCallEvent): void;
51
+ /**
52
+ * Get overall usage statistics.
53
+ */
54
+ getStats(slug?: string): UsageStats;
55
+ /**
56
+ * Get the most recent tool call events.
57
+ */
58
+ getRecentCalls(limit?: number): ToolCallEvent[];
59
+ /**
60
+ * Get tool calls that exceeded a latency threshold.
61
+ */
62
+ getSlowCalls(thresholdMs?: number): ToolCallEvent[];
63
+ /**
64
+ * Reset all analytics data.
65
+ */
66
+ reset(): void;
67
+ }
@@ -0,0 +1,148 @@
1
+ import { log } from "../utils/logger.js";
2
+ // ── Usage Tracker ────────────────────────────────────────────────────────────
3
+ const DEFAULT_BUFFER_SIZE = 10_000;
4
+ const LATENCY_WINDOW = 100; // Keep last 100 latencies for p95 calculation
5
+ /**
6
+ * In-memory usage analytics tracker.
7
+ * Uses a ring buffer for events and maintains per-tool aggregates.
8
+ */
9
+ export class UsageTracker {
10
+ events = [];
11
+ maxEvents;
12
+ insertIdx = 0;
13
+ totalInserted = 0;
14
+ /** Per-tool aggregates keyed by "slug::toolName" */
15
+ toolAggregates = new Map();
16
+ constructor(bufferSize = DEFAULT_BUFFER_SIZE) {
17
+ this.maxEvents = bufferSize;
18
+ }
19
+ /**
20
+ * Record a completed tool call event.
21
+ */
22
+ recordCall(event) {
23
+ // Ring buffer insert
24
+ if (this.totalInserted < this.maxEvents) {
25
+ this.events.push(event);
26
+ }
27
+ else {
28
+ this.events[this.insertIdx] = event;
29
+ }
30
+ this.insertIdx = (this.insertIdx + 1) % this.maxEvents;
31
+ this.totalInserted++;
32
+ // Update aggregates
33
+ const key = `${event.slug}::${event.toolName}`;
34
+ let agg = this.toolAggregates.get(key);
35
+ if (!agg) {
36
+ agg = {
37
+ key,
38
+ callCount: 0,
39
+ errorCount: 0,
40
+ totalDurationMs: 0,
41
+ avgLatencyMs: 0,
42
+ p95LatencyMs: 0,
43
+ lastCalledAt: 0,
44
+ latencies: [],
45
+ };
46
+ this.toolAggregates.set(key, agg);
47
+ }
48
+ agg.callCount++;
49
+ if (!event.success)
50
+ agg.errorCount++;
51
+ agg.totalDurationMs += event.durationMs;
52
+ agg.avgLatencyMs = agg.totalDurationMs / agg.callCount;
53
+ agg.lastCalledAt = event.startedAt;
54
+ // Track latencies for p95 (rolling window)
55
+ agg.latencies.push(event.durationMs);
56
+ if (agg.latencies.length > LATENCY_WINDOW) {
57
+ agg.latencies.shift();
58
+ }
59
+ agg.p95LatencyMs = percentile(agg.latencies, 95);
60
+ }
61
+ /**
62
+ * Get overall usage statistics.
63
+ */
64
+ getStats(slug) {
65
+ const allAggregates = [...this.toolAggregates.values()];
66
+ const filtered = slug
67
+ ? allAggregates.filter((a) => a.key.startsWith(`${slug}::`))
68
+ : allAggregates;
69
+ const totalCalls = filtered.reduce((s, a) => s + a.callCount, 0);
70
+ const totalErrors = filtered.reduce((s, a) => s + a.errorCount, 0);
71
+ const totalDuration = filtered.reduce((s, a) => s + a.totalDurationMs, 0);
72
+ const avgLatencyMs = totalCalls > 0 ? totalDuration / totalCalls : 0;
73
+ // Top tools by call count
74
+ const topToolsByCalls = [...filtered]
75
+ .sort((a, b) => b.callCount - a.callCount)
76
+ .slice(0, 10);
77
+ // Slowest tools by avg latency (min 5 calls to be relevant)
78
+ const slowestTools = [...filtered]
79
+ .filter((a) => a.callCount >= 5)
80
+ .sort((a, b) => b.avgLatencyMs - a.avgLatencyMs)
81
+ .slice(0, 10);
82
+ // Per-server aggregates
83
+ const serverMap = new Map();
84
+ for (const agg of filtered) {
85
+ const aggSlug = agg.key.split("::")[0];
86
+ const server = serverMap.get(aggSlug) || { totalCalls: 0, totalErrors: 0, totalDuration: 0 };
87
+ server.totalCalls += agg.callCount;
88
+ server.totalErrors += agg.errorCount;
89
+ server.totalDuration += agg.totalDurationMs;
90
+ serverMap.set(aggSlug, server);
91
+ }
92
+ const perServer = [...serverMap.entries()].map(([s, v]) => ({
93
+ slug: s,
94
+ totalCalls: v.totalCalls,
95
+ totalErrors: v.totalErrors,
96
+ avgLatencyMs: v.totalCalls > 0 ? v.totalDuration / v.totalCalls : 0,
97
+ }));
98
+ return {
99
+ totalCalls,
100
+ totalErrors,
101
+ avgLatencyMs,
102
+ topToolsByCalls,
103
+ slowestTools,
104
+ perServer,
105
+ recentCalls: this.getRecentCalls(20),
106
+ };
107
+ }
108
+ /**
109
+ * Get the most recent tool call events.
110
+ */
111
+ getRecentCalls(limit = 20) {
112
+ const len = Math.min(this.events.length, limit);
113
+ const recent = [];
114
+ // Read backwards from the insertion point
115
+ for (let i = 0; i < len; i++) {
116
+ const idx = (this.insertIdx - 1 - i + this.events.length) % this.events.length;
117
+ if (idx >= 0 && idx < this.events.length) {
118
+ recent.push(this.events[idx]);
119
+ }
120
+ }
121
+ return recent;
122
+ }
123
+ /**
124
+ * Get tool calls that exceeded a latency threshold.
125
+ */
126
+ getSlowCalls(thresholdMs = 5000) {
127
+ return this.events.filter((e) => e.durationMs >= thresholdMs);
128
+ }
129
+ /**
130
+ * Reset all analytics data.
131
+ */
132
+ reset() {
133
+ this.events = [];
134
+ this.insertIdx = 0;
135
+ this.totalInserted = 0;
136
+ this.toolAggregates.clear();
137
+ log.info("Usage analytics reset");
138
+ }
139
+ }
140
+ // ── Helpers ──────────────────────────────────────────────────────────────────
141
+ function percentile(values, p) {
142
+ if (values.length === 0)
143
+ return 0;
144
+ const sorted = [...values].sort((a, b) => a - b);
145
+ const idx = Math.ceil((p / 100) * sorted.length) - 1;
146
+ return sorted[Math.max(0, idx)];
147
+ }
148
+ //# sourceMappingURL=usage-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-tracker.js","sourceRoot":"","sources":["../../src/analytics/usage-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Safety audit trail — a forensics record of what sandboxed MCP servers
3
+ * actually did, and what the sandbox blocked.
4
+ *
5
+ * This is deliberately NOT generic observability (tool-call telemetry exists
6
+ * in UsageTracker). It's a *security* artifact: the evidence that containment
7
+ * worked. A security team reviewing "did this untrusted server try anything?"
8
+ * reads this log — it records sandbox-relevant events (calls under an
9
+ * enforcement level, blocked egress, blocked tools, connects with their
10
+ * granted capability envelope), not performance metrics.
11
+ *
12
+ * Storage: an in-memory ring buffer (always) plus optional append-only JSONL
13
+ * file (for durable forensics / SIEM ingestion).
14
+ */
15
+ export type AuditEventType = "connect" | "tool_call" | "tool_blocked" | "egress_blocked" | "egress_allowed" | "disconnect";
16
+ export interface AuditEvent {
17
+ /** ISO timestamp. */
18
+ ts: string;
19
+ type: AuditEventType;
20
+ /** Downstream server slug the event concerns. */
21
+ slug: string;
22
+ /** Sandbox enforcement level in effect (none | l1-process | l2-container | l3-wasm). */
23
+ enforcement?: string;
24
+ /** Tool name, for tool_* events. */
25
+ tool?: string;
26
+ /** Target host:port, for egress_* events. */
27
+ target?: string;
28
+ /** Whether the action succeeded (tool_call) — false on downstream error. */
29
+ ok?: boolean;
30
+ /** Short reason (block cause, error class). Never contains args/secrets. */
31
+ reason?: string;
32
+ /** Session id (multi-tenant daemon), if available. */
33
+ sessionId?: string;
34
+ }
35
+ export interface AuditLogOptions {
36
+ /** Max events kept in memory (ring buffer). Default 5000. */
37
+ bufferSize?: number;
38
+ /** Optional JSONL file path for durable, append-only forensics. */
39
+ filePath?: string;
40
+ }
41
+ /**
42
+ * Append-only safety audit log. Recording never throws — a forensics logger
43
+ * must not break the thing it observes.
44
+ */
45
+ export declare class AuditLog {
46
+ private readonly buffer;
47
+ private readonly bufferSize;
48
+ private readonly filePath?;
49
+ private counts;
50
+ constructor(opts?: AuditLogOptions);
51
+ /** Record an event. Caller supplies everything except the timestamp. */
52
+ record(event: Omit<AuditEvent, "ts">): void;
53
+ /**
54
+ * Query recent events, newest first. Filterable by slug, type, and a
55
+ * "security-relevant only" flag (blocks + errors — the events a reviewer
56
+ * actually cares about).
57
+ */
58
+ query(opts?: {
59
+ slug?: string;
60
+ type?: AuditEventType;
61
+ securityRelevantOnly?: boolean;
62
+ limit?: number;
63
+ }): AuditEvent[];
64
+ /** Aggregate counts by event type (for the summary view). */
65
+ summary(): {
66
+ counts: Record<AuditEventType, number>;
67
+ total: number;
68
+ /** Count of security-relevant events (blocks + errors). */
69
+ securityEvents: number;
70
+ };
71
+ }