Skip to main content
Glama

Graph Bridges

localnest_graph_bridges
Read-onlyIdempotent

Identify cross-nest or cross-branch bridges within a nest. Use mode and nest parameters to find entities that link different nests or branches.

Instructions

Discover cross-nest bridges (default) or cross-branch bridges within a nest. Use mode="cross-branch" with a nest to find entities that span different branches within that nest.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nestNo
modeNocross-nest
response_formatNojson

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
dataYes
metaYes

Implementation Reference

  • Core handler function that discovers bridges in the knowledge graph. Runs a SQL query to find triples whose subject and object belong to different nests (cross-nest mode) or different branches within the same nest (cross-branch mode). Returns bridge entries, insights about shared entities, and a summary.
    export async function discoverBridges(adapter: Adapter, { nest, mode }: DiscoverBridgesOpts = {}): Promise<DiscoverBridgesResult> {
      const cleanNest = nest ? cleanString(nest, 200) : null;
      const isCrossBranch = mode === 'cross-branch' && !!cleanNest;
    
      // Use LEFT JOINs so entities with NULL memory_id still participate.
      // Derive nest/branch via COALESCE: entity's own memory_id -> triple's source_memory_id.
      let sql = `
        SELECT * FROM (
          SELECT DISTINCT
            t.id AS triple_id,
            t.subject_id,
            s.name AS subject_name,
            s.entity_type AS subject_type,
            t.predicate,
            t.object_id,
            o.name AS object_name,
            o.entity_type AS object_type,
            COALESCE(NULLIF(ms1.nest,''), NULLIF(mt.nest,'')) AS subject_nest,
            COALESCE(NULLIF(mo1.nest,''), NULLIF(mt.nest,'')) AS object_nest,
            COALESCE(NULLIF(ms1.branch,''), NULLIF(mt.branch,'')) AS subject_branch,
            COALESCE(NULLIF(mo1.branch,''), NULLIF(mt.branch,'')) AS object_branch
          FROM kg_triples t
          JOIN kg_entities s ON s.id = t.subject_id
          JOIN kg_entities o ON o.id = t.object_id
          LEFT JOIN memory_entries ms1 ON ms1.id = s.memory_id
          LEFT JOIN memory_entries mo1 ON mo1.id = o.memory_id
          LEFT JOIN memory_entries mt  ON mt.id  = t.source_memory_id
          WHERE t.valid_to IS NULL
        ) AS bridges`;
    
      const params: unknown[] = [];
    
      if (isCrossBranch) {
        // Cross-branch mode: find bridges across branches within the specified nest
        sql += `
        WHERE subject_nest = ? AND object_nest = ?
          AND subject_branch != '' AND subject_branch IS NOT NULL
          AND object_branch  != '' AND object_branch  IS NOT NULL
          AND subject_branch != object_branch`;
        params.push(cleanNest, cleanNest);
      } else {
        // Default cross-nest mode
        sql += `
        WHERE subject_nest != '' AND subject_nest IS NOT NULL
          AND object_nest  != '' AND object_nest  IS NOT NULL
          AND subject_nest != object_nest`;
    
        if (cleanNest) {
          sql += `\n      AND (subject_nest = ? OR object_nest = ?)`;
          params.push(cleanNest, cleanNest);
        }
      }
    
      sql += `\n    ORDER BY subject_nest, object_nest, subject_name`;
    
      const rows = await adapter.all<BridgeRow>(sql, params);
    
      // --- Build insights from entity -> scope mapping ---
      const scopeLabel = isCrossBranch ? 'branch' : 'nest';
      const entityScopes = new Map<string, { name: string; type: string; scopes: Set<string>; predicates: Set<string> }>();
    
      for (const row of rows) {
        const bothScopes = isCrossBranch
          ? [row.subject_branch, row.object_branch]
          : [row.subject_nest, row.object_nest];
        for (const [id, name, type] of [
          [row.subject_id, row.subject_name, row.subject_type],
          [row.object_id, row.object_name, row.object_type]
        ] as [string, string, string][]) {
          let entry = entityScopes.get(id);
          if (!entry) {
            entry = { name, type, scopes: new Set(), predicates: new Set() };
            entityScopes.set(id, entry);
          }
          for (const s of bothScopes) entry.scopes.add(s);
          entry.predicates.add(row.predicate);
        }
      }
    
      const insights: string[] = [];
      for (const [, info] of entityScopes) {
        if (info.scopes.size >= 2) {
          const scopeList = [...info.scopes].sort().join(', ');
          const predList = [...info.predicates].sort().join(', ');
          insights.push(`'${info.name}' (${info.type}) bridges ${scopeLabel}es ${scopeList} via '${predList}'`);
        }
      }
    
      // --- Summary ---
      const scopePairs = new Set<string>();
      for (const row of rows) {
        const a = isCrossBranch ? row.subject_branch : row.subject_nest;
        const b = isCrossBranch ? row.object_branch : row.object_nest;
        scopePairs.add([a, b].sort().join('<->'));
      }
      const sharedCount = [...entityScopes.values()].filter(e => e.scopes.size >= 2).length;
      const noResultsMsg = isCrossBranch
        ? `No cross-branch bridges found within nest '${cleanNest}'`
        : 'No cross-nest bridges found';
      const foundMsg = isCrossBranch
        ? `Found ${rows.length} bridge(s) across ${scopePairs.size} branch pair(s) in nest '${cleanNest}' involving ${sharedCount} shared entity/entities`
        : `Found ${rows.length} bridge(s) across ${scopePairs.size} nest pair(s) involving ${sharedCount} shared entity/entities`;
      const summary = rows.length === 0 ? noResultsMsg : foundMsg;
    
      return {
        filter_nest: cleanNest,
        bridge_count: rows.length,
        bridges: rows.map((row): BridgeEntry => ({
          triple_id: row.triple_id,
          subject_id: row.subject_id,
          subject_name: row.subject_name,
          predicate: row.predicate,
          object_id: row.object_id,
          object_name: row.object_name,
          subject_nest: row.subject_nest,
          object_nest: row.object_nest,
          subject_type: row.subject_type,
          object_type: row.object_type,
          subject_branch: row.subject_branch,
          object_branch: row.object_branch
        })),
        insights,
        summary
      };
    }
  • Store-level wrapper for discoverBridges that initializes, emits before/after hooks, and delegates to the core graph function.
    async discoverBridges(args: DiscoverBridgesOpts) {
      await this.init();
      const hookResult = await this.hooks.emit('before:graph:bridges', args);
      if (hookResult.cancelled) return { cancelled: true, reason: hookResult.reason };
      const result = await discoverBridgesFn(this.adapter!, hookResult.payload as DiscoverBridgesOpts);
      await this.hooks.emit('after:graph:bridges', result);
      return result;
    }
  • Service-level wrapper that asserts the memory service is enabled and delegates to store.discoverBridges.
    async discoverBridges(args: DiscoverBridgesOpts) {
      this.assertEnabled();
      return this.store.discoverBridges(args);
    }
  • Registration of the 'localnest_graph_bridges' tool via registerJsonTool, with input schema (nest, mode), read-only annotations, and handler that calls memory.discoverBridges.
    registerJsonTool(
      ['localnest_graph_bridges'],
      {
        title: 'Graph Bridges',
        description: 'Discover cross-nest bridges (default) or cross-branch bridges within a nest. Use mode="cross-branch" with a nest to find entities that span different branches within that nest.',
        inputSchema: {
          nest: z.string().max(200).optional(),
          mode: z.enum(['cross-nest', 'cross-branch']).default('cross-nest')
        },
        annotations: READ_ONLY_ANNOTATIONS,
        outputSchema: schemas.OUTPUT_BUNDLE_RESULT_SCHEMA
      },
      async ({ nest, mode }: Record<string, unknown>) => memory.discoverBridges({ nest, mode: mode as 'cross-nest' | 'cross-branch' | undefined })
    );
  • Type definitions for DiscoverBridgesOpts (nest, mode), BridgeEntry (triple_id, subject/object details with nest/branch info), and DiscoverBridgesResult (filter_nest, bridge_count, bridges, insights, summary).
    export interface DiscoverBridgesOpts {
      nest?: string;
      /** When 'cross-branch', find bridges across branches within the given nest instead of across nests. */
      mode?: 'cross-nest' | 'cross-branch';
    }
    
    export interface BridgeEntry {
      triple_id: string;
      subject_id: string;
      subject_name: string;
      predicate: string;
      object_id: string;
      object_name: string;
      subject_nest: string;
      object_nest: string;
      subject_type?: string;
      object_type?: string;
      subject_branch?: string;
      object_branch?: string;
    }
    
    export interface DiscoverBridgesResult {
      filter_nest: string | null;
      bridge_count: number;
      bridges: BridgeEntry[];
      insights: string[];
      summary: string;
    }
Behavior4/5

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

Annotations already declare readOnly and idempotent hints; the description adds behavioral context about discovering bridges and mode-specific behavior. No contradictions.

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?

Two sentences, front-loaded with purpose. No unnecessary words. Highly concise.

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

Completeness4/5

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

With output schema present, return value explanation is unnecessary. The description covers the two modes and the key parameter usage, leaving little ambiguity for a tool of this complexity.

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

Parameters3/5

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

Schema description coverage is 0%, so description must compensate. It explains mode and the role of nest for cross-branch, but does not clarify response_format or the optionality of nest for cross-nest mode.

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?

The description clearly states the tool discovers bridges, with two modes (cross-nest and cross-branch), and distinguishes from siblings by focusing on bridges rather than traversal or other graph operations.

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

Usage Guidelines4/5

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

Provides clear context on when to use each mode, especially specifying that mode='cross-branch' requires a nest. Does not explicitly exclude alternative tools but the context is sufficient.

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/wmt-mobile/localnest'

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