Skip to content

Commit e4b488e

Browse files
committed
Pack it as MCP
Signed-off-by: Zhaoyuan (Ryan) Fu <[email protected]>
1 parent 2bf84f5 commit e4b488e

File tree

6 files changed

+202
-3
lines changed

6 files changed

+202
-3
lines changed

pom.xml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@
422422
<groupId>org.springframework.ai</groupId>
423423
<artifactId>spring-ai-starter-model-anthropic</artifactId>
424424
</dependency>
425+
<dependency>
426+
<groupId>org.springframework.ai</groupId>
427+
<artifactId>spring-ai-starter-mcp-server</artifactId>
428+
</dependency>
425429
</dependencies>
426430

427431
<dependencyManagement>
@@ -873,6 +877,75 @@
873877
<skipE2ETests>false</skipE2ETests>
874878
</properties>
875879
</profile>
880+
<!-- MCP Server Build Profile -->
881+
<profile>
882+
<id>mcp</id>
883+
<properties>
884+
<skipTests>true</skipTests>
885+
<skipIntegrationTests>true</skipIntegrationTests>
886+
<skipE2ETests>true</skipE2ETests>
887+
</properties>
888+
<build>
889+
<finalName>cbioportal-mcp-server</finalName>
890+
<plugins>
891+
<plugin>
892+
<groupId>org.springframework.boot</groupId>
893+
<artifactId>spring-boot-maven-plugin</artifactId>
894+
<configuration>
895+
<mainClass>org.cbioportal.infrastructure.ai.McpServerApplication</mainClass>
896+
<classifier>exec</classifier>
897+
<excludes>
898+
<!-- Exclude web-related dependencies to reduce JAR size -->
899+
<exclude>
900+
<groupId>org.springframework.boot</groupId>
901+
<artifactId>spring-boot-starter-thymeleaf</artifactId>
902+
</exclude>
903+
<exclude>
904+
<groupId>org.springframework.security</groupId>
905+
<artifactId>spring-security-web</artifactId>
906+
</exclude>
907+
<exclude>
908+
<groupId>org.springframework.security</groupId>
909+
<artifactId>spring-security-config</artifactId>
910+
</exclude>
911+
<exclude>
912+
<groupId>org.springframework.boot</groupId>
913+
<artifactId>spring-boot-starter-oauth2-client</artifactId>
914+
</exclude>
915+
<exclude>
916+
<groupId>org.springframework.boot</groupId>
917+
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
918+
</exclude>
919+
<exclude>
920+
<groupId>org.springframework.security</groupId>
921+
<artifactId>spring-security-saml2-service-provider</artifactId>
922+
</exclude>
923+
<exclude>
924+
<groupId>org.springframework.session</groupId>
925+
<artifactId>spring-session-data-redis</artifactId>
926+
</exclude>
927+
<exclude>
928+
<groupId>org.springframework.boot</groupId>
929+
<artifactId>spring-boot-starter-data-redis</artifactId>
930+
</exclude>
931+
<exclude>
932+
<groupId>org.springframework.boot</groupId>
933+
<artifactId>spring-boot-starter-data-mongodb</artifactId>
934+
</exclude>
935+
<exclude>
936+
<groupId>org.mybatis.spring.boot</groupId>
937+
<artifactId>mybatis-spring-boot-starter</artifactId>
938+
</exclude>
939+
<exclude>
940+
<groupId>org.springdoc</groupId>
941+
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
942+
</exclude>
943+
</excludes>
944+
</configuration>
945+
</plugin>
946+
</plugins>
947+
</build>
948+
</profile>
876949
<!-- Maven Central -->
877950
<profile>
878951
<id>maven-central</id>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.cbioportal.infrastructure.ai;
2+
3+
import org.cbioportal.infrastructure.ai.tools.DatabaseQueryTools;
4+
import org.cbioportal.infrastructure.ai.tools.DatabaseSchemaTools;
5+
import org.springframework.ai.tool.ToolCallbackProvider;
6+
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
7+
import org.springframework.boot.SpringApplication;
8+
import org.springframework.boot.autoconfigure.SpringBootApplication;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.context.annotation.ComponentScan;
11+
12+
/**
13+
* MCP (Model Context Protocol) Server Application for cBioPortal database queries.
14+
*
15+
* <p>This is a lightweight, standalone application that exposes database query tools via the MCP
16+
* protocol. It communicates through stdin/stdout and is designed for fast startup and low resource
17+
* usage.
18+
*
19+
* <p>Usage: java -jar cbioportal-mcp-server-exec.jar --spring.profiles.active=mcp
20+
*
21+
* <p>The server exposes two main tools: - DatabaseQueryTools: Execute SQL queries against
22+
* ClickHouse - DatabaseSchemaTools: Retrieve table schemas and list available tables
23+
*/
24+
@SpringBootApplication
25+
@ComponentScan(
26+
basePackages = {
27+
"org.cbioportal.infrastructure.ai.tools", // Tool implementations
28+
"org.cbioportal.legacy.properties" // DataSource configuration
29+
})
30+
public class McpServerApplication {
31+
32+
public static void main(String[] args) {
33+
SpringApplication.run(McpServerApplication.class, args);
34+
}
35+
36+
/**
37+
* Register database tools with the MCP server. The MethodToolCallbackProvider automatically
38+
* discovers methods annotated with @Tool in the provided tool objects.
39+
*
40+
* @param queryTools Tool for executing database queries
41+
* @param schemaTools Tool for retrieving schema information
42+
* @return ToolCallbackProvider configured with cBioPortal tools
43+
*/
44+
@Bean
45+
public ToolCallbackProvider cbioportalTools(
46+
DatabaseQueryTools queryTools, DatabaseSchemaTools schemaTools) {
47+
return MethodToolCallbackProvider.builder().toolObjects(queryTools, schemaTools).build();
48+
}
49+
}

