Skip to content

Commit ae1a149

Browse files
authored
Merge pull request #113 from tech-sushant/rate-limit
feat: implement rate-limiting for 'started' event
2 parents 47c6cda + 620d0ed commit ae1a149

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ process.on("exit", () => {
5050

5151
export { setLogger } from "./logger.js";
5252
export { BrowserStackMcpServer } from "./server-factory.js";
53+
export { trackMCP } from "./lib/instrumentation.js";

src/lib/device-cache.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import fs from "fs";
22
import os from "os";
33
import path from "path";
44
import { apiClient } from "./apiClient.js";
5+
import config from "../config.js";
56

67
const CACHE_DIR = path.join(os.homedir(), ".browserstack", "combined_cache");
78
const CACHE_FILE = path.join(CACHE_DIR, "data.json");
89
const TTL_MS = 24 * 60 * 60 * 1000; // 1 day
10+
const TTL_STARTED_MS = 3 * 60 * 60 * 1000; // 3 Hours
911

1012
export enum BrowserStackProducts {
1113
LIVE = "live",
@@ -64,3 +66,29 @@ export async function getDevicesAndBrowsers(
6466

6567
return cache[type];
6668
}
69+
70+
// Rate limiter for started event (3H)
71+
export function shouldSendStartedEvent(): boolean {
72+
try {
73+
if (config && config.REMOTE_MCP) {
74+
return false;
75+
}
76+
if (!fs.existsSync(CACHE_DIR)) {
77+
fs.mkdirSync(CACHE_DIR, { recursive: true });
78+
}
79+
let cache: Record<string, any> = {};
80+
if (fs.existsSync(CACHE_FILE)) {
81+
const raw = fs.readFileSync(CACHE_FILE, "utf8");
82+
cache = JSON.parse(raw || "{}");
83+
const last = parseInt(cache.lastStartedEvent, 10);
84+
if (!isNaN(last) && Date.now() - last < TTL_STARTED_MS) {
85+
return false;
86+
}
87+
}
88+
cache.lastStartedEvent = Date.now();
89+
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf8");
90+
return true;
91+
} catch {
92+
return true;
93+
}
94+
}

src/oninitialized.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { trackMCP } from "./lib/instrumentation.js";
22
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3+
import { shouldSendStartedEvent } from "./lib/device-cache.js";
34

45
export function setupOnInitialized(server: McpServer, config?: any) {
56
const nodeVersion = process.versions.node;
@@ -12,6 +13,8 @@ export function setupOnInitialized(server: McpServer, config?: any) {
1213
}
1314

1415
server.server.oninitialized = () => {
15-
trackMCP("started", server.server.getClientVersion()!, undefined, config);
16+
if (shouldSendStartedEvent()) {
17+
trackMCP("started", server.server.getClientVersion()!, undefined, config);
18+
}
1619
};
1720
}

0 commit comments

Comments
 (0)