Skip to main content
Glama
ukicar

Gallica/BnF MCP Server

by ukicar

search_by_date

Find documents in the Gallica digital library by specifying a date. Use YYYY, YYYY-MM, or YYYY-MM-DD format to locate historical materials from the Bibliothèque nationale de France collection.

Instructions

Search for documents in the Gallica digital library by date. Accepts YYYY, YYYY-MM, or YYYY-MM-DD format.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dateYesThe date to search for (format: YYYY or YYYY-MM or YYYY-MM-DD)
max_resultsNoMaximum number of results to return (1-50)
start_recordNoStarting record for pagination

Implementation Reference

  • The main MCP tool handler for search_by_date, including the tool name, description, input schema definition, and the async handler function that executes the search by calling searchApi.searchByDate().
    export function createSearchByDateTool(searchApi: SearchAPI) {
      return {
        name: 'search_by_date',
        description: 'Search for documents in the Gallica digital library by date. Accepts YYYY, YYYY-MM, or YYYY-MM-DD format.',
        inputSchema: {
          type: 'object',
          properties: {
            date: {
              type: 'string',
              description: 'The date to search for (format: YYYY or YYYY-MM or YYYY-MM-DD)',
            },
            max_results: {
              type: 'number',
              description: 'Maximum number of results to return (1-50)',
              default: config.defaultMaxRecords,
            },
            start_record: {
              type: 'number',
              description: 'Starting record for pagination',
              default: config.defaultStartRecord,
            },
          },
          required: ['date'],
        },
        handler: async (args: unknown) => {
          const parsed = searchParamsSchema.extend({ date: z.string() }).parse(args);
          return await searchApi.searchByDate(
            parsed.date,
            parsed.max_results ?? config.defaultMaxRecords,
            parsed.start_record ?? config.defaultStartRecord
          );
        },
      };
    }
  • The core search implementation that constructs the CQL query for date search (dc.date all) and delegates to the private search method which makes the actual API call to Gallica SRU endpoint.
    /**
     * Search by date - matches Python search_by_date
     * Accepts YYYY, YYYY-MM, or YYYY-MM-DD format
     */
    searchByDate(
      date: string,
      maxResults: number = config.defaultMaxRecords,
      startRecord: number = config.defaultStartRecord
    ): Promise<SearchResult> {
      const query = `dc.date all "${date}"`;
      return this.search(query, startRecord, maxResults);
    }
  • The Zod schema definition for search parameters used by search_by_date and other search tools, validating max_results and start_record optional parameters.
    const searchParamsSchema = z.object({
      max_results: z.number().int().positive().max(50).optional(),
      start_record: z.number().int().positive().optional(),
    });
  • Tool registration in the MCP server where createSearchByDateTool is called and added to the tools array that will be registered with the MCP framework for tools/list and tools/call handlers.
    // Register search tools (7 tools matching Python)
    const searchByTitle = createSearchByTitleTool(searchApi);
    const searchByAuthor = createSearchByAuthorTool(searchApi);
    const searchBySubject = createSearchBySubjectTool(searchApi);
    const searchByDate = createSearchByDateTool(searchApi);
    const searchByDocumentType = createSearchByDocumentTypeTool(searchApi);
    const advancedSearch = createAdvancedSearchTool(searchApi);
    const naturalLanguageSearch = createNaturalLanguageSearchTool(searchApi);
    
    // Register extended item tools (4 new tools)
    const getItemDetails = createGetItemDetailsTool(itemsClient);
    const getItemPages = createGetItemPagesTool(itemsClient);
    const getPageImage = createGetPageImageTool(iiifClient);
    const getPageText = createGetPageTextTool(textClient);
    
    // Register sequential reporting tool
    const sequentialReporting = createSequentialReportingTool(reportingServer);
    
    // Register all tools with error handling
    const tools = [
      searchByTitle,
      searchByAuthor,
      searchBySubject,
      searchByDate,
      searchByDocumentType,
      advancedSearch,
      naturalLanguageSearch,
      getItemDetails,
      getItemPages,
      getPageImage,
      getPageText,
      sequentialReporting,
    ];
  • The private core search method that actually executes the HTTP request to the Gallica SRU API and parses the XML response, used by searchByDate and all other search methods.
    private async search(
      query: string,
      startRecord: number = config.defaultStartRecord,
      maxRecords: number = config.defaultMaxRecords
    ): Promise<SearchResult> {
      logger.info(`[SEARCH] Executing search query: "${query}" (startRecord: ${startRecord}, maxRecords: ${maxRecords})`);
      const params = {
        version: '1.2',
        operation: 'searchRetrieve',
        query,
        startRecord: String(startRecord),
        maximumRecords: String(Math.min(maxRecords, 50)), // Cap at 50 like Python
      };
    
      try {
        logger.debug(`[SEARCH] Calling Gallica SRU API with params:`, params);
        const xmlBody = await this.httpClient.getXml(this.sruUrl, params);
        logger.debug(`[SEARCH] Received XML response, length: ${xmlBody.length} bytes`);
        const result = this.parseSruResponse(xmlBody, query);
        logger.info(`[SEARCH] Search completed: ${result.records.length} records returned out of ${result.metadata.total_records} total`);
        return result;
      } catch (error) {
        logger.error(`[SEARCH] Error during Gallica API request: ${error instanceof Error ? error.message : String(error)}`);
        logger.error(`[SEARCH] Error stack:`, error instanceof Error ? error.stack : 'No stack trace');
        return {
          metadata: {
            query,
            total_records: '0',
            records_returned: 0,
            date_retrieved: new Date().toISOString().replace('T', ' ').substring(0, 19),
          },
          records: [],
          error: error instanceof Error ? error.message : String(error),
          parameters: params,
        };
      }
    }

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/ukicar/sweet-bnf'

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