search_rfcs
Search for IETF RFC documents using keywords to find technical specifications and standards.
Instructions
Search for RFCs by keyword
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search keyword or phrase | |
| limit | No | Maximum number of results to return |
Implementation Reference
- src/services/rfcService.ts:72-153 (handler)Core handler function that implements the search logic by querying the RFC Editor search endpoint, parsing the HTML response with JSDOM, extracting RFC metadata from the results table, and returning an array of RfcMetadata objects.async searchRfcs(keyword: string): Promise<RfcMetadata[]> { try { // Search on the RFC Editor website const searchUrl = `https://www.rfc-editor.org/search/rfc_search_detail.php?title=${encodeURIComponent(keyword)}&pubstatus%5B%5D=Any&pub_date_type=any`; const response = await axios.get(searchUrl); const dom = new JSDOM(response.data); const document = dom.window.document; // Extract search results const results: RfcMetadata[] = []; // The results are in a table with class 'gridtable' const resultsTable = document.querySelector('table.gridtable'); if (!resultsTable) { // If we can't find the gridtable, look for any table after the results count const resultNodes = Array.from(document.querySelectorAll('p')).filter( node => node.textContent?.includes('results') && /\d+\s+results/.test(node.textContent) ); if (resultNodes.length === 0) return results; } // Get all rows from the results table const rows = resultsTable?.querySelectorAll('tr'); if (!rows || rows.length <= 1) return results; // Skip the header row for (let i = 1; i < rows.length; i++) { const row = rows[i]; const cells = row.querySelectorAll('td'); if (cells.length >= 5) { // Extract RFC number from first column const rfcLinkElement = cells[0].querySelector('a'); if (!rfcLinkElement) continue; // Get RFC number from text content let rfcNumber = ''; const rfcTextContent = rfcLinkElement.textContent?.trim() || ''; const rfcMatch = rfcTextContent.match(/RFC\s*(\d+)/i); if (rfcMatch && rfcMatch[1]) { rfcNumber = rfcMatch[1]; } if (!rfcNumber) continue; // Title is in the third column const title = cells[2].textContent?.trim() || ''; // Authors are in the fourth column const authorsText = cells[3].textContent?.trim() || ''; const authors = authorsText ? [authorsText] : []; // Date is in the fifth column const date = cells[4].textContent?.trim() || ''; // Status is in the seventh column const status = cells[6]?.textContent?.trim() || ''; // Get URL from the link in the first column const url = rfcLinkElement.getAttribute('href') || `https://www.rfc-editor.org/info/rfc${rfcNumber}`; results.push({ number: rfcNumber, title, authors, date, status, abstract: '', // Would need to fetch the full RFC to get this url }); } } return results; } catch (error) { console.error('Error in searchRfcs:', error); return []; // Return empty array instead of throwing } }
- src/services/rfcService.ts:4-12 (schema)Type definition for the RFC metadata returned by the searchRfcs tool.interface RfcMetadata { number: string; title: string; authors: string[]; date: string; status: string; abstract: string; url: string; }
- src/index.ts:148-167 (registration)Tool registration in the ListTools handler, including name, description, and input schema definition.name: 'search_rfcs', description: 'Search for RFCs by keyword', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search keyword or phrase', }, limit: { type: 'number', description: 'Maximum number of results to return', default: 10, }, }, required: ['query'], additionalProperties: false, }, }, {
- src/index.ts:246-279 (registration)MCP CallToolRequestSchema handler case for 'search_rfcs', which validates input, calls the rfcService.searchRfcs, applies limit, and formats the response.case 'search_rfcs': { if (typeof typedArgs.query !== 'string') { throw new McpError( ErrorCode.InvalidParams, 'Search query must be a string' ); } const limit = typeof typedArgs.limit === 'number' ? typedArgs.limit : 10; try { const results = await rfcService.searchRfcs(typedArgs.query); const limitedResults = results.slice(0, limit); return { content: [ { type: 'text', text: JSON.stringify(limitedResults, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error searching for RFCs: ${error}`, }, ], isError: true, }; } }