Health Check
pingVerifies Claude CLI installation and authentication, reporting versions, capabilities, and configuration. Local-only health check.
Instructions
Health check: verifies Claude CLI is installed and authenticated, reports versions, capabilities, and configuration. No cost (local check only).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools/ping.ts:61-142 (handler)The main handler function executePing() that performs the health check by detecting the Claude CLI binary, checking authentication, reading config, and returning a PingResult with server/cli state.
export async function executePing(): Promise<PingResult> { const binary = findClaudeBinary(); const maxConcurrent = getMaxConcurrent(); const activeCount = getActiveCount(); const queueDepth = getQueueDepth(); let cliFound = false; let version: string | null = null; try { version = execFileSync(binary, ["--version"], { encoding: "utf8", timeout: 10_000, }).trim(); cliFound = true; } catch (e) { const err = e as NodeJS.ErrnoException; if (err.code === "ENOENT") { return { cliFound: false, version: null, authMethod: "none", subscriptionType: null, defaultModel: getDefaultModel("query"), fallbackModel: getFallbackModel() ?? null, serverVersion: PKG_VERSION, nodeVersion: process.version, maxConcurrent, activeCount, queueDepth, capabilities: { bareMode: false, jsonOutput: false, jsonSchema: false, sessionResume: false, }, }; } // Non-ENOENT errors (EACCES, timeout, broken binary) mean the CLI exists // but is not usable. Report cliFound: false with a diagnostic message. return { cliFound: false, version: `error: ${err.message ?? String(e)}`, authMethod: "none", subscriptionType: null, defaultModel: getDefaultModel("query"), fallbackModel: getFallbackModel() ?? null, serverVersion: PKG_VERSION, nodeVersion: process.version, maxConcurrent, activeCount, queueDepth, capabilities: { bareMode: false, jsonOutput: false, jsonSchema: false, sessionResume: false, }, }; } const auth = detectAuth(); return { cliFound, version, authMethod: auth.method, subscriptionType: auth.subscriptionType, defaultModel: getDefaultModel("query"), fallbackModel: getFallbackModel() ?? null, serverVersion: PKG_VERSION, nodeVersion: process.version, maxConcurrent, activeCount, queueDepth, capabilities: { bareMode: true, jsonOutput: true, jsonSchema: true, sessionResume: true, }, }; } - src/tools/ping.ts:12-30 (schema)The PingResult interface defining the full shape of the ping tool's output (cliFound, version, authMethod, capabilities, etc.).
export interface PingResult { cliFound: boolean; version: string | null; authMethod: "api-key" | "subscription" | "none"; subscriptionType: string | null; defaultModel: string | null; fallbackModel: string | null; serverVersion: string; nodeVersion: string; maxConcurrent: number; activeCount: number; queueDepth: number; capabilities: { bareMode: boolean; jsonOutput: boolean; jsonSchema: boolean; sessionResume: boolean; }; } - src/index.ts:314-356 (registration)Registration of the 'ping' tool on the MCP server via server.registerTool, including inputSchema (empty), annotations, and the async callback that calls executePing() and formats the response.
// --- ping tool --- server.registerTool( "ping", { title: "Health Check", description: pingDescription, inputSchema: {}, annotations: pingAnnotations, }, async () => { const start = Date.now(); try { const result = await executePing(); const lines = [ `cliFound: ${result.cliFound}`, `version: ${result.version ?? "unknown"}`, `authMethod: ${result.authMethod}`, ...(result.subscriptionType ? [`subscriptionType: ${result.subscriptionType}`] : []), `defaultModel: ${result.defaultModel ?? "none"}`, `fallbackModel: ${result.fallbackModel ?? "none"}`, `serverVersion: ${result.serverVersion}`, `nodeVersion: ${result.nodeVersion}`, `maxConcurrent: ${result.maxConcurrent}`, `activeCount: ${result.activeCount}`, `queueDepth: ${result.queueDepth}`, `capabilities: bareMode=${result.capabilities.bareMode}, jsonOutput=${result.capabilities.jsonOutput}, jsonSchema=${result.capabilities.jsonSchema}, sessionResume=${result.capabilities.sessionResume}`, ]; return { content: [{ type: "text" as const, text: lines.join("\n") }], _meta: buildMeta({ durationMs: Date.now() - start }), }; } catch (e) { console.error("[ping]", e); return { content: [{ type: "text" as const, text: `Error: ${getErrorMessage(e)}` }], isError: true, _meta: buildMeta({ durationMs: Date.now() - start }), }; } }, ); - src/tools/ping.ts:39-59 (helper)Helper function detectAuth() that checks for ANTHROPIC_API_KEY env var or reads credentials file to determine auth method.
function detectAuth(): { method: PingResult["authMethod"]; subscriptionType: string | null } { const env = buildSubprocessEnv(); if (env["ANTHROPIC_API_KEY"]) { return { method: "api-key", subscriptionType: null }; } const configDir = process.env["CLAUDE_CONFIG_DIR"] ?? join(process.env["HOME"] ?? "", ".claude"); try { const raw = readFileSync(join(configDir, ".credentials.json"), "utf8"); const creds = JSON.parse(raw) as CredentialsFile; const oauth = creds.claudeAiOauth; if (oauth?.expiresAt && oauth.expiresAt > Date.now()) { return { method: "subscription", subscriptionType: oauth.subscriptionType ?? null }; } } catch { // No credentials file or unreadable } return { method: "none", subscriptionType: null }; } - src/utils/model.ts:1-8 (helper)ToolName type definition includes 'ping', and the DEFAULT_MODELS map assigns 'haiku' as the default model for ping.
export type ToolName = "query" | "structured" | "search" | "ping"; const DEFAULT_MODELS: Record<ToolName, string> = { query: "sonnet", structured: "sonnet", search: "sonnet", ping: "haiku", };