Skip to main content
Glama
DMontgomery40

mcp-server-birdstats

Read BirdWeather API Schema

get_birdweather_api
Read-onlyIdempotent

Inspect the BirdWeather OpenAPI contract to understand API endpoints and structure for integrating with bird observation data.

Instructions

Use this tool to inspect the BirdWeather OpenAPI contract used by this server. Required inputs: none. Defaults: mode='summary', maxPaths=25, optional pathPrefix filter. Set mode='full' with confirmLargePayload=true for full schema. Side effects: none (read-only local file access). Cost note: full schema is large; summary is preferred for planning.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
modeNosummary
confirmLargePayloadNo
maxPathsNo
pathPrefixNo

Implementation Reference

  • src/index.ts:385-414 (registration)
    Tool registration for 'get_birdweather_api' with schema definition (mode, confirmLargePayload, maxPaths, pathPrefix) and handler function that calls createApiSpecToolResult.
    server.registerTool(
      "get_birdweather_api",
      {
        title: "Read BirdWeather API Schema",
        description:
          "Use this tool to inspect the BirdWeather OpenAPI contract used by this server. Required inputs: none. Defaults: mode='summary', maxPaths=25, optional pathPrefix filter. Set mode='full' with confirmLargePayload=true for full schema. Side effects: none (read-only local file access). Cost note: full schema is large; summary is preferred for planning.",
        inputSchema: {
          mode: z.enum([TOOL_MODE_SUMMARY, TOOL_MODE_FULL]).default(TOOL_MODE_SUMMARY),
          confirmLargePayload: z.boolean().default(false),
          maxPaths: z.number().int().min(1).max(200).default(25),
          pathPrefix: z.string().trim().min(1).optional(),
        },
        annotations: {
          title: "Read BirdWeather API Schema",
          readOnlyHint: true,
          idempotentHint: true,
          destructiveHint: false,
          openWorldHint: false,
        },
      },
      async ({ mode, confirmLargePayload, maxPaths, pathPrefix }) =>
        createApiSpecToolResult(
          "birdweather",
          BIRDWEATHER_SPEC_PATH,
          mode as ToolMode,
          confirmLargePayload,
          maxPaths,
          pathPrefix
        )
    );
  • Handler function that extracts parameters and delegates to createApiSpecToolResult with 'birdweather' API type, BIRDWEATHER_SPEC_PATH, and the provided options.
    async ({ mode, confirmLargePayload, maxPaths, pathPrefix }) =>
      createApiSpecToolResult(
        "birdweather",
        BIRDWEATHER_SPEC_PATH,
        mode as ToolMode,
        confirmLargePayload,
        maxPaths,
        pathPrefix
      )
  • Main implementation function createApiSpecToolResult that reads the OpenAPI JSON spec, creates a summary via summarizeOpenApi, handles confirmLargePayload validation for full mode, and returns structured CallToolResult.
    function createApiSpecToolResult(
      api: "birdweather" | "ebird",
      sourcePath: string,
      mode: ToolMode,
      confirmLargePayload: boolean,
      maxPaths: number,
      pathPrefix: string | undefined
    ): CallToolResult {
      try {
        const spec = readJsonFile(sourcePath);
        const summary = summarizeOpenApi(api, sourcePath, spec, maxPaths, pathPrefix);
    
        if (mode === TOOL_MODE_FULL && !confirmLargePayload) {
          return buildToolErrorResult(
            "Large payload blocked by default.",
            "Set confirmLargePayload=true to receive the full OpenAPI document.",
            true,
            {
              api,
              expectedMode: TOOL_MODE_FULL,
              currentMode: mode,
            }
          );
        }
    
        if (mode === TOOL_MODE_FULL) {
          return {
            structuredContent: {
              ...summary,
              mode,
              spec,
            },
            content: [
              {
                type: "text",
                text: `Returned full ${api} OpenAPI spec (${summary.totals.pathCount} paths).`,
              },
            ],
          };
        }
    
        return {
          structuredContent: {
            ...summary,
            mode,
          },
          content: [
            {
              type: "text",
              text: `Returned ${api} OpenAPI summary with ${summary.selectedPaths.length} path samples.`,
            },
          ],
        };
      } catch (error) {
        return buildToolErrorResult(
          `Failed to load ${api} OpenAPI document: ${toErrorMessage(error)}`,
          "Verify the repository includes the expected JSON spec file.",
          false
        );
      }
    }
  • Helper function summarizeOpenApi that parses OpenAPI spec to extract info, paths, operations, schemas, and tags, creating an OpenApiSummary with filtered paths based on pathPrefix.
    function summarizeOpenApi(
      api: "birdweather" | "ebird",
      sourcePath: string,
      spec: Record<string, unknown>,
      maxPaths: number,
      pathPrefix?: string
    ): OpenApiSummary {
      const info = toObject(spec.info);
      const paths = toObject(spec.paths);
      const pathEntries = Object.entries(paths);
      const filteredEntries = pathPrefix
        ? pathEntries.filter(([pathName]) => pathName.startsWith(pathPrefix))
        : pathEntries;
    
      let operationCount = 0;
      for (const [, operationsValue] of filteredEntries) {
        const operations = toObject(operationsValue);
        operationCount += Object.keys(operations).filter((method) => HTTP_METHODS.has(method.toLowerCase())).length;
      }
    
      const components = toObject(spec.components);
      const schemas = toObject(components.schemas);
      const tags = Array.isArray(spec.tags) ? spec.tags : [];
    
      return {
        status: "ok",
        api,
        mode: TOOL_MODE_SUMMARY,
        sourcePath,
        info,
        totals: {
          pathCount: pathEntries.length,
          operationCount,
          schemaCount: Object.keys(schemas).length,
          tagCount: tags.length,
        },
        selectedPaths: filteredEntries.slice(0, maxPaths).map(([pathName]) => pathName),
      };
    }
  • Utility functions readJsonFile (reads and parses JSON from file system) and toObject (safely converts unknown type to Record<string, unknown>) used by the tool implementation.
    function readJsonFile(filePath: string): Record<string, unknown> {
      const raw = readUtf8File(filePath);
      const parsed = JSON.parse(raw) as unknown;
    
      if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
        throw new Error(`Expected top-level object in ${filePath}`);
      }
    
      return parsed as Record<string, unknown>;
    }
    
    function toObject(value: unknown): Record<string, unknown> {
      if (value && typeof value === "object" && !Array.isArray(value)) {
        return value as Record<string, unknown>;
      }
    
      return {};
    }
