refs #731: expose database game scope MCP

This commit is contained in:
devmrko
2026-07-27 13:43:59 +09:00
parent a17f18cffe
commit 455e2aa222
5 changed files with 157 additions and 10 deletions

View File

@@ -59,6 +59,10 @@ export BACKOFFICE_SELECT_AI_DB_PASSWORD=""
export BACKOFFICE_SELECT_AI_PROFILE="" export BACKOFFICE_SELECT_AI_PROFILE=""
export BACKOFFICE_SELECT_AI_FEW_SHOT_ENABLED="true" export BACKOFFICE_SELECT_AI_FEW_SHOT_ENABLED="true"
export BACKOFFICE_SELECT_AI_FEW_SHOT_TOP_K="3" export BACKOFFICE_SELECT_AI_FEW_SHOT_TOP_K="3"
# Customer-owned DB view: game aliases, approved profile objects, and valid DB objects.
export BACKOFFICE_GAME_SCOPE_ENABLED="false"
export BACKOFFICE_GAME_SCOPE_VIEW=""
export BACKOFFICE_GAME_SCOPE_MAX_SCOPES="8"
# 공통 데이터 카탈로그. objects는 key/tableName/objectType/businessName/description JSON 배열입니다. # 공통 데이터 카탈로그. objects는 key/tableName/objectType/businessName/description JSON 배열입니다.
# 배포 환경마다 반드시 실제 소유자와 허용 객체를 지정합니다. # 배포 환경마다 반드시 실제 소유자와 허용 객체를 지정합니다.
@@ -81,6 +85,9 @@ export BACKOFFICE_MCP_QA_VECTOR_SEARCH_TOOL_DESCRIPTION="현재 질문에 사용
export BACKOFFICE_MCP_QA_VECTOR_STORE_TOOL_NAME="oracle.select_ai.qa_vector_store" export BACKOFFICE_MCP_QA_VECTOR_STORE_TOOL_NAME="oracle.select_ai.qa_vector_store"
export BACKOFFICE_MCP_QA_VECTOR_STORE_TOOL_LABEL="Select AI 예제 SQL 저장" export BACKOFFICE_MCP_QA_VECTOR_STORE_TOOL_LABEL="Select AI 예제 SQL 저장"
export BACKOFFICE_MCP_QA_VECTOR_STORE_TOOL_DESCRIPTION="검토된 Select AI 결과를 후속 Text2SQL 품질 향상용 예제 SQL로 저장합니다." export BACKOFFICE_MCP_QA_VECTOR_STORE_TOOL_DESCRIPTION="검토된 Select AI 결과를 후속 Text2SQL 품질 향상용 예제 SQL로 저장합니다."
export BACKOFFICE_MCP_GAME_SCOPE_TOOL_NAME="oracle.select_ai.game_scope_resolve"
export BACKOFFICE_MCP_GAME_SCOPE_TOOL_LABEL="게임 조회 범위 확인"
export BACKOFFICE_MCP_GAME_SCOPE_TOOL_DESCRIPTION="질문의 게임 별칭을 DB 범위 view로 확인하고, SUPPORTED 결과에만 Few-shot NL2SQL을 호출하도록 안내합니다."
# 마스킹 관리 대상. objectName/policyName JSON 배열이며, 비우면 어떤 DB 정책도 관리하지 않습니다. # 마스킹 관리 대상. objectName/policyName JSON 배열이며, 비우면 어떤 DB 정책도 관리하지 않습니다.
export BACKOFFICE_MASKING_POLICIES='' export BACKOFFICE_MASKING_POLICIES=''
# 보안 SQL 화면에 노출할 번들 SQL. fileName은 패키지의 sql/adb/ 아래 파일명만 허용됩니다. # 보안 SQL 화면에 노출할 번들 SQL. fileName은 패키지의 sql/adb/ 아래 파일명만 허용됩니다.

View File

