Skip to main content
Glama

mcp-server-cloudflare

Official
by cloudflare
analytics-engine.ts4.37 kB
export type MetricsBindings = { MCP_METRICS: AnalyticsEngineDataset } /** * Generic metrics event utilities * @description Wrapper for RA binding */ export class MetricsTracker { constructor( private wae: AnalyticsEngineDataset, private mcpServerInfo: { name: string version: string } ) {} logEvent(event: MetricsEvent): void { try { event.serverInfo = this.mcpServerInfo let dataPoint = event.toDataPoint() this.wae.writeDataPoint(dataPoint) } catch (e) { console.error(`Failed to log metrics event, ${e}`) } } } /** * MetricsEvent * * Each event type is stored with a different indexId and has an associated class which * maps a more ergonomic event object to a ReadyAnalyticsEvent */ export abstract class MetricsEvent { public _serverInfo: { name: string; version: string } | undefined set serverInfo(serverInfo: { name: string; version: string }) { this._serverInfo = serverInfo } get serverInfo(): { name: string; version: string } { if (!this._serverInfo) { throw new Error('Server info not set') } return this._serverInfo } /** * Output a valid AnalyticsEngineDataPoint. Use `mapBlobs` and `mapDoubles` to write well defined * analytics engine datapoints. The first and second blob entries are reserved for the MCP server name and * MCP server version. */ abstract toDataPoint(): AnalyticsEngineDataPoint mapBlobs(blobs: Blobs): Array<string | null> { if (blobs.blob1 || blobs.blob2) { throw new MetricsError( 'Failed to map blobs, blob1 and blob2 are reserved for MCP server info' ) } // add placeholder blobs, filled in by the MetricsTracker later blobs.blob1 = this.serverInfo.name blobs.blob2 = this.serverInfo.version const blobsArray = new Array(Object.keys(blobs).length) for (const [key, value] of Object.entries(blobs)) { const match = key.match(/^blob(\d+)$/) if (match === null || match.length < 2) { // we should never hit this because of the typedefinitions above, // but this error is for safety throw new MetricsError('Failed to map blobs, invalid key') } const index = parseInt(match[1], 10) if (isNaN(index)) { // we should never hit this because of the typedefinitions above, // but this esrror is for safety throw new MetricsError('Failed to map blobs, invalid index') } if (index - 1 >= blobsArray.length) { throw new MetricsError('Failed to map blobs, missing blob') } blobsArray[index - 1] = value } return blobsArray } mapDoubles(doubles: Doubles): number[] { const doublesArray = new Array(Object.keys(doubles).length) for (const [key, value] of Object.entries(doubles)) { const match = key.match(/^double(\d+)$/) if (match === null || match.length < 2) { // we should never hit this because of the typedefinitions above, // but this error is for safety throw new MetricsError(': Failed to map doubles, invalid key') } const index = parseInt(match[1], 10) if (isNaN(index)) { // we should never hit this because of the typedefinitions above, // but this error is for safety throw new MetricsError('Failed to map doubles, invalid index') } if (index - 1 >= doublesArray.length) { throw new MetricsError('Failed to map doubles, missing blob') } doublesArray[index - 1] = value } return doublesArray } } export enum MetricsEventIndexIds { AUTH_USER = 'auth_user', SESSION_START = 'session_start', TOOL_CALL = 'tool_call', CONTAINER_MANAGER = 'container_manager', } /** * Utility functions to map named blob/double objects to an array * We do this so we don't have to annotate `blob1`, `blob2`, etc in comments. * * I prefer this to just writing it in an array because it'll be easier to reference * later when we are writing ready analytics queries. * * IMO named tuples and raw arrays aren't as ergonomic to work with, but they require less of this code below */ type Range1To20 = | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 // blob1 and blob2 are reserved for server name and version type Blobs = { [key in `blob${Range1To20}`]?: string | null } type Doubles = { [key in `double${Range1To20}`]?: number } export class MetricsError extends Error { constructor(message: string) { super(message) this.name = 'MetricsError' } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cloudflare/mcp-server-cloudflare'

If you have feedback or need assistance with the MCP directory API, please join our Discord server