@postman/postman-mcp-server
Version:
Postman MCP Server — connect AI agents (Claude Code, Cursor, VS Code Copilot, Gemini CLI) to your Postman collections, specifications, and environments via Model Context Protocol (MCP)
137 lines (136 loc) • 5.1 kB
JavaScript
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';
import { randomUUID, createHash } from 'node:crypto';
import { z } from 'zod';
import { PluginSourceSchema, PluginVersionSchema } from './types.js';
const PluginSourceHeaderSchema = z.string().max(96).trim().pipe(PluginSourceSchema);
const PluginVersionHeaderSchema = z.string().max(64).trim().pipe(PluginVersionSchema);
const TRACE_GAP_MS = 30_000;
export class TelemetrySession {
installId;
mcpSessionId;
sessionId;
region;
transport;
toolset;
serverVersion;
clientName;
clientVersion;
pluginSource;
pluginVersion;
protocolVersion;
clientCapabilities;
toolsetSnapshotId;
toolListCount;
traceId;
lastToolCallTime = 0;
constructor(options) {
this.installId = options.installId;
this.mcpSessionId = options.mcpSessionId;
this.sessionId = options.sessionId ?? randomUUID();
this.region = options.region;
this.transport = options.transport;
this.toolset = options.toolset;
this.serverVersion = options.serverVersion;
this.clientName = options.clientName ?? '';
this.clientVersion = options.clientVersion ?? '';
this.pluginSource = '';
this.pluginVersion = '';
this.setPluginInfo(options.pluginSource, options.pluginVersion);
this.protocolVersion = options.protocolVersion ?? '';
this.clientCapabilities = options.clientCapabilities ?? [];
this.toolsetSnapshotId = options.toolsetSnapshotId ?? '';
this.toolListCount = options.toolListCount ?? 0;
}
getTraceId(conversationId) {
if (conversationId) {
return conversationId;
}
const now = Date.now();
if (!this.traceId || now - this.lastToolCallTime > TRACE_GAP_MS) {
this.traceId = randomUUID();
}
this.lastToolCallTime = now;
return this.traceId;
}
setClientInfo(clientInfo, protocolVersion) {
this.clientName = clientInfo.name;
this.clientVersion = clientInfo.version;
this.protocolVersion = protocolVersion;
}
setPluginInfo(source, version) {
const parsedSource = PluginSourceHeaderSchema.safeParse(source);
const parsedVersion = PluginVersionHeaderSchema.safeParse(version);
this.pluginSource = parsedSource.success ? parsedSource.data : '';
this.pluginVersion = parsedSource.success && parsedVersion.success ? parsedVersion.data : '';
}
setClientCapabilities(capabilities) {
this.clientCapabilities = Object.keys(capabilities ?? {});
}
setToolNames(toolNames) {
this.toolListCount = toolNames.length;
const sorted = [...toolNames].sort();
const hash = createHash('sha256').update(sorted.join(',')).digest('hex');
this.toolsetSnapshotId = hash.substring(0, 12);
}
getToolListCount() {
return this.toolListCount;
}
serialize() {
return {
installId: this.installId,
mcpSessionId: this.mcpSessionId,
sessionId: this.sessionId,
region: this.region,
transport: this.transport,
toolset: this.toolset,
serverVersion: this.serverVersion,
clientName: this.clientName,
clientVersion: this.clientVersion,
pluginSource: this.pluginSource,
pluginVersion: this.pluginVersion,
protocolVersion: this.protocolVersion,
clientCapabilities: this.clientCapabilities,
toolsetSnapshotId: this.toolsetSnapshotId,
toolListCount: this.toolListCount,
};
}
static fromSerialized(snapshot) {
return new TelemetrySession({
installId: snapshot.installId,
mcpSessionId: snapshot.mcpSessionId,
sessionId: snapshot.sessionId,
region: snapshot.region,
transport: snapshot.transport,
toolset: snapshot.toolset,
serverVersion: snapshot.serverVersion,
clientName: snapshot.clientName,
clientVersion: snapshot.clientVersion,
pluginSource: snapshot.pluginSource,
pluginVersion: snapshot.pluginVersion,
protocolVersion: snapshot.protocolVersion,
clientCapabilities: snapshot.clientCapabilities ?? [],
toolsetSnapshotId: snapshot.toolsetSnapshotId,
toolListCount: snapshot.toolListCount,
});
}
static loadOrCreateInstallIdFromDisk() {
const dir = join(homedir(), '.postman');
const filePath = join(dir, 'mcp-telemetry-id');
try {
const existing = readFileSync(filePath, 'utf-8');
return existing.trim();
}
catch {
}
const newId = randomUUID();
try {
mkdirSync(dir, { recursive: true });
writeFileSync(filePath, newId, 'utf-8');
}
catch {
}
return newId;
}
}