@@ -20,7 +20,10 @@ public record McpProperties(
String qaVectorStoreToolDescription, String qaVectorStoreToolDescription,
String fewShotNl2SqlToolName, String fewShotNl2SqlToolName,
String fewShotNl2SqlToolLabel, String fewShotNl2SqlToolLabel,
String fewShotNl2SqlToolDescription String fewShotNl2SqlToolDescription,
String gameScopeToolName,
String gameScopeToolLabel,
String gameScopeToolDescription
) { ) {
private static final String DEFAULT_TOOL_NAME = "oracle.select_ai.data_text2sql"; private static final String DEFAULT_TOOL_NAME = "oracle.select_ai.data_text2sql";
@@ -56,6 +59,12 @@ public record McpProperties(
private static final String DEFAULT_FEW_SHOT_NL2SQL_TOOL_DESCRIPTION = private static final String DEFAULT_FEW_SHOT_NL2SQL_TOOL_DESCRIPTION =
"벡터 Few-shot 예제를 찾아 prompt에 반영하고, SHOWSQL로 생성한 읽기 전용 SQL을 실행합니다. " "벡터 Few-shot 예제를 찾아 prompt에 반영하고, SHOWSQL로 생성한 읽기 전용 SQL을 실행합니다. "
+ "Few-shot 근거, 생성 SQL, 실행 결과를 함께 반환합니다."; + "Few-shot 근거, 생성 SQL, 실행 결과를 함께 반환합니다.";
private static final String DEFAULT_GAME_SCOPE_TOOL_NAME =
"oracle.select_ai.game_scope_resolve";
private static final String DEFAULT_GAME_SCOPE_TOOL_LABEL = "게임 조회 범위 확인";
private static final String DEFAULT_GAME_SCOPE_TOOL_DESCRIPTION =
"질문에서 언급된 게임 별칭을 DB 게임 범위 view로 확인합니다. 데이터 SQL은 실행하지 않으며, "
+ "반환된 SUPPORTED scope에만 Few-shot NL2SQL을 호출하세요.";
public String resolvedToolName() { public String resolvedToolName() {
return requiredOrDefault(toolName, DEFAULT_TOOL_NAME); return requiredOrDefault(toolName, DEFAULT_TOOL_NAME);
@@ -121,6 +130,18 @@ public record McpProperties(
return requiredOrDefault(fewShotNl2SqlToolDescription, DEFAULT_FEW_SHOT_NL2SQL_TOOL_DESCRIPTION); return requiredOrDefault(fewShotNl2SqlToolDescription, DEFAULT_FEW_SHOT_NL2SQL_TOOL_DESCRIPTION);
} }
public String resolvedGameScopeToolName() {
return requiredOrDefault(gameScopeToolName, DEFAULT_GAME_SCOPE_TOOL_NAME);
}
public String resolvedGameScopeToolLabel() {
return requiredOrDefault(gameScopeToolLabel, DEFAULT_GAME_SCOPE_TOOL_LABEL);
}
public String resolvedGameScopeToolDescription() {
return requiredOrDefault(gameScopeToolDescription, DEFAULT_GAME_SCOPE_TOOL_DESCRIPTION);
}
private String requiredOrDefault(String value, String fallback) { private String requiredOrDefault(String value, String fallback) {
return value == null || value.isBlank() ? fallback : value.trim(); return value == null || value.isBlank() ? fallback : value.trim();
} }

View File

@@ -21,19 +21,22 @@ public class McpSseService {
private final BackofficeProperties properties; private final BackofficeProperties properties;
private final McpProperties mcpProperties; private final McpProperties mcpProperties;
private final QaVectorService qaVectorService; private final QaVectorService qaVectorService;
private final GameScopeService gameScopeService;
public McpSseService( public McpSseService(
SelectAiService selectAiService, SelectAiService selectAiService,
ObjectMapper objectMapper, ObjectMapper objectMapper,
BackofficeProperties properties, BackofficeProperties properties,
McpProperties mcpProperties, McpProperties mcpProperties,
QaVectorService qaVectorService QaVectorService qaVectorService,
GameScopeService gameScopeService
) { ) {
this.selectAiService = selectAiService; this.selectAiService = selectAiService;
this.objectMapper = objectMapper; this.objectMapper = objectMapper;
this.properties = properties; this.properties = properties;
this.mcpProperties = mcpProperties; this.mcpProperties = mcpProperties;
this.qaVectorService = qaVectorService; this.qaVectorService = qaVectorService;
this.gameScopeService = gameScopeService;
} }
public ObjectNode handle(String contextPath, JsonNode request) { public ObjectNode handle(String contextPath, JsonNode request) {
@@ -74,7 +77,7 @@ public class McpSseService {
public List<McpToolView> registeredTools() { public List<McpToolView> registeredTools() {
return List.of( return List.of(
selectAiQueryView(), selectAiShowpromptView(), qaVectorSearchView(), selectAiQueryView(), selectAiShowpromptView(), qaVectorSearchView(),
qaVectorStoreView(), fewShotNl2SqlView()); qaVectorStoreView(), fewShotNl2SqlView(), gameScopeView());
} }
private ObjectNode initializeResult(String contextPath) { private ObjectNode initializeResult(String contextPath) {
@@ -98,6 +101,7 @@ public class McpSseService {
tools.add(toolDefinition(qaVectorSearchView())); tools.add(toolDefinition(qaVectorSearchView()));
tools.add(toolDefinition(qaVectorStoreView())); tools.add(toolDefinition(qaVectorStoreView()));
tools.add(toolDefinition(fewShotNl2SqlView())); tools.add(toolDefinition(fewShotNl2SqlView()));
tools.add(toolDefinition(gameScopeView()));
result.set("tools", tools); result.set("tools", tools);
return result; return result;
} }
@@ -112,7 +116,7 @@ public class McpSseService {
ObjectNode properties = objectMapper.createObjectNode(); ObjectNode properties = objectMapper.createObjectNode();
ArrayNode required = objectMapper.createArrayNode(); ArrayNode required = objectMapper.createArrayNode();
if (qaVectorSearchToolName().equals(toolView.name())) { if (qaVectorSearchToolName().equals(toolView.name()) || gameScopeToolName().equals(toolView.name())) {
addStringProperty(properties, "question", "few-shot 예제 SQL을 찾을 현재 질문입니다.", 4000); addStringProperty(properties, "question", "few-shot 예제 SQL을 찾을 현재 질문입니다.", 4000);
ObjectNode topK = properties.putObject("topK"); ObjectNode topK = properties.putObject("topK");
topK.put("type", "integer"); topK.put("type", "integer");
@@ -129,6 +133,10 @@ public class McpSseService {
required.add("answerSql"); required.add("answerSql");
} else { } else {
addStringProperty(properties, "prompt", promptDescription(), 4000); addStringProperty(properties, "prompt", promptDescription(), 4000);
if (fewShotNl2SqlToolName().equals(toolView.name())) {
addStringProperty(properties, "scopeGameKey",
"선택 사항입니다. game_scope_resolve가 반환한 SUPPORTED gameKey만 전달하세요.", 128);
}
required.add("prompt"); required.add("prompt");
} }
schema.set("properties", properties); schema.set("properties", properties);
@@ -152,7 +160,9 @@ public class McpSseService {
boolean qaVectorSearchTool = qaVectorSearchToolName().equals(calledToolName); boolean qaVectorSearchTool = qaVectorSearchToolName().equals(calledToolName);
boolean qaVectorStoreTool = qaVectorStoreToolName().equals(calledToolName); boolean qaVectorStoreTool = qaVectorStoreToolName().equals(calledToolName);
boolean fewShotNl2SqlTool = fewShotNl2SqlToolName().equals(calledToolName); boolean fewShotNl2SqlTool = fewShotNl2SqlToolName().equals(calledToolName);
if (!queryTool && !showpromptTool && !qaVectorSearchTool && !qaVectorStoreTool && !fewShotNl2SqlTool) { boolean gameScopeTool = gameScopeToolName().equals(calledToolName);
if (!queryTool && !showpromptTool && !qaVectorSearchTool && !qaVectorStoreTool && !fewShotNl2SqlTool
&& !gameScopeTool) {
throw new AppException("등록되지 않은 MCP tool입니다: " + calledToolName); throw new AppException("등록되지 않은 MCP tool입니다: " + calledToolName);
} }
@@ -173,10 +183,16 @@ public class McpSseService {
arguments.path("answerSql").asText(""), arguments.path("answerSql").asText(""),
arguments.path("answer").isMissingNode() ? null : arguments.path("answer").asText(null) arguments.path("answer").isMissingNode() ? null : arguments.path("answer").asText(null)
)); ));
} else if (gameScopeTool) {
response = gameScopeResponse(gameScopeService.resolve(
token, arguments.path("question").asText("")));
} else { } else {
String prompt = arguments.path("prompt").asText(""); String prompt = arguments.path("prompt").asText("");
response = queryTool || fewShotNl2SqlTool response = queryTool
? selectAiService.generateAndExecute(token, prompt) ? selectAiService.generateAndExecute(token, prompt)
: fewShotNl2SqlTool
? selectAiService.generateAndExecute(token, prompt,
arguments.path("scopeGameKey").asText(""))
: selectAiService.generatePrompt(token, prompt); : selectAiService.generatePrompt(token, prompt);
} }
} catch (VpdTokenAccessDeniedException ignored) { } catch (VpdTokenAccessDeniedException ignored) {
@@ -231,6 +247,28 @@ public class McpSseService {
return response; return response;
} }
/** Converts DB-derived scope facts to a tool response; this tool never executes query SQL. */
private ObjectNode gameScopeResponse(GameScopeService.GameScopeResult result) {
ObjectNode response = objectMapper.createObjectNode();
response.put("status", result.status());
response.put("instruction", "반환된 SUPPORTED scope에만 Few-shot NL2SQL을 호출하세요.");
response.put("question", result.question());
ArrayNode scopes = response.putArray("scopes");
for (GameScopeService.GameScope scope : result.scopes()) {
ObjectNode item = scopes.addObject();
item.put("gameKey", scope.gameKey());
item.put("displayName", scope.displayName());
item.put("matchedAlias", scope.matchedAlias());
item.put("status", scope.status());
item.put("reasonCode", scope.reasonCode());
item.put("aliasPriority", scope.aliasPriority());
item.put("scopeVersion", scope.scopeVersion());
item.put("nextAction", "SUPPORTED".equals(scope.status())
? "CALL_FEW_SHOT_NL2SQL" : "REPORT_UNSUPPORTED");
}
return response;
}
private ObjectNode tokenAccessDeniedResult() { private ObjectNode tokenAccessDeniedResult() {
ObjectNode payload = objectMapper.createObjectNode(); ObjectNode payload = objectMapper.createObjectNode();
payload.put("status", "VPD_TOKEN_DENIED"); payload.put("status", "VPD_TOKEN_DENIED");
@@ -287,6 +325,12 @@ public class McpSseService {
fewShotNl2SqlToolLabel(), SELECT_AI_TOOL_PATH); fewShotNl2SqlToolLabel(), SELECT_AI_TOOL_PATH);
} }
private McpToolView gameScopeView() {
return new McpToolView(
gameScopeToolName(), gameScopeToolDescription(), -1L,
gameScopeToolLabel(), SELECT_AI_TOOL_PATH);
}
private String selectAiProfile() { private String selectAiProfile() {
BackofficeProperties.SelectAi selectAi = properties == null ? null : properties.selectAi(); BackofficeProperties.SelectAi selectAi = properties == null ? null : properties.selectAi();
if (selectAi == null || selectAi.profile() == null || selectAi.profile().isBlank()) { if (selectAi == null || selectAi.profile() == null || selectAi.profile().isBlank()) {
@@ -379,6 +423,21 @@ public class McpSseService {
: mcpProperties.resolvedFewShotNl2SqlToolDescription(); : mcpProperties.resolvedFewShotNl2SqlToolDescription();
} }
private String gameScopeToolName() {
return mcpProperties == null ? "oracle.select_ai.game_scope_resolve"
: mcpProperties.resolvedGameScopeToolName();
}
private String gameScopeToolLabel() {
return mcpProperties == null ? "게임 조회 범위 확인" : mcpProperties.resolvedGameScopeToolLabel();
}
private String gameScopeToolDescription() {
return mcpProperties == null
? "질문에서 언급된 게임 별칭을 DB 게임 범위 view로 확인합니다."
: mcpProperties.resolvedGameScopeToolDescription();
}
private String pretty(Object value) { private String pretty(Object value) {
try { try {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(value); return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(value);

View File

@@ -77,6 +77,12 @@ backoffice:
profile: ${BACKOFFICE_SELECT_AI_PROFILE:} profile: ${BACKOFFICE_SELECT_AI_PROFILE:}
few-shot-enabled: ${BACKOFFICE_SELECT_AI_FEW_SHOT_ENABLED:true} few-shot-enabled: ${BACKOFFICE_SELECT_AI_FEW_SHOT_ENABLED:true}
few-shot-top-k: ${BACKOFFICE_SELECT_AI_FEW_SHOT_TOP_K:3} few-shot-top-k: ${BACKOFFICE_SELECT_AI_FEW_SHOT_TOP_K:3}
game-scope:
# Customer DB view contract: aliases + profile object list + Oracle objects.
# No customer game or table identifier is embedded in application code.
enabled: ${BACKOFFICE_GAME_SCOPE_ENABLED:false}
view-name: ${BACKOFFICE_GAME_SCOPE_VIEW:}
max-scopes: ${BACKOFFICE_GAME_SCOPE_MAX_SCOPES:8}
catalog: catalog:
owner: ${BACKOFFICE_CATALOG_OWNER:} owner: ${BACKOFFICE_CATALOG_OWNER:}
objects: ${BACKOFFICE_CATALOG_OBJECTS:} objects: ${BACKOFFICE_CATALOG_OBJECTS:}
@@ -101,6 +107,9 @@ backoffice:
few-shot-nl2sql-tool-name: ${BACKOFFICE_MCP_FEW_SHOT_NL2SQL_TOOL_NAME:oracle.select_ai.smilegate_fewshot_nl2sql} few-shot-nl2sql-tool-name: ${BACKOFFICE_MCP_FEW_SHOT_NL2SQL_TOOL_NAME:oracle.select_ai.smilegate_fewshot_nl2sql}
few-shot-nl2sql-tool-label: ${BACKOFFICE_MCP_FEW_SHOT_NL2SQL_TOOL_LABEL:Few-shot NL2SQL 실행} few-shot-nl2sql-tool-label: ${BACKOFFICE_MCP_FEW_SHOT_NL2SQL_TOOL_LABEL:Few-shot NL2SQL 실행}
few-shot-nl2sql-tool-description: ${BACKOFFICE_MCP_FEW_SHOT_NL2SQL_TOOL_DESCRIPTION:벡터 Few-shot 예제를 찾아 prompt에 반영하고 SHOWSQL로 생성한 읽기 전용 SQL을 실행합니다. Few-shot 근거, 생성 SQL, 실행 결과를 함께 반환합니다.} few-shot-nl2sql-tool-description: ${BACKOFFICE_MCP_FEW_SHOT_NL2SQL_TOOL_DESCRIPTION:벡터 Few-shot 예제를 찾아 prompt에 반영하고 SHOWSQL로 생성한 읽기 전용 SQL을 실행합니다. Few-shot 근거, 생성 SQL, 실행 결과를 함께 반환합니다.}
game-scope-tool-name: ${BACKOFFICE_MCP_GAME_SCOPE_TOOL_NAME:oracle.select_ai.game_scope_resolve}
game-scope-tool-label: ${BACKOFFICE_MCP_GAME_SCOPE_TOOL_LABEL:게임 조회 범위 확인}
game-scope-tool-description: ${BACKOFFICE_MCP_GAME_SCOPE_TOOL_DESCRIPTION:질문에서 언급된 게임 별칭을 DB 게임 범위 view로 확인합니다. 데이터 SQL은 실행하지 않으며, 반환된 SUPPORTED scope에만 Few-shot NL2SQL을 호출하세요.}
masking: masking:
policies: ${BACKOFFICE_MASKING_POLICIES:} policies: ${BACKOFFICE_MASKING_POLICIES:}
security-sql-scripts: security-sql-scripts:

View File

@@ -2,6 +2,7 @@ package com.cloudhandson.vpdbackoffice.service;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import com.cloudhandson.vpdbackoffice.config.BackofficeProperties; import com.cloudhandson.vpdbackoffice.config.BackofficeProperties;
import com.cloudhandson.vpdbackoffice.config.GameScopeProperties;
import com.cloudhandson.vpdbackoffice.config.McpProperties; import com.cloudhandson.vpdbackoffice.config.McpProperties;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@@ -13,6 +14,7 @@ class McpSseServiceTest {
private final ObjectMapper objectMapper = new ObjectMapper(); private final ObjectMapper objectMapper = new ObjectMapper();
private final SelectAiService selectAiService = new CapturingSelectAiService(); private final SelectAiService selectAiService = new CapturingSelectAiService();
private final QaVectorService qaVectorService = new CapturingQaVectorService(); private final QaVectorService qaVectorService = new CapturingQaVectorService();
private final GameScopeService gameScopeService = new CapturingGameScopeService();
private final McpSseService service = new McpSseService( private final McpSseService service = new McpSseService(
selectAiService, selectAiService,
objectMapper, objectMapper,
@@ -40,9 +42,13 @@ class McpSseServiceTest {
"테스트 예제 SQL을 저장합니다.", "테스트 예제 SQL을 저장합니다.",
"oracle.select_ai.test_fewshot_nl2sql", "oracle.select_ai.test_fewshot_nl2sql",
"테스트 Few-shot NL2SQL", "테스트 Few-shot NL2SQL",
"테스트 Few-shot 검색 및 실행 도구입니다." "테스트 Few-shot 검색 및 실행 도구입니다.",
"oracle.select_ai.test_game_scope_resolve",
"테스트 게임 범위 확인",
"테스트 DB 게임 범위 확인 도구입니다."
), ),
qaVectorService qaVectorService,
gameScopeService
); );
@Test @Test
@@ -50,7 +56,7 @@ class McpSseServiceTest {
ObjectNode response = service.handle("default", request(1, "tools/list")); ObjectNode response = service.handle("default", request(1, "tools/list"));
var tools = response.path("result").path("tools"); var tools = response.path("result").path("tools");
assertThat(tools).hasSize(5); assertThat(tools).hasSize(6);
var selectAi = tools.get(0); var selectAi = tools.get(0);
assertThat(selectAi.path("name").asText()).isEqualTo("oracle.select_ai.test_data_text2sql"); assertThat(selectAi.path("name").asText()).isEqualTo("oracle.select_ai.test_data_text2sql");
assertThat(selectAi.path("description").asText()).contains("SGMP_POC_OCI_GPT54MINI"); assertThat(selectAi.path("description").asText()).contains("SGMP_POC_OCI_GPT54MINI");
@@ -90,6 +96,12 @@ class McpSseServiceTest {
assertThat(fewShot.path("name").asText()) assertThat(fewShot.path("name").asText())
.isEqualTo("oracle.select_ai.test_fewshot_nl2sql"); .isEqualTo("oracle.select_ai.test_fewshot_nl2sql");
assertThat(fewShot.path("description").asText()).contains("Few-shot"); assertThat(fewShot.path("description").asText()).contains("Few-shot");
var gameScope = tools.get(5);
assertThat(gameScope.path("name").asText())
.isEqualTo("oracle.select_ai.test_game_scope_resolve");
assertThat(gameScope.path("inputSchema").path("required"))
.extracting(node -> node.asText()).contains("question");
} }
@Test @Test
@@ -208,6 +220,23 @@ class McpSseServiceTest {
.contains("exampleId"); .contains("exampleId");
} }
@Test
void resolvesGameScopeFromTheDatabaseBackedTool() {
ObjectNode request = request(8, "tools/call");
ObjectNode params = (ObjectNode) request.putObject("params");
params.put("name", "oracle.select_ai.test_game_scope_resolve");
params.putObject("arguments").put("question", "games requested");
ObjectNode response = service.handle("default", request, "user-bearer");
assertThat(response.path("result").path("isError").asBoolean()).isFalse();
String payload = response.path("result").path("content").get(0).path("text").asText();
assertThat(payload)
.contains("RESOLVED")
.contains("CALL_FEW_SHOT_NL2SQL")
.contains("REPORT_UNSUPPORTED");
}
private ObjectNode request(int id, String method) { private ObjectNode request(int id, String method) {
ObjectNode request = objectMapper.createObjectNode(); ObjectNode request = objectMapper.createObjectNode();
request.put("jsonrpc", "2.0"); request.put("jsonrpc", "2.0");
@@ -223,7 +252,7 @@ class McpSseServiceTest {
private boolean showpromptCalled; private boolean showpromptCalled;
private CapturingSelectAiService() { private CapturingSelectAiService() {
super(null, null, null, new ObjectMapper(), null); super(null, null, null, new ObjectMapper(), null, null);
} }
@Override @Override
@@ -240,6 +269,11 @@ class McpSseServiceTest {
return response; return response;
} }
@Override
public JsonNode generateAndExecute(String bearerToken, String prompt, String scopeGameKey) {
return generateAndExecute(bearerToken, prompt);
}
@Override @Override
public JsonNode generatePrompt(String bearerToken, String prompt) { public JsonNode generatePrompt(String bearerToken, String prompt) {
this.bearerToken = bearerToken; this.bearerToken = bearerToken;
@@ -282,4 +316,21 @@ class McpSseServiceTest {
return new VectorStoreResult(77L, question, "cohere.embed-v4.0"); return new VectorStoreResult(77L, question, "cohere.embed-v4.0");
} }
} }
private static final class CapturingGameScopeService extends GameScopeService {
private CapturingGameScopeService() {
super(null, new GameScopeProperties(false, "", 8), null, null);
}
@Override
public GameScopeResult resolve(String bearerToken, String question) {
return new GameScopeResult(question, "RESOLVED", java.util.List.of(
new GameScope("SUPPORTED_GAME", "Supported game", "Supported", "SUPPORTED",
"APPROVED_OBJECT_AVAILABLE", 100, "100"),
new GameScope("UNSUPPORTED_GAME", "Unsupported game", "Unsupported", "UNSUPPORTED",
"OBJECT_LIST_NOT_AVAILABLE", 100, "100")
));
}
}
} }