Skip to main content
Glama

Endpoint Reachability Check

check_endpoint
Read-onlyIdempotent

Probe a public URL or API endpoint to verify it responds and inspect its HTTP status, content type, elapsed time, and response sample. Use this before recommending, documenting, or building on an endpoint.

Instructions

Perform one live, unauthenticated fetch against a public URL or API endpoint before you recommend it, document it, or build on top of it. Use this when the question is simply whether an endpoint currently responds and what kind of response it returns. It reports HTTP status, content type, elapsed time, likely auth/rate-limit signals, and a short response sample. Do not use it to validate authenticated flows, POST side effects, or deeper business logic.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesPublic http(s) URL or bare domain to probe. Bare domains like google.com are accepted and normalized to https:// automatically.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
inputUrlNoOriginal user input when normalization changed it, for example when https:// was added.
urlYesNormalized URL that was actually fetched.
accessibleYesTrue when the endpoint returned a 2xx HTTP status.
statusNoHTTP status code returned by the endpoint, when a response was received.
contentTypeNoResponse Content-Type header, if present.
responseTimeMsNoElapsed request time in milliseconds.
authRequiredNoTrue when the server responded with 401 or 403, which usually means credentials are required.
rateLimitedNoTrue when the server responded with 429 Too Many Requests.
sampleResponseNoFirst 1,000 characters of the response body for quick inspection.
errorNoValidation or network error when the request could not be completed.

