How HTTP Route Detection and HTTP-Calls Edge Linking Work in codebase-memory-mcp

HTTP route detection and HTTP-calls edge linking in codebase-memory-mcp work through a two-pass analysis pipeline that canonicalizes URL paths to match outgoing HTTP calls to their target route definitions, storing the results as graph edges in SQLite.

The codebase-memory-mcp repository constructs a graph-like memory model of your codebase, where symbols such as functions, files, and HTTP endpoints become nodes and their relationships become queryable edges. Understanding how HTTP route detection and HTTP-calls edge linking function is essential for mapping request flows across service boundaries and identifying which client code calls which server endpoints.

The Two-Pass Pipeline Architecture

The system processes source code in two distinct passes to build a complete picture of HTTP traffic within your application.

The first pass scans the abstract syntax tree (AST) of each file to identify route definitions using framework-specific patterns. These definitions are normalized and stored as route nodes linked to their handler functions via route edges.

The second pass examines the same AST to detect outgoing HTTP calls (fetch, axios, requests.get, etc.). Each call site is canonicalized and matched against the route index built during the first pass, creating httpcalls edges when paths align.

This separation ensures that all routes are indexed before the system attempts to link call sites, preventing false negatives from declaration ordering.

Route Detection and Canonicalization

Route discovery occurs in src/pipeline/pass_route_nodes.c, which walks the AST looking for framework-specific constructs like app.get('/api/orders', handler), router.post('/users', …), or @GetMapping("/items").

For each route declaration found, the system:

  • Extracts the HTTP method and raw path string
  • Invokes cbm_route_canon_path() to normalize the path
  • Creates a cbm_node_t with kind ROUTE storing the method, canonical path, and handler name
  • Establishes a route edge connecting the route node to its handler function node

The canonicalization logic transforms placeholder syntax into a standard format. Paths like "/users/:id", "/users/{id}", or "/users/<int:id>" all normalize to "/users/{}", stripping specific parameter names while preserving the structural pattern.

HTTP-Calls Edge Linking

The HTTP call linking implementation resides in src/pipeline/pass_httpcalls.c, specifically within the cbm_link_httpcalls() function. This pass executes after route indexing completes.

When the walker encounters an HTTP call expression, it performs the following sequence:

  1. Extracts the URL string from static literals or simple template-string interpolations
  2. Strips query strings and fragments to isolate the path component
  3. Canonicalizes the path using the same routine applied to route definitions
  4. Queries the route index for a matching canonical path
  5. Creates the edge if found: a cbm_node_t with kind HTTPCALL is instantiated and linked to the target route node via an EDGE_HTTP_CALLS edge

Calls that fail to match any known route are preserved as orphan HTTP-call nodes for later manual analysis or fuzzy matching.

/* Simplified logic from src/pipeline/pass_httpcalls.c */
if (is_http_call(node)) {
    const char *raw_url = extract_url_literal(node);
    char canon_path[256];
    canonicalise_path(raw_url, canon_path);
    cbm_node_t *call_node = cbm_node_new(HTTPCALL, ...);
    cbm_node_t *target_route = route_index_lookup(canon_path);
    if (target_route) {
        cbm_edge_new(call_node, target_route, EDGE_HTTP_CALLS);
    }
}

Why Path Canonicalization Matters

Frameworks allow multiple syntaxes for path parameters. Without normalization, a route defined as /users/:id would never match a client call to /users/{userId} despite representing the same endpoint.

The cbm_route_canon_path() function solves this by converting all parameter patterns to the uniform {} token. This enables reliable matching across language boundaries—whether your backend uses Express-style colons and your client uses template literals, the structural equivalence is preserved.

The test suite in tests/test_route_canon.c validates this behavior across colon, brace, angle-bracket, and template-string forms, ensuring consistent canonicalization regardless of source language.

Working with the Graph Programmatically

