Skip to main content
Glama

codebase_health

Check the health of Docker, Qdrant, Ollama, and embedding model infrastructure to diagnose setup issues.

Instructions

Check the health of all infrastructure: Docker, Qdrant container, Ollama, and embedding model. Use this to diagnose setup issues.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The handleManageTool function contains the 'codebase_health' case (lines 63-129) which performs the full health check logic: checks Docker availability, Qdrant container status (managed or external mode), embedding provider health, and returns a formatted status report.
    export async function handleManageTool(
      name: string,
      _args: Record<string, unknown>,
    ): Promise<string> {
      switch (name) {
        case "codebase_health": {
          const config = getEmbeddingConfig();
          const status: HealthStatus = {
            docker: false,
            ollama: false,
            qdrant: false,
            ollamaModel: false,
            qdrantImage: false,
            ollamaImage: false,
          };
    
          const icon = (ok: boolean) => (ok ? "[OK]" : "[MISSING]");
          const lines: string[] = [
            "SocratiCode — Infrastructure Health Check:",
            "",
            `Qdrant mode: ${QDRANT_MODE}`,
          ];
    
          if (QDRANT_MODE === "external") {
            const endpoint = QDRANT_URL ?? `http://${QDRANT_HOST}:${QDRANT_PORT}`;
            lines.push(`Qdrant endpoint: ${endpoint}`);
            try {
              await listCodebaseCollections();
              status.qdrant = true;
              lines.push(`${icon(true)} External Qdrant (${endpoint}): Reachable`);
            } catch {
              lines.push(`${icon(false)} External Qdrant (${endpoint}): Unreachable — check QDRANT_URL / QDRANT_HOST`);
            }
          } else {
            // managed mode — Docker-managed container
            const docker = await isDockerAvailable();
            status.docker = docker;
            lines.push(`${icon(status.docker)} Docker: ${status.docker ? "Running" : "Not found — install from https://docker.com"}`);
    
            if (docker) {
              const [qdrantRunning, qdrantImage] = await Promise.all([
                isQdrantRunning(),
                isQdrantImagePresent(),
              ]);
              status.qdrant = qdrantRunning;
              status.qdrantImage = qdrantImage;
    
              lines.push(`${icon(status.qdrantImage)} Qdrant image: ${status.qdrantImage ? "Pulled" : "Not pulled — will be pulled on first index"}`);
              lines.push(`${icon(status.qdrant)} Qdrant container: ${status.qdrant ? "Running" : "Not running — will be started on first index"}`);
            }
          }
    
          // Embedding provider health check (works for ollama, openai, google)
          lines.push("");
          lines.push(`Embedding provider: ${config.embeddingProvider}`);
          const provider = await getEmbeddingProvider();
          const health = await provider.healthCheck();
          lines.push(...health.statusLines);
    
          lines.push("");
          if (QDRANT_MODE === "external") {
            lines.push("External Qdrant mode — Docker is not required for the vector database.");
          } else {
            lines.push(
              status.docker
                ? "Docker is available. Qdrant container will be auto-managed."
                : "Docker is required for Qdrant. Install from https://docker.com",
            );
          }
    
          return lines.join("\n");
        }
    
        case "codebase_list_projects": {
          try {
            const collections = await listCodebaseCollections();
    
            if (collections.length === 0) {
              return "No projects have been indexed yet. Use codebase_index to index a project.";
            }
    
            const codebaseCollections = collections.filter((c) => c.startsWith("codebase_"));
            const graphCollections = collections.filter((c) => c.startsWith("codegraph_"));
    
            const lines = ["Indexed projects:\n"];
    
            for (const c of codebaseCollections) {
              const projectId = c.replace("codebase_", "");
              const hasGraph = graphCollections.includes(`codegraph_${projectId}`);
              const metadata = await getProjectMetadata(c);
              const pathInfo = metadata?.projectPath || "(path unknown — indexed before path tracking)";
              lines.push(`  - ${pathInfo}`);
              lines.push(`    Collection: ${c}`);
              if (metadata?.lastIndexedAt) {
                lines.push(`    Last indexed: ${metadata.lastIndexedAt}`);
              }
              if (metadata?.filesIndexed !== undefined) {
                if (metadata.indexingStatus === "in-progress") {
                  lines.push(`    Files: ${metadata.filesIndexed}/${metadata.filesTotal} (INCOMPLETE — run codebase_index to resume)`);
                } else {
                  lines.push(`    Files: ${metadata.filesIndexed}`);
                }
              }
              if (hasGraph) {
                const graphMeta = await getGraphMetadata(`codegraph_${projectId}`);
                if (graphMeta) {
                  lines.push(`    Code graph: ${graphMeta.nodeCount} files, ${graphMeta.edgeCount} edges (built: ${graphMeta.lastBuiltAt})`);
                } else {
                  lines.push(`    Code graph: present`);
                }
              } else {
                lines.push(`    Code graph: not built`);
              }
              // Context artifacts
              try {
                const pathInfo2 = metadata?.projectPath;
                if (pathInfo2) {
                  const artifactSummary = await getArtifactStatusSummary(pathInfo2);
                  if (artifactSummary) {
                    lines.push(`    ${artifactSummary.lines[0]}`);
                  }
                }
              } catch {
                // non-critical
              }
            }
    
            return lines.join("\n");
          } catch {
            return "Could not connect to Qdrant. Run codebase_health to check infrastructure status.";
          }
        }
    
        case "codebase_about": {
          const infraStatus = await getInfraStatusSummary();
          return [
            "SocratiCode — Codebase intelligence MCP server",
            "Hybrid semantic + keyword search, dependency graphs, context artifacts.",
            "",
            ...infraStatus,
            "",
            "━━━ Quick Reference ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
            "",
            "Indexing:",
            "  codebase_index        — Index a project (background). Poll with codebase_status.",
            "  codebase_update       — Incremental re-index (changed files only).",
            "  codebase_stop         — Gracefully stop in-progress indexing.",
            "  codebase_remove       — Delete a project's index.",
            "  codebase_watch        — Start/stop/status of live file watcher.",
            "",
            "Search:",
            "  codebase_search       — Hybrid semantic + BM25 search. Use after indexing.",
            "  codebase_status       — Check index status, progress, watcher state.",
            "",
            "Dependency Graph:",
            "  codebase_graph_build  — Build AST-based dependency graph (background).",
            "  codebase_graph_query  — Imports & dependents for a file.",
            "  codebase_graph_stats  — Graph stats: files, edges, most connected, orphans.",
            "  codebase_graph_circular — Find circular dependencies.",
            "  codebase_graph_visualize — Mermaid diagram (default) or interactive HTML explorer (mode=\"interactive\"), colour-coded by language.",
            "  codebase_graph_status — Poll graph build progress.",
            "  codebase_graph_remove — Delete a project's graph.",
            "",
            "Context Artifacts:",
            "  codebase_context        — List artifacts (.socraticodecontextartifacts.json).",
            "  codebase_context_search — Search schemas, API specs, configs, docs.",
            "  codebase_context_index  — Re-index artifacts (usually automatic).",
            "  codebase_context_remove — Delete indexed artifacts.",
            "",
            "Management:",
            "  codebase_health       — Check Docker, Qdrant, embeddings status.",
            "  codebase_list_projects — List all indexed projects.",
            "",
            "━━━ Typical Workflow ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
            "",
            "1. codebase_index → poll codebase_status until complete.",
            "2. codebase_search to find code. Search before reading files.",
            "3. codebase_graph_query to explore dependencies.",
            "4. codebase_context_search for schemas, API specs, configs.",
            "",
            `v${SOCRATICODE_VERSION} · © 2026 Giancarlo Erra — Altaire Limited · AGPL-3.0`,
            "https://github.com/giancarloerra/socraticode",
          ].join("\n");
        }
    
        default:
          return `Unknown tool: ${name}`;
      }
    }
  • src/index.ts:414-421 (registration)
    Registration of the 'codebase_health' tool via server.tool(), with description and delegation to handleManageTool.
    server.tool(
      "codebase_health",
      "Check the health of all infrastructure: Docker, Qdrant container, Ollama, and embedding model. Use this to diagnose setup issues.",
      {},
      async (args) => ({
        content: [{ type: "text", text: await handleManageTool("codebase_health", args) }],
      }),
    );
  • HealthStatus interface defining the boolean fields tracked during health checks (docker, ollama, qdrant, ollamaModel, qdrantImage, ollamaImage).
    export interface HealthStatus {
      docker: boolean;
      ollama: boolean;
      qdrant: boolean;
      ollamaModel: boolean;
      qdrantImage: boolean;
      ollamaImage: boolean;
    }
  • EmbeddingHealthStatus interface returned by provider.healthCheck(), including available, modelReady, and statusLines used in the health tool output.
    export interface EmbeddingHealthStatus {
      /** Provider is reachable and ready. */
      available: boolean;
      /** The model/endpoint is accessible. */
      modelReady: boolean;
      /** Human-readable status lines for the health tool. */
      statusLines: string[];
    }
  • getInfraStatusSummary helper used by codebase_about, sharing infrastructure check logic similar to codebase_health.
    /** Quick infrastructure check for embedding in codebase_about */
    async function getInfraStatusSummary(): Promise<string[]> {
      const lines: string[] = [];
      const config = getEmbeddingConfig();
      try {
        if (QDRANT_MODE === "external") {
          const endpoint = QDRANT_URL ?? `http://${QDRANT_HOST}:${QDRANT_PORT}`;
          try {
            await listCodebaseCollections(); // throws if unreachable
            const provider = await getEmbeddingProvider();
            const health = await provider.healthCheck();
            if (health.available) {
              lines.push(`Infrastructure: ✅ External Qdrant reachable (${endpoint}), ${config.embeddingProvider} embeddings ready`);
            } else {
              lines.push(`Infrastructure: ⚠️ External Qdrant reachable (${endpoint}), but ${config.embeddingProvider} embeddings not ready`);
            }
          } catch {
            lines.push(`Infrastructure: ❌ Cannot reach external Qdrant at ${endpoint}`);
            lines.push("  Check QDRANT_URL / QDRANT_HOST and make sure the server is running.");
          }
        } else {
          const docker = await isDockerAvailable();
          if (!docker) {
            lines.push("Infrastructure: ❌ Docker not available");
            lines.push("  Install from https://docker.com and start Docker Desktop.");
            return lines;
          }
          const qdrant = await isQdrantRunning();
          const provider = await getEmbeddingProvider();
          const health = await provider.healthCheck();
          if (qdrant && health.available) {
            lines.push(`Infrastructure: ✅ All services running (Docker, Qdrant, ${config.embeddingProvider} embeddings)`);
          } else {
            const missing: string[] = [];
            if (!qdrant) missing.push("Qdrant");
            if (!health.available) missing.push(`${config.embeddingProvider} embeddings`);
            lines.push(`Infrastructure: ⚠️ Docker OK, but ${missing.join(" and ")} not running`);
            lines.push("  Run codebase_index or codebase_health to auto-start services.");
          }
        }
      } catch {
        lines.push("Infrastructure: ❓ Could not check status");
      }
      return lines;
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It states 'check the health' which implies a read-only operation, but it does not explicitly confirm that it is non-destructive or detail any side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences long, contains no redundant information, and is clearly structured with the action and purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description adequately covers what the tool checks and its intended use case given the absence of parameters and output schema. However, the lack of explicit read-only assurance is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters and 100% description coverage, so the description does not need to add parameter information. Baseline score of 4 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Check' and the specific resources: Docker, Qdrant container, Ollama, and embedding model. It distinguishes from siblings like 'codebase_status' which likely checks only the codebase itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says 'Use this to diagnose setup issues,' which implies the context for use. However, it does not explicitly state when not to use it or provide alternatives among siblings, though no sibling directly overlaps with this broad health check.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/giancarloerra/SocratiCode'

If you have feedback or need assistance with the MCP directory API, please join our Discord server