diff --git a/tests/integration/suites/uc41_health_check_withdrawal/artifacts/java-hc-consumer/pom.xml b/tests/integration/suites/uc41_health_check_withdrawal/artifacts/java-hc-consumer/pom.xml
new file mode 100644
index 000000000..88c5076c4
--- /dev/null
+++ b/tests/integration/suites/uc41_health_check_withdrawal/artifacts/java-hc-consumer/pom.xml
@@ -0,0 +1,52 @@
+
+
+ 4.0.0
+
+ com.example
+ java-hc-consumer
+ 1.0.0-SNAPSHOT
+ jar
+
+ uc41 consumer that reports which provider served it
+ uc41 consumer that reports which provider served it (issue #1480)
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 4.0.5
+
+
+
+
+ 17
+ 3.5.1
+
+
+
+
+ io.mcp-mesh
+ mcp-mesh-spring-boot-starter
+ ${mcp-mesh.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.example.hcconsumer.HcConsumerApplication
+
+
+
+
+
+
diff --git a/tests/integration/suites/uc41_health_check_withdrawal/artifacts/java-hc-consumer/src/main/java/com/example/hcconsumer/HcConsumerApplication.java b/tests/integration/suites/uc41_health_check_withdrawal/artifacts/java-hc-consumer/src/main/java/com/example/hcconsumer/HcConsumerApplication.java
new file mode 100644
index 000000000..98f31d1c3
--- /dev/null
+++ b/tests/integration/suites/uc41_health_check_withdrawal/artifacts/java-hc-consumer/src/main/java/com/example/hcconsumer/HcConsumerApplication.java
@@ -0,0 +1,64 @@
+package com.example.hcconsumer;
+
+import io.mcpmesh.MeshAgent;
+import io.mcpmesh.MeshTool;
+import io.mcpmesh.Selector;
+import io.mcpmesh.types.McpMeshTool;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * java-hc-consumer — reports which provider the mesh routed it to (#1480).
+ *
+ *
{@code who_served} injects {@code hc_probe_java} and returns the
+ * provider's payload verbatim. Started ONCE and never restarted, so the only
+ * way its answer can move from provider A to provider B and back is a genuine
+ * re-resolution — the withdrawal / recovery chain under test.
+ *
+ *
The MCP tool name is the METHOD name verbatim — {@code @MeshTool} has no
+ * {@code name()} attribute and does not snake_case anything — so the test
+ * calls {@code hc-consumer-java:whoServed}, not {@code who_served}. Same
+ * convention as uc38's {@code getRejectCount}.
+ *
+ *
An unresolved dependency reports {@code served_by: "UNRESOLVED"} rather
+ * than throwing. The test's failover poll then keeps polling through a
+ * transient gap instead of tripping on it, and a PERMANENT gap still fails the
+ * run because {@code "UNRESOLVED"} never becomes a provider name.
+ */
+@SpringBootApplication
+@MeshAgent(
+ name = "hc-consumer-java",
+ version = "1.0.0",
+ description = "Consumer that must fail over when provider A withdraws (#1480)",
+ port = 3433
+)
+public class HcConsumerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(HcConsumerApplication.class, args);
+ }
+
+ @MeshTool(
+ capability = "who_served_java",
+ description = "Call hc_probe_java and report which provider answered",
+ tags = {"hc-withdrawal"},
+ dependencies = {@Selector(capability = "hc_probe_java")}
+ )
+ public Map whoServed(McpMeshTool