Skip to main content
Glama

Graph Query

graph_query
Read-only

Query the memory graph using an entity's canonical name to retrieve matching nodes, edges, weights, and source provenance. Use when you have the exact or near-canonical entity name.

Instructions

Query the memory graph by canonical entity name. Use when you know the entity name or close-to-canonical form (e.g. "Steve", "graph-memory"); for natural-language phrasing or synonyms (e.g. "the knowledge graph project") prefer graph_search. Returns up to limit matching nodes plus the edges that connect them within max_hops, with per-edge weight and source provenance.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
entitiesYesEntity names to search for
entity_typesNoFilter results to these entity types
max_hopsNoMax traversal depth (default: 2)
min_weightNoMin edge weight to traverse (default: 0.3)
limitNoMax results (default: 20)
project_contextNoProject directory or name for affinity scoring
context_levelNoResponse detail level (default: full)full
current_onlyNoOnly current facts, exclude superseded (default: true)

Implementation Reference

  • Tool registration for graph_query via server.registerTool, with inputSchema defined using zod schemas, annotations, and the async handler function that calls client.query()
    // ─── Tool: graph_query ───
    
    server.registerTool("graph_query", {
      title: "Graph Query",
      description:
        "Query the memory graph by canonical entity name. Use when you know the entity name or close-to-canonical form (e.g. \"Steve\", \"graph-memory\"); for natural-language phrasing or synonyms (e.g. \"the knowledge graph project\") prefer graph_search. Returns up to `limit` matching nodes plus the edges that connect them within `max_hops`, with per-edge weight and source provenance.",
      inputSchema: {
        entities: z.array(z.string()).describe("Entity names to search for"),
        entity_types: z.array(z.string()).optional().describe("Filter results to these entity types"),
        max_hops: z.number().optional().default(2).describe("Max traversal depth (default: 2)"),
        min_weight: z.number().optional().default(0.3).describe("Min edge weight to traverse (default: 0.3)"),
        limit: z.number().optional().default(20).describe("Max results (default: 20)"),
        project_context: z.string().optional().describe("Project directory or name for affinity scoring"),
        context_level: z.enum(["minimal", "full", "relations-only"]).optional().default("full").describe("Response detail level (default: full)"),
        current_only: z.boolean().optional().default(true).describe("Only current facts, exclude superseded (default: true)"),
      },
      annotations: { readOnlyHint: true },
    }, async (args) => {
      try {
        const result = await client.query(currentTenant(), args.entities, {
          entity_types: args.entity_types as EntityType[] | undefined,
          max_hops: args.max_hops,
          min_weight: args.min_weight,
          limit: args.limit,
          project_context: args.project_context,
          current_only: args.current_only,
        });
    
        if (args.context_level === "minimal") {
          return toolResult({
            nodes: result.nodes.map((n) => ({
              id: n.id, type: n.type, name: n.name, confidence: n.confidence,
            })),
            edge_count: result.edges.length,
          });
        }
    
        if (args.context_level === "relations-only") {
          return toolResult({
            nodes: result.nodes.map((n) => ({
              id: n.id, type: n.type, name: n.name,
            })),
            edges: result.edges,
          });
        }
    
        return toolResult(result);
      } catch (err) {
        return toolError(`graph_query failed: ${err instanceof Error ? err.message : String(err)}`);
      }
    });
  • The async handler function for graph_query that receives args, calls client.query() with tenant-scoped parameters, and processes context_level (minimal/full/relations-only) formatting of the result
    }, async (args) => {
      try {
        const result = await client.query(currentTenant(), args.entities, {
          entity_types: args.entity_types as EntityType[] | undefined,
          max_hops: args.max_hops,
          min_weight: args.min_weight,
          limit: args.limit,
          project_context: args.project_context,
          current_only: args.current_only,
        });
    
        if (args.context_level === "minimal") {
          return toolResult({
            nodes: result.nodes.map((n) => ({
              id: n.id, type: n.type, name: n.name, confidence: n.confidence,
            })),
            edge_count: result.edges.length,
          });
        }
    
        if (args.context_level === "relations-only") {
          return toolResult({
            nodes: result.nodes.map((n) => ({
              id: n.id, type: n.type, name: n.name,
            })),
            edges: result.edges,
          });
        }
    
        return toolResult(result);
      } catch (err) {
        return toolError(`graph_query failed: ${err instanceof Error ? err.message : String(err)}`);
      }
    });
  • Input schema definition for graph_query: entities (required array), entity_types, max_hops, min_weight, limit, project_context, context_level, current_only with defaults and descriptions
    inputSchema: {
      entities: z.array(z.string()).describe("Entity names to search for"),
      entity_types: z.array(z.string()).optional().describe("Filter results to these entity types"),
      max_hops: z.number().optional().default(2).describe("Max traversal depth (default: 2)"),
      min_weight: z.number().optional().default(0.3).describe("Min edge weight to traverse (default: 0.3)"),
      limit: z.number().optional().default(20).describe("Max results (default: 20)"),
      project_context: z.string().optional().describe("Project directory or name for affinity scoring"),
      context_level: z.enum(["minimal", "full", "relations-only"]).optional().default("full").describe("Response detail level (default: full)"),
      current_only: z.boolean().optional().default(true).describe("Only current facts, exclude superseded (default: true)"),
    },
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond readOnlyHint annotation, description details return structure: 'Returns up to `limit` matching nodes plus the edges... within `max_hops`, with per-edge weight and source provenance'. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with clear front-loading of purpose, usage guidance, and result description. No redundant or extraneous information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 8 parameters, high schema coverage, and readOnlyHint annotation, description sufficiently covers behavior, query method, filtering, and output. Adequate for an AI agent to select and invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. Description adds value by contextualizing parameters (e.g., tying `limit` and `max_hops` to the result shape), but does not significantly elaborate beyond schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Query the memory graph by canonical entity name', a specific verb+resource. It distinguishes from sibling graph_search by explaining when to use each: canonical names vs natural-language phrases.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use when you know the entity name or close-to-canonical form' and 'for natural-language phrasing or synonyms prefer graph_search', providing clear context and alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/stevepridemore/graph-memory'

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