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

> Discover how HTTP route detection and HTTP-calls edge linking work in codebase-memory-mcp. Learn about the two-pass analysis pipeline for matching URL paths to route definitions.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: deep-dive
- Published: 2026-07-30

---

**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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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.

```c
/* 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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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:**

```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:**

```c
#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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/pkg/go/cmd/codebase-memory-mcp/main.go). Each language frontend produces a language-agnostic AST that [`pass_route_nodes.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/pass_route_nodes.c) and [`pass_httpcalls.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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.