search-marginalia
Discover non-commercial and independent web content using Marginalia Search. Retrieve unique sites with URLs, titles, and descriptions by specifying a search query, index, and result count.
Instructions
Search the web using Marginalia Search
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Number of results to return | |
| index | No | Search index (corresponds to dropdown in main GUI) | |
| query | Yes | Search query |
Implementation Reference
- src/index.ts:72-118 (handler)The main handler function for the 'search-marginalia' tool. It validates the tool name, destructures input arguments, makes an HTTP request to the Marginalia API, processes the response, and returns formatted results as text content. Includes comprehensive error handling for rate limits and other API errors.server.setRequestHandler(CallToolRequestSchema, async (request: { params: { name: string; arguments?: any } }) => { if (request.params.name !== "search-marginalia") { throw new McpError(ErrorCode.MethodNotFound, "Unknown tool"); } const { query, index = 0, count = 10 } = request.params.arguments as { query: string; index?: number; count?: number; }; try { const url = `${BASE_URL}/${API_KEY}/search/${encodeURIComponent(query)}`; const params = { index, count }; const response = await axios.get<MarginaliaResponse>(url, { params }); return { content: [{ type: "text", text: JSON.stringify({ query: response.data.query, license: response.data.license, results: response.data.results.map(result => ({ url: result.url, title: result.title, description: result.description })) }, null, 2) }] }; } catch (error) { if (axios.isAxiosError(error)) { if (error.response?.status === 503) { throw new McpError( ErrorCode.InvalidRequest, "Rate limit exceeded. Consider requesting a dedicated API key from kontakt@marginalia.nu" ); } throw new McpError( ErrorCode.InternalError, `Search failed: ${error.response?.data?.message || error.message}` ); } throw error; } });
- src/index.ts:46-66 (schema)Input schema definition for the 'search-marginalia' tool, specifying the expected parameters: query (required string), optional index (number >=0), and count (number 1-100).inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query" }, index: { type: "number", description: "Search index (corresponds to dropdown in main GUI)", minimum: 0 }, count: { type: "number", description: "Number of results to return", minimum: 1, maximum: 100 } }, required: ["query"] }
- src/index.ts:40-70 (registration)Registration of the 'search-marginalia' tool via the ListToolsRequestSchema handler, which returns the tool's name, description, and input schema.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "search-marginalia", description: "Search the web using Marginalia Search", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query" }, index: { type: "number", description: "Search index (corresponds to dropdown in main GUI)", minimum: 0 }, count: { type: "number", description: "Number of results to return", minimum: 1, maximum: 100 } }, required: ["query"] } } ] }; });
- src/index.ts:16-26 (helper)TypeScript interfaces defining the structure of Marginalia search results and API response, used in the handler for type safety.interface SearchResult { url: string; title: string; description: string; } interface MarginaliaResponse { query: string; license: string; results: SearchResult[]; }
- src/index.ts:13-14 (helper)Constants for Marginalia API configuration: API key from environment or default 'public', and base URL for search endpoint.const API_KEY = process.env.MARGINALIA_API_KEY || 'public'; const BASE_URL = 'https://api.marginalia.nu';