test_runs_getRecentTestRuns
Retrieve recent test run details from LoadRunner Cloud to monitor performance testing results and analyze trends over the past month.
Instructions
Get recent test runs details for the last month from LoadRunner Cloud. Optionally filter by projectIds.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectIds | No | Optional project IDs to filter the usage. |
Implementation Reference
- The core handler function `executeFunction` that makes an authenticated GET request to the LoadRunner Cloud `/license/usage` endpoint for recent test runs data over the last 30 days, optionally filtered by project IDs.const executeFunction = async ({ projectIds = '' } = {}) => { const baseUrl = process.env.LRC_BASE_URL; const tenantId = process.env.LRC_TENANT_ID; const token = await getAuthToken(); // Calculate startTime and endTime for the last 1 month const endTime = Date.now(); const startTime = endTime - 30 * 24 * 60 * 60 * 1000; // 30 days in ms try { // Construct the URL with query parameters const url = new URL(`${baseUrl}/license/usage`); url.searchParams.append('TENANTID', tenantId); if (projectIds) url.searchParams.append('projectIds', projectIds); url.searchParams.append('startTime', startTime); url.searchParams.append('endTime', endTime); // Set up headers for the request const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }; // Perform the fetch request const response = await fetch(url.toString(), { method: 'GET', headers }); // Check if the response was successful if (!response.ok) { const text = await response.text(); try { const errorData = JSON.parse(text); throw new Error(JSON.stringify(errorData)); } catch (jsonErr) { // Not JSON, log the raw text console.error('Non-JSON error response:', text); throw new Error(text); } } // Parse and return the response data const text = await response.text(); try { const data = JSON.parse(text); return data; } catch (jsonErr) { // Not JSON, log the raw text console.error('Non-JSON success response:', text); return { error: 'Received non-JSON response from API', raw: text }; } } catch (error) { console.error('Error retrieving license usage:', error); return { error: 'An error occurred while retrieving license usage.' }; } };
- The input schema definition for the tool, including the tool name, description, and parameters (optional `projectIds` string).type: 'function', function: { name: 'test_runs_getRecentTestRuns', description: 'Get recent test runs details for the last month from LoadRunner Cloud. Optionally filter by projectIds.', parameters: { type: 'object', properties: { projectIds: { type: 'string', description: 'Optional project IDs to filter the usage.' } }, required: [] } } }
- The `apiTool` object that packages the handler function and schema definition for dynamic registration in the MCP server.const apiTool = { function: executeFunction, definition: { type: 'function', function: { name: 'test_runs_getRecentTestRuns', description: 'Get recent test runs details for the last month from LoadRunner Cloud. Optionally filter by projectIds.', parameters: { type: 'object', properties: { projectIds: { type: 'string', description: 'Optional project IDs to filter the usage.' } }, required: [] } } } }; export { apiTool };
- tools/paths.js:1-11 (registration)The `toolPaths` array that lists the path to this tool's file, enabling its discovery and import.export const toolPaths = [ 'loadrunner-cloud/load-runner-cloud-api/projects-get-projects.js', 'loadrunner-cloud/load-runner-cloud-api/test-runs-get-active-test-runs.js', 'loadrunner-cloud/load-runner-cloud-api/test-runs-get-test-run-transactions.js', 'loadrunner-cloud/load-runner-cloud-api/test-runs-get-test-run-summary.js', 'loadrunner-cloud/load-runner-cloud-api/test-runs-get-http-responses.js', 'loadrunner-cloud/load-runner-cloud-api/test-runs-get-test-run-recent.js', 'loadrunner-cloud/load-runner-cloud-api/projects-get-load-tests.js', 'loadrunner-cloud/load-runner-cloud-api/projects-get-load-test-scripts.js', 'loadrunner-cloud/load-runner-cloud-api/projects-get-load-test-runs.js' ];
- lib/tools.js:7-16 (registration)The `discoverTools` function that dynamically loads all `apiTool` objects from files listed in `toolPaths`, including this tool.export async function discoverTools() { const toolPromises = toolPaths.map(async (file) => { const module = await import(`../tools/${file}`); return { ...module.apiTool, path: file, }; }); return Promise.all(toolPromises); }
- mcpServer.js:40-160 (registration)The `setupServerHandlers` function in the MCP server that registers the list tools and call tool handlers, dynamically handling calls to `test_runs_getRecentTestRuns` by matching name and invoking its `function`.async function setupServerHandlers(server, tools) { server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: await transformTools(tools), })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const toolName = request.params.name; const tool = tools.find((t) => t.definition.function.name === toolName); if (!tool) { throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${toolName}`); } const args = request.params.arguments; const requiredParameters = tool.definition?.function?.parameters?.required || []; for (const requiredParameter of requiredParameters) { if (!(requiredParameter in args)) { throw new McpError( ErrorCode.InvalidParams, `Missing required parameter: ${requiredParameter}` ); } } try { const result = await tool.function(args); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { console.error("[Error] Failed to fetch data:", error); throw new McpError( ErrorCode.InternalError, `API error: ${error.message}` ); } }); } async function run() { const args = process.argv.slice(2); const isSSE = args.includes("--sse"); const tools = await discoverTools(); if (isSSE) { const app = express(); const transports = {}; const servers = {}; app.get("/sse", async (_req, res) => { // Create a new Server instance for each session const server = new Server( { name: SERVER_NAME, version: "0.1.0", }, { capabilities: { tools: {}, }, } ); server.onerror = (error) => console.error("[Error]", error); await setupServerHandlers(server, tools); const transport = new SSEServerTransport("/messages", res); transports[transport.sessionId] = transport; servers[transport.sessionId] = server; res.on("close", async () => { delete transports[transport.sessionId]; await server.close(); delete servers[transport.sessionId]; }); await server.connect(transport); }); app.post("/messages", async (req, res) => { const sessionId = req.query.sessionId; const transport = transports[sessionId]; const server = servers[sessionId]; if (transport && server) { await transport.handlePostMessage(req, res); } else { res.status(400).send("No transport/server found for sessionId"); } }); const port = process.env.PORT || 3001; app.listen(port, () => { console.log(`[SSE Server] running on port ${port}`); }); } else { // stdio mode: single server instance const server = new Server( { name: SERVER_NAME, version: "0.1.0", }, { capabilities: { tools: {}, }, } ); server.onerror = (error) => console.error("[Error]", error); await setupServerHandlers(server, tools); process.on("SIGINT", async () => { await server.close(); process.exit(0); }); const transport = new StdioServerTransport(); await server.connect(transport); }