Skip to main content
Glama

search_nodes

Find entities and relations by semantic similarity to search queries, enabling semantic search for information retrieval.

Instructions

Search for entities and relations by semantic similarity.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query string.
topKNoMax number of results to return.
thresholdNoDistance threshold for semantic filtering.

Implementation Reference

  • Main handler implementation for search_nodes tool. Embeds the query, performs semantic vector search on entities, filters by similarity threshold, applies advanced relevance scoring, and returns top entities with their relations.
    async searchNodes({ query, topK = 10, threshold = 0.75, includeScoreDetails = false, scoringProfile = 'balanced' }) { try { const [ rawVectorBuf ] = await this.embedTexts([ query ]); const rawVector = Array.from(new Float32Array(rawVectorBuf.buffer, rawVectorBuf.byteOffset, rawVectorBuf.byteLength / 4)); const unitVector = normalizeVector(rawVector); const limit = Math.max(topK * 2, topK + 5); const rows = await this.#repository.semanticSearch(unitVector, limit); const ids = rows .filter(r => Number(r.similarity) >= Number(threshold)) .slice(0, topK) .map(r => r.entity_id); if (!ids.length) { return { entities: [], relations: [] } } return this.#applyScoring(ids, query, includeScoreDetails, scoringProfile); } catch (error) { console.error(`Search error:`, error?.message ?? error); throw error; } function normalizeVector(v) { let sum = 0; for (let i = 0; i < v.length; i += 1) { sum += v[i] * v[i]; } const norm = Math.sqrt(sum) if (!isFinite(norm) || norm === 0) { return v; } const out = new Array(v.length) for (let i = 0; i < v.length; i += 1) { out[i] = v[i] / norm; } return out; } }
  • src/server.js:175-200 (registration)
    Registration of the search_nodes tool in the MCP server, defining name, description, Zod input schema (query, topK, threshold), and async handler that invokes KnowledgeGraphManager.searchNodes and returns JSON response.
    // Tool: search_nodes this.tool( 'search_nodes', 'Search for entities and relations by semantic similarity.', { query: z.string().describe('Search query string.'), topK: z.number().int().min(1).max(100) .optional() .default(8) .describe('Max number of results to return.'), threshold: z.number().min(0).max(1) .optional() .default(0.35) .describe('Distance threshold for semantic filtering.') }, async (args) => ({ content: [{ type: 'text', text: JSON.stringify( await this.#knowledgeGraphManager.searchNodes(args), null, 2 ) }] }) );
  • Zod schema definition for search_nodes tool inputs: query (string), topK (int 1-100 default 8), threshold (float 0-1 default 0.35).
    query: z.string().describe('Search query string.'), topK: z.number().int().min(1).max(100) .optional() .default(8) .describe('Max number of results to return.'), threshold: z.number().min(0).max(1) .optional() .default(0.35) .describe('Distance threshold for semantic filtering.') },
  • Helper method called by searchNodes to apply contextual relevance scoring: fetches details, prepares context, scores via SearchContextManager, updates access stats, and merges scores with full graph details.
    async #applyScoring(entityIds, query, includeScoreDetails, scoringProfile) { if (!entityIds?.length) { return { entities: [], relations: [] }; } const entityData = await this.#repository.fetchEntitiesWithDetails(entityIds); const normalized = entityData.map(row => ({ ...row, entity_id: String(row.entity_id) })); const searchContext = await this.#searchContextManager.prepareSearchContext(query, { contextSize: 5, preloadDepth: 2 }); const scored = await this.#searchContextManager.scoreSearchResults(normalized, searchContext, { includeComponents: includeScoreDetails, scoringProfile }); scored.sort((a, b) => (b.score || 0) - (a.score || 0)); const foundIds = scored.map(row => Number(row.entity_id)); if (foundIds.length) { await this.#searchContextManager.updateAccessStats(foundIds); } const entityNames = scored.map(row => row.name); const fullDetails = await this.openNodes(entityNames); if (includeScoreDetails) { const withScores = fullDetails.entities.map((entity, index) => ({ ...entity, score: scored[index]?.score, scoreComponents: scored[index]?.scoreComponents })); return { entities: withScores, relations: fullDetails.relations }; } return fullDetails; }

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/iAchilles/memento'

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