Get AppDynamics service dependency map
appd_get_dependency_mapConstruct a tier-to-tier dependency map using application model and transaction snapshots, with warnings for sparse data.
Instructions
Synthesize a tier→tier/backend dependency map from the application model + transaction snapshots (with exit calls). MCP-level aggregation — confidence depends on snapshot density (warning surfaces when sparse).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| application | Yes | ||
| timeRange | No | AppD time range. Defaults to BEFORE_NOW with durationMinutes=30 if omitted by the caller. |
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/getDependencyMap.ts:76-209 (handler)The entire ToolRegistration object for appd_get_dependency_map. The register() method (line 79-208) calls server.registerTool with the name, schema, and handler. The handler (lines 92-205) is the core logic: it fetches tiers, backends, and transaction snapshots from the AppDynamics controller, synthesizes a dependency map (nodes + edges), and returns it wrapped in an envelope.
export const getDependencyMapTool: ToolRegistration = { name: 'appd_get_dependency_map', profile: 'read', register(server, services) { server.registerTool( 'appd_get_dependency_map', { title: 'Get AppDynamics service dependency map', description: 'Synthesize a tier→tier/backend dependency map from the application model + transaction snapshots (with exit calls). MCP-level aggregation — confidence depends on snapshot density (warning surfaces when sparse).', inputSchema: inputShape, outputSchema: envelopeOutputShape, }, wrapHandler<{ application: AppRef; timeRange?: TimeRange | undefined }, DependencyMapEvidence>( services.log, 'appd_get_dependency_map', async (input) => { const tr = input.timeRange ?? DEFAULT_TIME_RANGE; const appPath = appRefToPath(input.application); const sourceEndpoints: string[] = []; const limit = pLimit(3); const [tiersRes, backendsRes, snapshotsRes] = await Promise.all([ limit(() => services.controller.get<Tier[]>(`applications/${appPath}/tiers`)), limit(() => services.controller.get<Backend[]>(`applications/${appPath}/backends`)), limit(() => { const params = applyTimeRangeToParams(tr); params.append('need-exit-calls', 'true'); params.append('maximum-results', String(SNAPSHOT_FETCH)); return services.controller.get<Snapshot[]>( `applications/${appPath}/request-snapshots`, Object.fromEntries(params), ); }), ]); sourceEndpoints.push( `GET /controller/rest/applications/${appPath}/tiers`, `GET /controller/rest/applications/${appPath}/backends`, `GET /controller/rest/applications/${appPath}/request-snapshots`, ); const tiers = Array.isArray(tiersRes.body) ? tiersRes.body : []; const backends = Array.isArray(backendsRes.body) ? backendsRes.body : []; const snapshots = Array.isArray(snapshotsRes.body) ? snapshotsRes.body : []; const nodes: DependencyNode[] = [ ...tiers .filter((t): t is Tier & { id: number; name: string } => typeof t.id === 'number' && !!t.name) .map((t) => ({ kind: 'tier' as const, id: t.id, name: t.name, type: t.type })), ...backends .filter( (b): b is Backend & { id: number; name: string } => typeof b.id === 'number' && !!b.name, ) .map((b) => ({ kind: 'backend' as const, id: b.id, name: b.name, type: b.exitPointType, })), ]; // Edge keying: fromTierId|toTierId-or-backendId|exitPointType const edgeMap = new Map<string, DependencyEdge>(); for (const snap of snapshots) { const fromTierId = snap.applicationComponentId; if (typeof fromTierId !== 'number') continue; const calls = Array.isArray(snap.exitCalls) ? snap.exitCalls : []; for (const call of calls) { const toTier = call.toComponentId; const toBackend = call.backendId; if (typeof toTier !== 'number' && typeof toBackend !== 'number') continue; const exitPointType = call.exitPointType ?? 'UNKNOWN'; const key = `${fromTierId}|${toTier ?? `b${toBackend}`}|${exitPointType}`; const existing = edgeMap.get(key); const callCount = call.count ?? 1; const callLatency = call.timeTakenInMillis ?? 0; const isError = snap.errorOccured === true || (typeof call.httpStatusCode === 'number' && call.httpStatusCode >= 500); if (existing) { existing.callCount += callCount; existing.totalLatencyMs += callLatency; if (isError) existing.errorCount += 1; } else { edgeMap.set(key, { fromTierId, toTierId: toTier, toBackendId: toBackend, exitPointType, callCount, totalLatencyMs: callLatency, avgLatencyMs: undefined, errorCount: isError ? 1 : 0, detail: call.detailString, }); } } } const edges: DependencyEdge[] = Array.from(edgeMap.values()).map((e) => ({ ...e, avgLatencyMs: e.callCount > 0 ? Math.round((e.totalLatencyMs / e.callCount) * 100) / 100 : undefined, })); const warnings = timeRangeWarnings(tr); if (snapshots.length < MIN_SNAPSHOTS_FOR_CONFIDENCE) { warnings.push( `Low confidence: only ${snapshots.length} snapshot${ snapshots.length === 1 ? '' : 's' } back the synthesized edges (threshold ${MIN_SNAPSHOTS_FOR_CONFIDENCE}). Widen the time range or relax filters for a more complete map.`, ); } return toToolResult( buildEnvelope({ summary: `Dependency map: ${nodes.length} nodes, ${edges.length} edges from ${snapshots.length} snapshots.`, evidence: { application: input.application, applicationId: input.application, snapshotsScanned: snapshots.length, nodes, edges, } as DependencyMapEvidence, entities: [{ kind: 'application', id: input.application }], timeRange: toEnvelopeTimeRange(tr), sourceEndpoints, warnings, }), ); }, ), ); }, }; - src/tools/getDependencyMap.ts:27-30 (schema)Input schema for the tool: application (AppRef: string or number) and optional timeRange.
const inputShape = { application: appRefSchema, timeRange: timeRangeSchema.optional(), }; - src/tools/index.ts:18-38 (registration)The getDependencyMapTool is exported from getDependencyMap.ts and included in the ALL_TOOLS array, getting registered via registerAllTools -> registerTools.
export const ALL_TOOLS: ToolRegistration[] = [ listApplicationsTool, getApplicationModelTool, getMetricHierarchyTool, queryMetricsTool, getTransactionSnapshotsTool, getHealthRuleViolationsTool, getAnomalyViolationsTool, getEventsTool, listHealthRulesTool, getAlertingConfigTool, queryAnalyticsEventsTool, getDependencyMapTool, ]; export function registerAllTools( server: McpServer, services: Services, ): { registered: string[]; skipped: string[] } { return registerTools(server, services, ALL_TOOLS); } - src/tools/getDependencyMap.ts:24-25 (helper)Constants: MIN_SNAPSHOTS_FOR_CONFIDENCE (25) and SNAPSHOT_FETCH (200) used in the handler logic.
const MIN_SNAPSHOTS_FOR_CONFIDENCE = 25; const SNAPSHOT_FETCH = 200;