Implementation Reference

  • src/index.ts:574-670 (registration)
    Registration of the check_endpoint tool via McpServer.registerTool, including metadata about the free tier tool.
    this.server.registerTool(
      "check_endpoint",
      {
        title: "Endpoint Reachability Check",
        description:
          "Perform one live, unauthenticated fetch against a public URL or API endpoint " +
          "before you recommend it, document it, or build on top of it. Use this when " +
          "the question is simply whether an endpoint currently responds and what kind " +
          "of response it returns. It reports HTTP status, content type, elapsed time, " +
          "likely auth/rate-limit signals, and a short response sample. A successful " +
          "result only proves basic reachability at fetch time. Do not use it to " +
          "validate authenticated flows, POST side effects, JavaScript execution, " +
          "or deeper business logic.",
        inputSchema: {
          url: z.string().trim().min(1).describe(
            "Public http(s) URL or bare domain to probe. Bare domains like google.com are accepted and normalized to https:// automatically.",
          ),
        },
        outputSchema: {
          inputUrl: z.string().describe(
            "Original user input when normalization changed it, for example when https:// was added.",
          ).optional(),
          url: z.string().describe(
            "Normalized URL that was actually fetched.",
          ),
          accessible: z.boolean().describe(
            "True when the endpoint returned a 2xx HTTP status.",
          ),
          status: z.number().int().describe(
            "HTTP status code returned by the endpoint, when a response was received.",
          ).optional(),
          contentType: z.string().nullable().describe(
            "Response Content-Type header, if present.",
          ).optional(),
          responseTimeMs: z.number().int().nonnegative().describe(
            "Elapsed request time in milliseconds.",
          ).optional(),
          authRequired: z.boolean().describe(
            "True when the server responded with 401 or 403, which usually means credentials are required.",
          ).optional(),
          rateLimited: z.boolean().describe(
            "True when the server responded with 429 Too Many Requests.",
          ).optional(),
          sampleResponse: z.string().describe(
            "First 1,000 characters of the response body for quick inspection.",
          ).optional(),
          error: z.string().describe(
            "Validation or network error when the request could not be completed.",
          ).optional(),
        },
        annotations: readOnlyNetworkToolAnnotations,
      },
      async ({ url }) => {
        const normalizedUrl = normalizeHttpUrlInput(url);
        if (!normalizedUrl) {
          logUsage("check_endpoint", false);
          return structuredToolResult({
            url,
            accessible: false,
            error: "Invalid URL. Use a public http(s) URL or a bare domain like google.com.",
          });
        }
    
        const start = Date.now();
        try {
          const resp = await fetch(normalizedUrl, {
            headers: { "User-Agent": "GroundTruth/0.3" },
          });
          const elapsed = Date.now() - start;
          const body = await resp.text();
          const sample = body.slice(0, 1000);
          logUsage("check_endpoint", true);
    
          return structuredToolResult({
            ...(normalizedUrl !== url ? { inputUrl: url } : {}),
            url: normalizedUrl,
            accessible: resp.ok,
            status: resp.status,
            contentType: resp.headers.get("content-type"),
            responseTimeMs: elapsed,
            authRequired: resp.status === 401 || resp.status === 403,
            rateLimited: resp.status === 429,
            sampleResponse: sample,
          });
        } catch (e: unknown) {
          const message = e instanceof Error ? e.message : String(e);
          logUsage("check_endpoint", false);
          return structuredToolResult({
            ...(normalizedUrl !== url ? { inputUrl: url } : {}),
            url: normalizedUrl,
            accessible: false,
            error: message,
            responseTimeMs: Date.now() - start,
          });
        }
      }
    );
  • Input/output schema for check_endpoint using Zod validators. Input requires a URL string; output includes reachability, status, timing, auth/rate-limit signals, and a response sample.
    inputSchema: {
      url: z.string().trim().min(1).describe(
        "Public http(s) URL or bare domain to probe. Bare domains like google.com are accepted and normalized to https:// automatically.",
      ),
    },
    outputSchema: {
      inputUrl: z.string().describe(
  • Handler function that executes the check_endpoint logic: normalizes URL, performs an HTTP GET, returns status/content-type/response time/auth/rate-limit signals and a sample of the response body.
    async ({ url }) => {
      const normalizedUrl = normalizeHttpUrlInput(url);
      if (!normalizedUrl) {
        logUsage("check_endpoint", false);
        return structuredToolResult({
          url,
          accessible: false,
          error: "Invalid URL. Use a public http(s) URL or a bare domain like google.com.",
        });
      }
    
      const start = Date.now();
      try {
        const resp = await fetch(normalizedUrl, {
          headers: { "User-Agent": "GroundTruth/0.3" },
        });
        const elapsed = Date.now() - start;
        const body = await resp.text();
        const sample = body.slice(0, 1000);
        logUsage("check_endpoint", true);
    
        return structuredToolResult({
          ...(normalizedUrl !== url ? { inputUrl: url } : {}),
          url: normalizedUrl,
          accessible: resp.ok,
          status: resp.status,
          contentType: resp.headers.get("content-type"),
          responseTimeMs: elapsed,
          authRequired: resp.status === 401 || resp.status === 403,
          rateLimited: resp.status === 429,
          sampleResponse: sample,
        });
      } catch (e: unknown) {
        const message = e instanceof Error ? e.message : String(e);
        logUsage("check_endpoint", false);
        return structuredToolResult({
          ...(normalizedUrl !== url ? { inputUrl: url } : {}),
          url: normalizedUrl,
          accessible: false,
          error: message,
          responseTimeMs: Date.now() - start,
        });
      }
    }
  • Helper used by the check_endpoint handler to normalize user input into a valid http(s) URL, including auto-prepending https:// for bare domains.
    function normalizeHttpUrlInput(input: string): string | null {
      const trimmed = input.trim();
      if (!trimmed) return null;
    
      const candidate = /^[a-zA-Z][a-zA-Z\d+.-]*:/.test(trimmed)
        ? trimmed
        : `https://${trimmed}`;
    
      try {
        const parsed = new URL(candidate);
        if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
          return null;
        }
        if (!parsed.hostname) {
          return null;
        }
        return parsed.toString();
      } catch {
        return null;
      }
    }
  • Helper function that wraps structured data into an MCP tool result with JSON text content, used by the check_endpoint handler to return its output.
    function structuredToolResult<T extends Record<string, unknown>>(structuredContent: T) {
      return {
        content: [{
          type: "text" as const,
          text: JSON.stringify(structuredContent, null, 2),
        }],
        structuredContent,
      };
    }
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, etc. Description adds that it reports HTTP status, content type, elapsed time, auth/rate-limit signals, and a short response sample. Also discloses it's unauthenticated and live. No contradictions.

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?

Description is short, front-loaded with purpose, and every sentence adds value. No unnecessary words.

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

Completeness5/5

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

Simple tool with one parameter, high schema coverage, output schema exists, and annotations are complete. Description covers purpose, usage, behavior, and output details sufficiently.

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

Parameters3/5

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

Single parameter url has 100% schema coverage. Description in text reinforces that it's a public URL, but doesn't add much beyond the schema's description. Baseline 3 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?

Clearly states it performs a live, unauthenticated fetch against a public URL. Uses specific verb 'perform' and resource 'public URL/API endpoint', and context 'before you recommend, document, or build on top of it'. Distinguishes from sibling tools like check_pricing.

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

Usage Guidelines5/5

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

Explicitly says 'Use this when the question is simply whether an endpoint currently responds and what kind of response it returns.' Also provides negative guidance: 'Do not use it to validate authenticated flows, POST side effects, or deeper business logic.'

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/anish632/ground-truth-mcp'

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