All files / src/mcp/ep parse.ts

89.47% Statements 17/19
88.23% Branches 15/17
100% Functions 2/2
93.75% Lines 15/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62                                          171x 171x 170x 170x 170x 169x     1x                                         4x 4x 4x 4x 21x 21x 21x     4x    
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
// SPDX-License-Identifier: Apache-2.0
 
/**
 * @module MCP/ep/parse
 * @description JSON payload parsing helpers for EP MCP tool results.
 */
 
import type { MCPToolResult } from '../../types/index.js';
 
/**
 * Parse the text payload of an {@link MCPToolResult} as JSON, returning
 * `undefined` when the payload is missing or malformed. Small helper used by
 * the unavailable-envelope detectors below.
 *
 * @param result - Raw MCP tool result
 * @returns Parsed JSON object, or `undefined` if the payload is not a JSON object
 */
export function _parseResultPayload(
  result: MCPToolResult | undefined
): Record<string, unknown> | undefined {
  const text = result?.content?.[0]?.text;
  if (typeof text !== 'string' || text.length === 0) return undefined;
  try {
    const parsed: unknown = JSON.parse(text);
    if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
      return parsed as Record<string, unknown>;
    }
  } catch {
    return undefined;
  }
  return undefined;
}
 
/**
 * Detect the "all string fields empty" sentinel emitted by
 * `get_adopted_texts({docId})` for documents that are indexed but whose
 * content has not yet been populated by the EP Open Data Portal. The server
 * returns a JSON-schema-valid response in which every string field is the
 * empty string, which bypasses standard error handling — see upstream issue
 * Hack23/European-Parliament-MCP-Server#369.
 *
 * Only treats a payload as a sentinel when it has at least three string
 * fields (to avoid false positives on intentionally sparse payloads) AND
 * all string fields are the empty string.
 *
 * @param payload - Parsed JSON payload object (or `undefined`)
 * @returns `true` when the payload matches the CONTENT_PENDING sentinel
 */
export function _isEmptyStringSentinel(payload: Record<string, unknown> | undefined): boolean {
  Iif (!payload) return false;
  let totalStringFields = 0;
  let emptyStringFields = 0;
  for (const value of Object.values(payload)) {
    Eif (typeof value === 'string') {
      totalStringFields++;
      if (value.length === 0) emptyStringFields++;
    }
  }
  return totalStringFields >= 3 && totalStringFields === emptyStringFields;
}