Repository navigation
Description
Version
codebase-memory-mcp 0.12.0
Platform
Linux (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
ui
What happened, and what did you expect?
Indexing a Java client that calls a Java server produces HTTP_CALLS edges only when the HTTP client is
constructed inline at the call site (new RestTemplate().getForObject("/v1/orders", …)) and the URL is a
literal or an expr + "literal" concatenation. Three common production shapes produce no HTTP_CALLS edge:
- the client is an injected field, parameter or local whose type comes from a jar
(private final RestTemplate restTemplate;), or an in-house wrapper around such a client; - the URL is a formatted string (
"%s/challenges/%s/verified/%s".formatted(base, id, token)); - the URL goes into a request builder and the request is dispatched by a later call
(like for OkHttpnew Request.Builder().url("/v1/orders")…client.newCall(request).execute())
Expected: see the table under "Result vs expected" in the Reproduction section.
Nearest existing issues, none covering Java: #706 , #1147, #1009.
Reproduction
1. Code. Two dummy repos
Client repo /tmp/cbm-java-http-client, all files under src/main/java/com/acme/client/:
// InlineClient.java (control: these two DO produce HTTP_CALLS)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class InlineClient {
public String literal() {
return new RestTemplate().getForObject("/v1/orders", String.class);
}
public String concat(String baseUrl) {
return new RestTemplate().getForObject(baseUrl + "/challenges/state", String.class);
}
}// JarFieldClient.java (gap 1: jar-typed field; `verified` also hits gap 2)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class JarFieldClient {
private final RestTemplate restTemplate;
public JarFieldClient(RestTemplate restTemplate) { this.restTemplate = restTemplate; }
public String orders() {
return restTemplate.getForObject("/v1/orders", String.class);
}
public String verified(String baseUrl, String challengeId, String token) {
return restTemplate.getForObject("%s/challenges/%s/verified/%s".formatted(baseUrl, challengeId, token), String.class);
}
}// LocalVarClient.java (gap 1: jar-typed parameter and local)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class LocalVarClient {
public String orders(RestTemplate rt) {
return rt.getForObject("/v1/orders", String.class);
}
public String byId(RestTemplate rt) {
var t = rt;
return t.getForObject("/v1/orders/{id}", String.class, "42");
}
}// WrapperClient.java (gap 1: in-house wrapper type from a jar; build() returns a RestTemplate)
package com.acme.client;
import com.acme.http.AcmeHttpClientBuilder;
public class WrapperClient {
private final AcmeHttpClientBuilder builder;
public WrapperClient(AcmeHttpClientBuilder builder) { this.builder = builder; }
public String orders() {
return builder.build().getForObject("/v1/orders", String.class);
}
}// FormatInlineClient.java (gap 2 alone: inline client, format-string URL)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class FormatInlineClient {
public String verified(String baseUrl, String challengeId, String token) {
return new RestTemplate().getForObject("%s/challenges/%s/verified/%s".formatted(baseUrl, challengeId, token), String.class);
}
}// OkClient.java (gap 3 alone: inline client, URL into a builder, dispatched by a later call)
package com.acme.client;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkClient {
public Response orders() throws Exception {
Request request = new Request.Builder().url("/v1/orders").get().build();
return new OkHttpClient().newCall(request).execute();
}
}Server repo /tmp/cbm-java-server, under src/main/java/com/acme/server/ (JAX-RS; indexes correctly):
// OrderResource.java
package com.acme.server;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
@Path("/v1/orders")
public class OrderResource {
@GET public String list() { return "[]"; }
@GET @Path("/{id}") public String get(@PathParam("id") String id) { return id; }
@POST public String create(String body) { return body; }
}// ChallengeResource.java
package com.acme.server;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
@Path("/challenges")
public class ChallengeResource {
@GET @Path("/state") public String state() { return "ok"; }
@GET @Path("/{id}/verified/{token}")
public String verified(@PathParam("id") String id, @PathParam("token") String token) { return id; }
}2. Commands. The project ids below are what the indexer derives from the /tmp/... paths.
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-java-http-client","mode":"moderate"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-java-server","mode":"moderate"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-java-http-client","query":"MATCH (f)-[e:HTTP_CALLS]->(r:Route) RETURN f.file_path, f.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-java-http-client","query":"MATCH (f)-[e:CALLS]->(g) RETURN f.file_path, f.name, g.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-java-server","query":"MATCH (r:Route) RETURN r.qualified_name"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-java-http-client","mode":"cross-repo-intelligence","target_projects":["tmp-cbm-java-server"]}'
3. Result vs expected.
Client HTTP_CALLS (CLI output; expected 9 rows, one per call site in the table below):
rows: 2 (cols: f.file_path f.name r.qualified_name)
src/main/java/com/acme/client/InlineClient.java literal __route__GET__/v1/orders
src/main/java/com/acme/client/InlineClient.java concat __route__GET__/challenges/state
returned: 2
Server Route nodes (correct):
rows: 5 (cols: r.qualified_name)
__route__GET__/v1/orders
__route__GET__/v1/orders/{}
__route__POST__/v1/orders
__route__GET__/challenges/state
__route__GET__/challenges/{}/verified/{}
returned: 5
cross-repo-intelligence: "cross_http_calls":2,"total_cross_edges":2 (the two InlineClient edges).
Expected 9 (all rows below should be a HTTP_CALLS).
| call site | shape | expected Route | current HTTP_CALLS |
|---|---|---|---|
InlineClient.literal |
new RestTemplate().getForObject("/v1/orders", …) |
__route__GET__/v1/orders |
yes |
InlineClient.concat |
new RestTemplate().getForObject(baseUrl + "/challenges/state", …) |
__route__GET__/challenges/state |
yes |
JarFieldClient.orders |
restTemplate.getForObject("/v1/orders", …), RestTemplate field typed from a jar |
__route__GET__/v1/orders |
no |
LocalVarClient.orders |
rt.getForObject("/v1/orders", …), RestTemplate rt parameter |
__route__GET__/v1/orders |
no |
LocalVarClient.byId |
var t = rt; t.getForObject("/v1/orders/{id}", …) |
__route__GET__/v1/orders/{} |
no |
WrapperClient.orders |
builder.build().getForObject("/v1/orders", …), wrapper type from a jar |
__route__GET__/v1/orders |
no |
FormatInlineClient.verified |
new RestTemplate().getForObject("%s/challenges/%s/verified/%s".formatted(…), …) |
__route__GET__/challenges/{}/verified/{} |
no |
JarFieldClient.verified |
same format string on the jar-typed field (gaps 1 and 2) | __route__GET__/challenges/{}/verified/{} |
no |
OkClient.orders |
new Request.Builder().url("/v1/orders").get().build() then new OkHttpClient().newCall(request).execute() |
__route__GET__/v1/orders |
no |
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
No response
Confirmations
- I searched existing issues and this is not a duplicate.
- My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.
Activity
DeusData commentedon Oct 19, 2026
Thank you for the shareable client/server fixtures and the comparison table. Separating injected receivers, formatted URLs, and builder-based requests makes the missing HTTP_CALLS reports much easier to evaluate independently. There is no verified fix to report yet.
DeusData commentedon Oct 25, 2026
Thank you again for separating injected receivers, formatted URLs and request builders. Those three HTTP_CALLS gaps remain the investigation scope; no new reproduction is needed from you now. Sorry for the delay—I’ll follow up soon.