List AppDynamics applications
appd_list_applicationsRetrieve business applications visible to the API client, with an optional filter for apps active within the last N minutes (SaaS only).
Instructions
List business applications visible to the configured API Client. Optionally filter to apps that have been "alive" in the last N minutes (SaaS only).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| aliveWithinMinutes | No | SaaS-only: filter to applications that have been alive within the last N minutes (uses time-range-type=BEFORE_NOW). Omit to list all. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| summary | Yes | ||
| evidence | No | ||
| entities | Yes | ||
| timeRange | No | ||
| sourceEndpoints | Yes | ||
| pagination | No | ||
| warnings | Yes | ||
| truncated | Yes |
Implementation Reference
- src/tools/listApplications.ts:36-97 (handler)Main tool handler for 'appd_list_applications'. Registers the tool with MCP server, calls GET /controller/rest/applications, populates appNameToId cache, and returns a response envelope with application entities.
export const listApplicationsTool: ToolRegistration = { name: 'appd_list_applications', profile: 'read', register(server, services) { server.registerTool( 'appd_list_applications', { title: 'List AppDynamics applications', description: 'List business applications visible to the configured API Client. Optionally filter to apps that have been "alive" in the last N minutes (SaaS only).', inputSchema: inputShape, outputSchema: envelopeOutputShape, }, wrapHandler<{ aliveWithinMinutes?: number | undefined }, AppListEvidence>( services.log, 'appd_list_applications', async (input) => { const query: Record<string, string | number> = {}; if (input.aliveWithinMinutes !== undefined) { query['time-range-type'] = 'BEFORE_NOW'; query['duration-in-mins'] = input.aliveWithinMinutes; } const res = await services.controller.get<AppDApp[]>('applications', query); const apps = Array.isArray(res.body) ? res.body : []; for (const app of apps) { if (typeof app.name === 'string' && typeof app.id === 'number') { services.caches.appNameToId.set(app.name, app.id); } } const entities: EnvelopeEntity[] = apps .filter((a): a is AppDApp & { id: number } => typeof a.id === 'number') .map((a) => ({ kind: 'application', id: a.id, ...(a.name !== undefined ? { name: a.name } : {}), })); const evidence: AppListEvidence = { count: apps.length, applications: apps.map((a) => ({ id: a.id, name: a.name, description: a.description, accountGuid: a.accountGuid, })), }; return toToolResult( buildEnvelope({ summary: `Found ${apps.length} application${apps.length === 1 ? '' : 's'}.`, evidence, entities, sourceEndpoints: ['GET /controller/rest/applications'], }), ); }, ), ); }, }; - src/tools/listApplications.ts:8-17 (schema)Input schema: optional 'aliveWithinMinutes' integer to filter SaaS applications alive within N minutes.
const inputShape = { aliveWithinMinutes: z .number() .int() .positive() .optional() .describe( 'SaaS-only: filter to applications that have been alive within the last N minutes (uses time-range-type=BEFORE_NOW). Omit to list all.', ), }; - src/tools/index.ts:13-13 (registration)Imports listApplicationsTool and includes it in the ALL_TOOLS array at line 19.
import { listApplicationsTool } from './listApplications.js'; - src/tools/registry.ts:9-19 (registration)ToolRegistration interface that defines the shape of tool registrations, including name 'appd_list_applications'.
export interface ToolRegistration { /** Public tool name, e.g. "appd_list_applications" */ name: string; /** Stable profile, used for future allowlists in Phase 2/3 */ profile: 'read' | 'sensitive-read' | 'change'; /** * Function that calls McpServer#registerTool with name, config, and handler. * Implementations must use registerTool (not the deprecated tool() overloads). */ register: (server: McpServer, services: Services) => void; } - src/tools/_common.ts:28-60 (helper)wrapHandler utility that wraps the tool handler with error handling for HttpErrors and unexpected exceptions.
export function wrapHandler<I, R>( log: Logger, toolName: string, handler: (input: I) => Promise<DualToolResult<R>>, ): (input: I) => Promise<DualToolResult<R> | (DualToolResult<R> & { isError: true })> { return async (input) => { try { return await handler(input); } catch (err) { if (err instanceof HttpError) { log.warn( { tool: toolName, kind: err.kind, statusCode: err.statusCode, sourceEndpoint: err.sourceEndpoint, }, 'tool: HttpError', ); return toErrorResult({ summary: `${toolName} failed: ${err.kind}${err.statusCode ? ` (HTTP ${err.statusCode})` : ''}. ${err.hint ?? ''}`.trim(), evidence: { kind: err.kind, message: err.message, hint: err.hint } as unknown as R, sourceEndpoints: [err.sourceEndpoint], }); } log.error({ tool: toolName, err }, 'tool: unexpected error'); const message = err instanceof Error ? err.message : String(err); return toErrorResult({ summary: `${toolName} failed: unexpected error: ${message}`, evidence: { kind: 'internal', message } as unknown as R, }); }