refactor: Migrate MCP Gateway to Spring AI MCP Server

This commit is contained in:
jade
2026-07-14 15:39:55 +09:00
parent a944841427
commit 0308926116
10 changed files with 517 additions and 196 deletions

View File

@@ -19,71 +19,20 @@ public class McpBridge {
line = line.trim();
if (line.isEmpty()) continue;
// Simple JSON parsing by finding method names
// Using a rudimentary JSON parser since we don't have Jackson here
if (line.contains("\"method\":\"initialize\"") || line.contains("\"method\": \"initialize\"")) {
String id = extractId(line);
String resp = "{\"jsonrpc\":\"2.0\",\"id\":" + id + ",\"result\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{\"tools\":{}},\"serverInfo\":{\"name\":\"axhub-gateway\",\"version\":\"1.0.0\"}}}";
System.out.println(resp);
try {
HttpRequest req = HttpRequest.newBuilder()
// Spring AI MCP Server의 공식 단일 엔드포인트
.uri(URI.create("http://localhost:8081/mcp"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(line))
.build();
HttpResponse<String> response = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
System.out.flush();
} else if (line.contains("\"method\":\"notifications/initialized\"") || line.contains("\"method\": \"notifications/initialized\"")) {
// Do nothing
} else if (line.contains("\"method\":\"tools/list\"") || line.contains("\"method\": \"tools/list\"")) {
String id = extractId(line);
try {
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8281/mcp/api/v1/tools/list"))
.GET()
.build();
HttpResponse<String> response = client.send(req, HttpResponse.BodyHandlers.ofString());
// Parse tools from response string manually (basic string manipulation)
// axhub-gateway returns: {"result":{"tools":[{"subToolName":"other_get_sample_string","description":"...","parametersSchema":{...}}]}}
// We need to format it to standard MCP format
String rawJson = response.body();
// For simplicity, we can just proxy the response if it matches closely, but it doesn't.
// Let's just do a naive conversion by replacing "subToolName" with "name" and "parametersSchema" with "inputSchema"
String transformed = rawJson;
// Add type: "object" to inputSchema if missing - too complex with string replace, let's hope axhub-gateway already provides correct schema
// The result format expects: {"tools": [ ... ]}
// axhub-gateway returns: {"id":"...","result":{"tools":[...]}}
// So we extract the "result" object and wrap it in the JSON-RPC response
int resultIdx = transformed.indexOf("\"result\":{");
if (resultIdx != -1) {
String resultObj = transformed.substring(resultIdx + 9, transformed.lastIndexOf("}") );
System.out.println("{\"jsonrpc\":\"2.0\",\"id\":" + id + ",\"result\":" + resultObj + "}");
} else {
System.out.println("{\"jsonrpc\":\"2.0\",\"id\":" + id + ",\"result\":{\"tools\":[]}}");
}
} catch (Exception e) {
System.out.println("{\"jsonrpc\":\"2.0\",\"id\":" + id + ",\"error\":{\"code\":-32603,\"message\":\"" + e.getMessage().replace("\"", "\\\"") + "\"}}");
}
System.out.flush();
} else if (line.contains("\"method\":\"tools/call\"") || line.contains("\"method\": \"tools/call\"")) {
String id = extractId(line);
try {
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8281/mcp/api/v1/tools/call"))
.header("Content-Type", "application/json")
.header("X-Agent-Id", "Antigravity")
.POST(HttpRequest.BodyPublishers.ofString(line))
.build();
HttpResponse<String> response = client.send(req, HttpResponse.BodyHandlers.ofString());
String rawJson = response.body();
// The gateway returns {"jsonrpc":"2.0", "result": {...}, "error": {...}}
// Standard MCP expects {"content": [{"type": "text", "text": "..."}], "isError": false}
boolean isError = rawJson.contains("\"error\":") || rawJson.contains("\"status\":\"ERROR\"");
String escapedRawJson = rawJson.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "");
System.out.println("{\"jsonrpc\":\"2.0\",\"id\":" + id + ",\"result\":{\"content\":[{\"type\":\"text\",\"text\":\"" + escapedRawJson + "\"}],\"isError\":" + isError + "}}");
} catch (Exception e) {
System.out.println("{\"jsonrpc\":\"2.0\",\"id\":" + id + ",\"result\":{\"content\":[{\"type\":\"text\",\"text\":\"" + e.getMessage().replace("\"", "\\\"") + "\"}],\"isError\":true}}");
}
} catch (Exception e) {
// MCP 표준 에러 포맷으로 반환 (임의로 id 추출 제외, 최소한의 에러 응답)
System.out.println("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32603,\"message\":\"" + e.getMessage().replace("\"", "\\\"") + "\"}}");
System.out.flush();
}
}
@@ -91,34 +40,6 @@ public class McpBridge {
e.printStackTrace();
}
}
private static String extractId(String line) {
int idx = line.indexOf("\"id\":");
if (idx == -1) return "null";
int start = idx + 5;
while (start < line.length() && line.charAt(start) == ' ') {
start++;
}
if (start >= line.length()) return "null";
int end = start;
if (line.charAt(start) == '\"') {
end = start + 1;
while (end < line.length() && line.charAt(end) != '\"') {
end++;
}
if (end < line.length()) {
end++; // include closing quote
}
} else {
while (end < line.length() && Character.isDigit(line.charAt(end))) {
end++;
}
}
if (start == end) return "null";
return line.substring(start, end);
}
}