Behavior4/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, covering safety and idempotency. The description adds valuable context beyond this: 'Side effects: none (read-only local file access)' clarifies the scope, and 'Cost note: full schema is large' warns about payload size. It doesn't contradict annotations but provides practical behavioral details.

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 front-loaded with the core purpose, followed by parameter guidance and behavioral notes in a logical flow. Every sentence adds value: the first states the action, the second covers inputs and defaults, the third explains mode usage, and the fourth adds side effects and cost. No wasted words.

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?

Given 4 parameters with no schema descriptions and no output schema, the description does well to explain parameter usage, defaults, and behavioral traits. It covers when to use different modes and warnings about payload size. However, it doesn't detail the response format or error handling, leaving some gaps for a tool with multiple parameters.

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?

With 0% schema description coverage, the description compensates well by explaining parameter purposes: 'mode='summary'' vs. 'full', 'maxPaths=25' for limiting output, 'optional pathPrefix filter' for filtering, and the requirement of 'confirmLargePayload=true' for full mode. It adds meaning beyond the bare schema, though it doesn't detail all constraints like min/max values.

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 specific action ('inspect the BirdWeather OpenAPI contract') and resource ('used by this server'), distinguishing it from sibling tools like get_ebird_api and get_system_prompt. It goes beyond the title by specifying it's for reading the API schema, not just a generic 'read' operation.

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?

The description provides explicit guidance on when to use different modes: 'summary is preferred for planning' and 'Set mode='full' with confirmLargePayload=true for full schema.' It also mentions 'optional pathPrefix filter' for specific use cases, offering clear alternatives within the tool itself.

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/DMontgomery40/mcp-server-birdstats'

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