Skip to main content
Glama
jbenton

guardian-mcp-server

by jbenton

guardian_search_by_author

Find Guardian articles written by specific journalists, with options to filter by date, section, keywords, and sort results.

Instructions

Search Guardian articles by specific author/journalist

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
authorYesAuthor name to search for
queryNoAdditional search terms within author's articles
sectionNoFilter by section ID
from_dateNoStart date (YYYY-MM-DD format)
to_dateNoEnd date (YYYY-MM-DD format)
order_byNoSort order: 'newest', 'oldest', 'relevance' (default: 'newest')
page_sizeNoResults per page, max 200 (default: 20)
pageNoPage number (default: 1)

Implementation Reference

  • The core handler function that executes the tool logic: parses input params, constructs Guardian search query for articles by author, filters results by byline match, and formats output with article details.
    export async function guardianSearchByAuthor(client: GuardianClient, args: any): Promise<string> {
      const params = SearchByAuthorParamsSchema.parse(args);
    
      // Build search parameters - we'll search for the author name in the byline
      const searchParams: Record<string, any> = {
        'show-fields': 'headline,standfirst,byline,publication,firstPublicationDate,wordcount',
        'order-by': params.order_by || 'newest',
        'page-size': params.page_size || 20,
        page: params.page || 1
      };
    
      // Combine author search with optional query
      if (params.query) {
        searchParams.q = `"${params.author}" ${params.query}`;
      } else {
        searchParams.q = `"${params.author}"`;
      }
    
      if (params.section) {
        searchParams.section = params.section;
      }
      if (params.from_date) {
        const fromDate = validateDate(params.from_date);
        if (!fromDate) {
          throw new Error(`Invalid from_date format: ${params.from_date}. Use YYYY-MM-DD format.`);
        }
        searchParams['from-date'] = fromDate;
      }
      if (params.to_date) {
        const toDate = validateDate(params.to_date);
        if (!toDate) {
          throw new Error(`Invalid to_date format: ${params.to_date}. Use YYYY-MM-DD format.`);
        }
        searchParams['to-date'] = toDate;
      }
    
      const response = await client.search(searchParams);
      const articles = response.response.results;
    
      // Filter to only articles where the author name appears in the byline
      const authorArticles = articles.filter(article => {
        const byline = article.fields?.byline || '';
        return byline.toLowerCase().includes(params.author.toLowerCase());
      });
    
      if (authorArticles.length > 0) {
        const pagination = response.response;
        let result = `Found ${authorArticles.length} article(s) by ${params.author}:\n\n`;
    
        authorArticles.forEach((article, index) => {
          result += `**${index + 1}. ${article.webTitle || 'Untitled'}**\n`;
    
          if (article.fields) {
            const { fields } = article;
            
            if (fields.byline) {
              result += `By: ${fields.byline}\n`;
            }
            
            if (fields.firstPublicationDate) {
              const pubDate = fields.firstPublicationDate.substring(0, 10);
              result += `Published: ${pubDate}\n`;
            }
            
            if (fields.wordcount) {
              result += `Word count: ${fields.wordcount}\n`;
            }
            
            if (fields.standfirst) {
              result += `Summary: ${fields.standfirst}\n`;
            }
          }
    
          result += `Section: ${article.sectionName || 'Unknown'}\n`;
          result += `URL: ${article.webUrl || 'N/A'}\n\n`;
        });
    
        if (pagination.pages > 1) {
          result += `\nPagination: Page ${pagination.currentPage} of ${pagination.pages}\n`;
        }
    
        return result;
      } else {
        return `No articles found by author '${params.author}'.`;
      }
    }
  • Zod schema defining and validating the input parameters for the guardian_search_by_author tool, used in the handler for parsing args.
    export const SearchByAuthorParamsSchema = z.object({
      author: z.string(),
      query: z.string().optional(),
      section: z.string().optional(),
      from_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
      to_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
      order_by: z.enum(['newest', 'oldest', 'relevance']).optional(),
      page_size: z.number().min(1).max(200).optional(),
      page: z.number().min(1).optional(),
    });
  • Tool registration function that maps the 'guardian_search_by_author' name to the handler function, used by the MCP server.
    export function registerTools(client: GuardianClient): Record<string, ToolHandler> {
      return {
        guardian_search: (args) => guardianSearch(client, args),
        guardian_get_article: (args) => guardianGetArticle(client, args),
        guardian_longread: (args) => guardianLongread(client, args),
        guardian_lookback: (args) => guardianLookback(client, args),
        guardian_browse_section: (args) => guardianBrowseSection(client, args),
        guardian_get_sections: (args) => guardianGetSections(client, args),
        guardian_search_tags: (args) => guardianSearchTags(client, args),
        guardian_search_by_length: (args) => guardianSearchByLength(client, args),
        guardian_search_by_author: (args) => guardianSearchByAuthor(client, args),
        guardian_find_related: (args) => guardianFindRelated(client, args),
        guardian_get_article_tags: (args) => guardianGetArticleTags(client, args),
        guardian_content_timeline: (args) => guardianContentTimeline(client, args),
        guardian_author_profile: (args) => guardianAuthorProfile(client, args),
        guardian_topic_trends: (args) => guardianTopicTrends(client, args),
        guardian_top_stories_by_date: (args) => guardianTopStoriesByDate(client, args),
        guardian_recommend_longreads: (args) => guardianRecommendLongreads(client, args),
      };
  • src/index.ts:307-350 (registration)
    MCP tool listing registration including name, description, and input schema for the ListToolsRequest, advertised to MCP clients.
    name: 'guardian_search_by_author',
    description: 'Search Guardian articles by specific author/journalist',
    inputSchema: {
      type: 'object',
      properties: {
        author: {
          type: 'string',
          description: 'Author name to search for',
        },
        query: {
          type: 'string',
          description: "Additional search terms within author's articles",
        },
        section: {
          type: 'string',
          description: 'Filter by section ID',
        },
        from_date: {
          type: 'string',
          description: 'Start date (YYYY-MM-DD format)',
        },
        to_date: {
          type: 'string',
          description: 'End date (YYYY-MM-DD format)',
        },
        order_by: {
          type: 'string',
          description: "Sort order: 'newest', 'oldest', 'relevance' (default: 'newest')",
          enum: ['newest', 'oldest', 'relevance'],
        },
        page_size: {
          type: 'integer',
          description: 'Results per page, max 200 (default: 20)',
          minimum: 1,
          maximum: 200,
        },
        page: {
          type: 'integer',
          description: 'Page number (default: 1)',
          minimum: 1,
        },
      },
      required: ['author'],
    },
  • Import of helper function used for date validation in the handler.
    import { validateDate } from '../utils/formatters.js';

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/jbenton/guardian-mcp-server'

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