After the pipeline completes, the resulting graph persists to an on-disk SQLite3 database via src/store/arch.c. You can query this structure using the Go API or directly via the store interface.

Example: Querying routes and their callers in Go:

package main

import (
    "fmt"
    "github.com/DeusData/codebase-memory-mcp/pkg/go/cmd"
)

func main() {
    // Extract memory graph from current directory
    mem, err := cmd.Extract("./", cmd.Options{
        Languages: []string{"javascript", "python", "go"},
    })
    if err != nil {
        panic(err)
    }

    // Find specific route by handler name
    route, _ := mem.NodeByQualifiedName("myapp.handler.GetOrders")
    
    // Retrieve all HTTP call sites targeting this route
    calls := mem.Edges(route, "httpcalls")
    fmt.Printf("Found %d call sites for %s\n", len(calls), route.QualifiedName())
}

Example: Low-level C API for custom analysis:

#include "cbm_store.h"
#include "pass_httpcalls.h"

void custom_analysis(cbm_store_t *store) {
    // Create HTTP call node manually
    cbm_node_t *call = cbm_node_new(
        HTTPCALL, 
        "fetch('/api/orders')", 
        "src/client.js:12"
    );
    
    // Look up target route in the store
    cbm_node_t *route = cbm_store_lookup_route(store, "/api/orders");
    if (route) {
        cbm_edge_new(call, route, EDGE_HTTP_CALLS);
    }
    cbm_store_add_node(store, call);
}

Integration tests in tests/test_store_arch.c verify that route_count and httpcalls_count metrics reflect the expected graph structure after processing.

Summary

  • HTTP route detection occurs in src/pipeline/pass_route_nodes.c, scanning ASTs for framework-specific route declarations and creating ROUTE nodes linked to handlers.
  • HTTP-calls edge linking happens in src/pipeline/pass_httpcalls.c via cbm_link_httpcalls(), matching canonicalized call URLs against the route index to create httpcalls edges.
  • Path canonicalization via cbm_route_canon_path() normalizes parameter syntax (:id, {id}, <id>) to {}, enabling cross-language route matching.
  • Unmatched calls persist as orphan nodes rather than being discarded, supporting analysis of external or dynamic endpoints.
  • All nodes and edges persist to SQLite through src/store/arch.c, queryable via Go or C APIs.

Frequently Asked Questions

How does the system handle different framework syntaxes for route definitions?

The parser recognizes multiple framework patterns—including Express-style app.get(), Flask decorators, Spring Boot annotations, and Go HTTP handlers—extracting the method and path regardless of syntactic differences. All paths are immediately canonicalized using cbm_route_canon_path() in src/pipeline/pass_route_nodes.c, which strips framework-specific parameter syntax down to uniform {} tokens.

What happens when an HTTP call doesn't match any known route?

When cbm_link_httpcalls() fails to find a matching canonical path in the route index, it still creates a HTTPCALL node for the call site but leaves it unattached (orphan). These orphan nodes remain available in the SQLite store via src/store/arch.c for later analysis, enabling identification of calls to external services or routes defined in configuration files outside the scanned source.

Which programming languages does the HTTP route detection support?

The pipeline supports JavaScript, TypeScript, Python, and Go according to the CLI entry point in pkg/go/cmd/codebase-memory-mcp/main.go. Each language frontend produces a language-agnostic AST that pass_route_nodes.c and pass_httpcalls.c traverse uniformly, allowing the canonicalization and edge-linking logic to remain language-agnostic while the parsers handle syntax specifics.

How is the graph data persisted and queried?

All nodes and edges write to an on-disk SQLite3 database managed by src/store/arch.c. The store provides APIs for inserting nodes (cbm_store_add_node), looking up routes by canonical path (cbm_store_lookup_route), and querying edge relationships. Higher-level Go bindings in pkg/go/cmd/ wrap these primitives, enabling queries like retrieving all HTTP calls targeting a specific route node through the Edges() method.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →