Skip to main content
Glama

search_by_links

Identify and retrieve notes based on their link relationships—find notes that link to specific references, are linked from others, contain external domains, or have broken internal links using Flint Note's MCP server tool.

Instructions

Search for notes based on their link relationships

Input Schema

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

Input Schema (JSON Schema)

{ "properties": { "broken_links": { "description": "Find notes with broken internal links", "type": "boolean" }, "external_domains": { "description": "Find notes with external links to these domains", "items": { "type": "string" }, "type": "array" }, "has_links_to": { "description": "Find notes that link to any of these notes", "items": { "type": "string" }, "type": "array" }, "linked_from": { "description": "Find notes that are linked from any of these notes", "items": { "type": "string" }, "type": "array" } }, "type": "object" }

Implementation Reference

  • The core handler function that implements the search_by_links tool. It validates arguments, connects to the database, and executes SQL queries based on different link criteria (outgoing links, incoming links, external domains, broken links), returning matching notes.
    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 }; } };
  • Defines the input schema, description, and parameters for the search_by_links tool.
    { 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' }, vault_id: { type: 'string', description: 'Optional vault ID to search in. If not provided, uses the current active vault.' } } } },
  • Registers the search_by_links tool in the MCP server's CallToolRequestSchema handler by mapping it to the LinkHandlers.handleSearchByLinks method.
    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; } );
  • Provides argument validation rules for search_by_links, including custom validators for note identifiers 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