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,
        };
      }
    }
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions the date format but doesn't describe what happens when no results are found, whether the search is case-sensitive, what types of documents are returned, or any rate limits or authentication requirements. For a search tool with zero annotation coverage, this is insufficient.

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 extremely concise with just two sentences that directly communicate the tool's purpose and key constraint. Every word earns its place with no wasted text, making it easy to parse quickly.

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

Completeness2/5

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

For a search tool with 3 parameters, no annotations, and no output schema, the description is inadequate. It doesn't explain what kind of results are returned, how they're structured, whether there's pagination behavior (beyond the start_record parameter), or any error conditions. The agent would have significant gaps in understanding how to use this tool effectively.

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?

Schema description coverage is 100%, so the schema already documents all three parameters thoroughly. The description adds the date format information which is already in the schema's parameter description, providing minimal additional value beyond what's already structured.

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

Purpose4/5

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

The description clearly states the action ('Search for documents') and resource ('Gallica digital library') with a specific scope ('by date'). It distinguishes from some siblings like search_by_author or search_by_title, but doesn't explicitly differentiate from advanced_search or natural_language_search which might also support date filtering.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like advanced_search, natural_language_search, or other search_by_* tools. It mentions the date format but doesn't explain when date-based searching is preferable to other search methods.

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

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