src/main/java/org/cbioportal/infrastructure/ai/tools/DatabaseQueryTools.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import org.springframework.stereotype.Component;
1515

1616
/**
17-
* Spring AI Tool for querying cBioPortal database. This tool can be called by AI assistants to
18-
* retrieve cancer genomics data.
17+
* Spring AI Tool for querying cBioPortal ClickHouse database. Provides direct, fast access to
18+
* cancer genomics data.
1919
*/
2020
@Component
2121
public class DatabaseQueryTools {

src/main/java/org/cbioportal/infrastructure/ai/tools/DatabaseSchemaTools.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.io.InputStreamReader;
77
import java.util.ArrayList;
88
import java.util.List;
9+
import java.util.regex.Pattern;
910
import org.slf4j.Logger;
1011
import org.slf4j.LoggerFactory;
1112
import org.springframework.ai.tool.annotation.Tool;
@@ -203,7 +204,7 @@ private String extractTableSchema(String schemaPath, String tableName) throws IO
203204
// Check if this is the start of our target table (case-insensitive)
204205
if (trimmed
205206
.toUpperCase()
206-
.matches("CREATE\\s+TABLE\\s+`?" + tableName.toUpperCase() + "`?.*")) {
207+
.matches("CREATE\\s+TABLE\\s+`?" + Pattern.quote(tableName.toUpperCase()) + "`?.*")) {
207208
inTargetTable = true;
208209
currentTable.append(line).append("\n");
209210
parenthesesDepth = countChar(line, '(') - countChar(line, ')');
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# =====================================================
2+
# cBioPortal MCP Server Configuration
3+
# =====================================================
4+
# Usage: java -jar cbioportal-mcp-server-exec.jar --spring.profiles.active=mcp,clickhouse
5+
#
6+
# Disable web application - MCP uses stdin/stdout, not HTTP
7+
spring.main.web-application-type=none
8+
spring.main.banner-mode=off
9+
10+
# CRITICAL: All logs MUST go to stderr, NEVER stdout
11+
# MCP uses stdin/stdout for protocol communication
12+
logging.pattern.console=
13+
# Ensure logback uses our configuration
14+
logging.config=classpath:logback-spring.xml
15+
16+
# =====================================================
17+
# MCP Server Metadata
18+
# =====================================================
19+
spring.ai.mcp.server.name=cbioportal-assistant
20+
spring.ai.mcp.server.version=1.0.0
21+
22+
# =====================================================
23+
# ClickHouse Database Configuration
24+
# =====================================================
25+
spring.datasource.clickhouse.url=
26+
spring.datasource.clickhouse.username=
27+
spring.datasource.clickhouse.password=
28+
spring.datasource.clickhouse.driver-class-name=com.clickhouse.jdbc.ClickHouseDriver
29+
30+
# Connection pool settings for fast startup
31+
spring.datasource.clickhouse.hikari.maximum-pool-size=5
32+
spring.datasource.clickhouse.hikari.minimum-idle=1
33+
spring.datasource.clickhouse.connection-timeout=10000
34+
35+
# =====================================================
36+
# Disable Features Not Needed for MCP Server
37+
# =====================================================
38+
# No cache needed for stateless MCP server
39+
persistence.cache_type=no-cache
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<configuration>
3+
<!--
4+
Logback configuration for MCP Server
5+
CRITICAL: MCP protocol uses STDOUT for JSON messages
6+
All application logs MUST go to STDERR or file, NEVER to STDOUT
7+
-->
8+
9+
<!-- Disable logback status messages -->
10+
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
11+
12+
<!-- Console appender that outputs to STDERR (not STDOUT) -->
13+
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
14+
<target>System.err</target>
15+
<encoder>
16+
<pattern>%date %-5level %logger{36} - %msg%n</pattern>
17+
</encoder>
18+
</appender>
19+
20+
<!-- Root logger - output to STDERR only -->
21+
<root level="WARN">
22+
<appender-ref ref="STDERR" />
23+
</root>
24+
25+
<!-- Application-specific loggers -->
26+
<logger name="org.cbioportal.infrastructure.ai" level="INFO" additivity="false">
27+
<appender-ref ref="STDERR" />
28+
</logger>
29+
30+
<logger name="org.springframework" level="WARN" additivity="false">
31+
<appender-ref ref="STDERR" />
32+
</logger>
33+
34+
<logger name="org.springframework.boot" level="WARN" additivity="false">
35+
<appender-ref ref="STDERR" />
36+
</logger>
37+
</configuration>

0 commit comments

Comments
 (0)