Skip to main content
Glama

search_by_links

Find notes in your vault by analyzing link relationships. Search for notes that link to specific content, are linked from other notes, contain external domain links, or have broken internal connections.

Instructions

Search for notes based on their link relationships

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
has_links_toNoFind notes that link to any of these notes
linked_fromNoFind notes that are linked from any of these notes
external_domainsNoFind notes with external links to these domains
broken_linksNoFind notes with broken internal links

Implementation Reference

  • The primary handler function for the 'search_by_links' tool. It validates arguments, resolves the vault context, executes SQL queries based on link criteria (has_links_to, linked_from, external_domains, broken_links), and returns JSON results or error.
    handleSearchByLinks = async (args: { has_links_to?: string[]; linked_from?: string[]; external_domains?: string[]; broken_links?: boolean; vault_id?: string; }) => { try { // Validate arguments validateToolArgs('search_by_links', args); const { hybridSearchManager } = await this.resolveVaultContext(args.vault_id); const db = await hybridSearchManager.getDatabaseConnection(); let notes: NoteRow[] = []; // Handle different search criteria if (args.has_links_to && args.has_links_to.length > 0) { // Find notes that link to any of the specified notes const targetIds = args.has_links_to.map(id => this.generateNoteIdFromIdentifier(id) ); const placeholders = targetIds.map(() => '?').join(','); notes = await db.all( `SELECT DISTINCT n.* FROM notes n INNER JOIN note_links nl ON n.id = nl.source_note_id WHERE nl.target_note_id IN (${placeholders})`, targetIds ); } else if (args.linked_from && args.linked_from.length > 0) { // Find notes that are linked from any of the specified notes const sourceIds = args.linked_from.map(id => this.generateNoteIdFromIdentifier(id) ); const placeholders = sourceIds.map(() => '?').join(','); notes = await db.all( `SELECT DISTINCT n.* FROM notes n INNER JOIN note_links nl ON n.id = nl.target_note_id WHERE nl.source_note_id IN (${placeholders})`, sourceIds ); } else if (args.external_domains && args.external_domains.length > 0) { // Find notes with external links to specified domains const domainConditions = args.external_domains .map(() => 'el.url LIKE ?') .join(' OR '); const domainParams = args.external_domains.map(domain => `%${domain}%`); notes = await db.all( `SELECT DISTINCT n.* FROM notes n INNER JOIN external_links el ON n.id = el.note_id WHERE ${domainConditions}`, domainParams ); } else if (args.broken_links) { // Find notes with broken internal links notes = await db.all( `SELECT DISTINCT n.* FROM notes n INNER JOIN note_links nl ON n.id = nl.source_note_id WHERE nl.target_note_id IS NULL` ); } return { content: [ { type: 'text', text: JSON.stringify( { success: true, notes: notes, count: notes.length }, null, 2 ) } ] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { content: [ { type: 'text', text: JSON.stringify( { success: false, error: errorMessage }, null, 2 ) } ], isError: true }; } };
  • Registration of the 'search_by_links' tool handler in the MCP server's CallToolRequestSchema switch statement, mapping tool calls to LinkHandlers.handleSearchByLinks.
    case 'search_by_links': return await this.linkHandlers.handleSearchByLinks( args as unknown as { has_links_to?: string[]; linked_from?: string[]; external_domains?: string[]; broken_links?: boolean; vault_id?: string; } );
  • Input schema definition for the 'search_by_links' tool, returned by ListToolsRequestSchema handler, defining parameters and descriptions.
    { name: 'search_by_links', description: 'Search for notes based on their link relationships', inputSchema: { type: 'object', properties: { has_links_to: { type: 'array', items: { type: 'string' }, description: 'Find notes that link to any of these notes' }, linked_from: { type: 'array', items: { type: 'string' }, description: 'Find notes that are linked from any of these notes' }, external_domains: { type: 'array', items: { type: 'string' }, description: 'Find notes with external links to these domains' }, broken_links: { type: 'boolean', description: 'Find notes with broken internal links' } } } },
  • Validation rules used by validateToolArgs('search_by_links', args) in the handler, including custom validators for identifier formats in arrays.
    search_by_links: [ { field: 'has_links_to', required: false, type: 'array', arrayItemType: 'string', allowEmpty: true, customValidator: (value: any) => { if (!Array.isArray(value)) return null; for (const identifier of value) { if (!identifier.includes('/')) { return `identifier "${identifier}" must be in format "type/filename"`; } const parts = identifier.split('/'); if (parts.length !== 2 || !parts[0] || !parts[1]) { return `identifier "${identifier}" must be in format "type/filename" with both parts non-empty`; } } return null; } }, { field: 'linked_from', required: false, type: 'array', arrayItemType: 'string', allowEmpty: true, customValidator: (value: any) => { if (!Array.isArray(value)) return null; for (const identifier of value) { if (!identifier.includes('/')) { return `identifier "${identifier}" must be in format "type/filename"`; } const parts = identifier.split('/'); if (parts.length !== 2 || !parts[0] || !parts[1]) { return `identifier "${identifier}" must be in format "type/filename" with both parts non-empty`; } } return null; } }, { field: 'external_domains', required: false, type: 'array', arrayItemType: 'string', allowEmpty: true }, { field: 'broken_links', required: false, type: 'boolean' }, { field: 'vault_id', required: false, type: 'string', allowEmpty: false } ],

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/disnet/flint-note'

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