Skip to main content
Glama

search_nodes

Find entities and relations by keyword or semantic similarity using hybrid search. Specify query, mode, and threshold to retrieve relevant results from the Memento MCP server.

Instructions

Search for entities and relations by keyword or semantic similarity. Supports hybrid mode.

Input Schema

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

Implementation Reference

  • Core handler function performing semantic embedding search on observations, cosine similarity filtering, and relevance re-ranking using context-aware scoring.
    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:176-199 (registration)
    Registers the MCP tool 'search_nodes' with input schema validation using Zod and delegates execution to KnowledgeGraphManager.searchNodes.
    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 defining input parameters: query (string), topK (number, default 8), threshold (number, 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.') },
  • Private helper method that fetches entity details, prepares search context, applies relevance scoring, 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