{"url_pattern":"^https?://(www\\.)?reuters\\.com(/.*)?$","site_name":"reuters","allowed_domains":["reuters.com"],"tools":[{"name":"reuters_search","description":"Reuters 路透社新闻搜索","inputSchema":{"type":"object","properties":{"query":{"type":"string","description":"Search query"},"count":{"type":"string","description":"Max results to return (default 10)"}},"required":["query"]},"handler":"(params) => {\n  const run = async function(args) {\n\n      if (!args.query) return {error: 'Missing argument: query', hint: 'Provide a search query string'};\n      const count = Math.min(parseInt(args.count) || 10, 40);\n\n      // Strategy 1: Try Reuters Arc API (works when browser has valid session)\n      const apiQuery = JSON.stringify({\n        keyword: args.query,\n        offset: 0,\n        orderby: 'display_date:desc',\n        size: count,\n        website: 'reuters'\n      });\n      const apiUrl = 'https://www.reuters.com/pf/api/v3/content/fetch/articles-by-search-v2?query=' + encodeURIComponent(apiQuery);\n\n      try {\n        const apiResp = await fetch(apiUrl, {credentials: 'include'});\n        if (apiResp.ok) {\n          const data = await apiResp.json();\n          const articles = (data.result?.articles || data.articles || []);\n          if (articles.length > 0) {\n            const results = articles.slice(0, count).map(a => ({\n              title: a.title || a.headlines?.basic || '',\n              description: a.description?.basic || a.description || a.subheadlines?.basic || '',\n              date: a.display_date || a.published_time || a.first_publish_date || '',\n              url: a.canonical_url\n                ? 'https://www.reuters.com' + a.canonical_url\n                : (a.website_url ? 'https://www.reuters.com' + a.website_url : ''),\n              section: a.taxonomy?.section?.name || a.section?.name || '',\n              authors: (a.authors || []).map(au => au.name).filter(Boolean).join(', ')\n            }));\n            return {query: args.query, source: 'api', count: results.length, results};\n          }\n        }\n      } catch (e) {\n        // API failed, fall through to HTML parsing\n      }\n\n      // Strategy 2: Parse HTML search results page\n      const searchUrl = 'https://www.reuters.com/site-search/?query=' + encodeURIComponent(args.query);\n      const resp = await fetch(searchUrl, {credentials: 'include'});\n      if (!resp.ok) return {error: 'HTTP ' + resp.status, hint: 'Make sure a reuters.com tab is open so cookies are available'};\n      const html = await resp.text();\n      const parser = new DOMParser();\n      const doc = parser.parseFromString(html, 'text/html');\n\n      const results = [];\n      const seen = new Set();\n\n      // Reuters search results are rendered as media-story cards or search result items\n      // Try structured selectors first\n      const cards = doc.querySelectorAll('[class*=\"search-result\"], [class*=\"media-story\"], [data-testid*=\"search\"], li[class*=\"story\"], article');\n      cards.forEach(card => {\n        if (results.length >= count) return;\n        const anchor = card.querySelector('a[href]');\n        if (!anchor) return;\n        const href = anchor.getAttribute('href') || '';\n        const fullUrl = href.startsWith('http') ? href : 'https://www.reuters.com' + href;\n        if (seen.has(fullUrl)) return;\n        if (!href.includes('/') || href === '/') return;\n\n        const heading = card.querySelector('h3, h2, h4, [data-testid*=\"Heading\"], span[class*=\"title\"]');\n        const title = heading ? heading.textContent.trim() : anchor.textContent.trim();\n        if (!title || title.length < 5) return;\n\n        let description = '';\n        const pTags = card.querySelectorAll('p, [class*=\"description\"], [class*=\"snippet\"]');\n        for (const p of pTags) {\n          const txt = p.textContent.trim();\n          if (txt.length > 15 && txt !== title) {\n            description = txt.substring(0, 500);\n            break;\n          }\n        }\n\n        let date = '';\n        const timeEl = card.querySelector('time, [class*=\"date\"], [class*=\"time\"]');\n        if (timeEl) {\n          date = timeEl.getAttribute('datetime') || timeEl.textContent.trim();\n        }\n\n        seen.add(fullUrl);\n        results.push({title, description, date, url: fullUrl});\n      });\n\n      // Fallback: broad link scan if structured selectors found nothing\n      if (results.length === 0) {\n        const links = doc.querySelectorAll('a[href]');\n        links.forEach(a => {\n          if (results.length >= count) return;\n          const href = a.getAttribute('href') || '';\n          // Keep only article-like paths\n          if (!(href.includes('/world/') || href.includes('/business/') || href.includes('/markets/') ||\n                href.includes('/technology/') || href.includes('/science/') || href.includes('/sports/') ||\n                href.includes('/legal/') || href.includes('/sustainability/'))) return;\n          const fullUrl = href.startsWith('http') ? href : 'https://www.reuters.com' + href;\n          if (seen.has(fullUrl)) return;\n\n          const heading = a.querySelector('h1, h2, h3, h4, span');\n          const title = heading ? heading.textContent.trim() : a.textContent.trim();\n          if (!title || title.length < 8) return;\n\n          seen.add(fullUrl);\n\n          let description = '';\n          const parent = a.closest('li, div, article, section');\n          if (parent) {\n            const pTags = parent.querySelectorAll('p');\n            for (const p of pTags) {\n              const txt = p.textContent.trim();\n              if (txt.length > 15 && txt !== title) {\n                description = txt.substring(0, 500);\n                break;\n              }\n            }\n          }\n\n          results.push({title, description, url: fullUrl});\n        });\n      }\n\n      if (results.length === 0) {\n        return {query: args.query, count: 0, results: [], hint: 'No results found. Ensure reuters.com is open in a browser tab and you are not blocked by captcha.'};\n      }\n\n      return {query: args.query, source: 'html', count: results.length, results};\n  };\n  return run(params || {});\n}"}]}