fa570ab32a
Resolve who is calling an MCP tool from the connection, not a spoofable argument (per docs/MCP-Contract.md). ConnectionIdentity ties the loopback peer PID (LsofPeerPidLookup) to a herdr pane (PaneLocator via pane.list/pane.process_info) → the caller's terminal_id; a caller owning no pane is the primary. bridge_reply now takes only content and resolves the worker from the connection (no sessionId). Live-verified: real PID→pane (contract test), and a non-pane MCP caller correctly gets a workers-only error. Single-host; the token path stays the split-host fallback. 58 tests green, IDE-clean.
59 lines
2.1 KiB
Java
59 lines
2.1 KiB
Java
package dev.ltms.bridged.mcp;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.InputStreamReader;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
/**
|
|
* {@link PeerPidLookup} via {@code lsof} (present on macOS and Linux). For a loopback TCP source
|
|
* {@code port}, both the client and this daemon appear on that port — so we exclude our own PID
|
|
* and take the other end, which is the calling process.
|
|
*/
|
|
public final class LsofPeerPidLookup implements PeerPidLookup {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(LsofPeerPidLookup.class);
|
|
|
|
private final long selfPid = ProcessHandle.current().pid();
|
|
|
|
@Override
|
|
public long pidForLocalPort(int port) {
|
|
try {
|
|
Process p = new ProcessBuilder("lsof", "-nP", "-FpP", "-iTCP:" + port)
|
|
.redirectErrorStream(true).start();
|
|
long found = -1;
|
|
try (BufferedReader r = new BufferedReader(
|
|
new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) {
|
|
long current = -1;
|
|
String line;
|
|
// -Fp emits records: a 'p<pid>' line, then the ports/files under that pid.
|
|
while ((line = r.readLine()) != null) {
|
|
if (line.startsWith("p")) {
|
|
current = parse(line.substring(1));
|
|
} else if (current > 0 && current != selfPid) {
|
|
found = current; // first process on this port that isn't us = the client
|
|
}
|
|
}
|
|
}
|
|
if (!p.waitFor(2, TimeUnit.SECONDS)) {
|
|
p.destroyForcibly();
|
|
}
|
|
return found;
|
|
} catch (Exception e) {
|
|
log.debug("lsof peer-pid lookup for port {} failed: {}", port, e.getMessage());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private static long parse(String s) {
|
|
try {
|
|
return Long.parseLong(s.trim());
|
|
} catch (NumberFormatException e) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|