Membangun MCP dengan Java : Membuat Tools untuk AI Assistant
Model Context Protocol (MCP) adalah standar untuk menghubungkan AI assistant dengan sistem, data, dan fungsi yang kita miliki. Dengan MCP, AI tidak hanya menjawab berdasarkan pengetahuan model, tetapi dapat memanggil tool untuk mengambil data tiket, membuat laporan, mengecek status JIRA, mencari SOP, atau menjalankan proses bisnis tertentu.
Artikel ini membangun MCP Server sederhana menggunakan Java dan Spring Boot dari nol. Contoh yang dibuat adalah tool untuk mengambil data tiket berdasarkan nomor tiket. Konsep yang sama bisa dikembangkan untuk PLATO, PIA, sistem helpdesk, ERP, database internal, atau API perusahaan.
Apa Itu MCP?
Sederhananya, MCP adalah “bahasa penghubung” antara AI dan aplikasi.
Tanpa MCP, AI hanya menerima teks dari pengguna lalu menghasilkan teks kembali.
User → LLM → Jawaban teks
Dengan MCP, AI dapat menentukan kapan perlu memakai fungsi dari sistem lain.
User → LLM / AI Host → MCP Client → MCP Server → API / Database
↑ ↓
└──── hasil tool ────┘
Contoh percakapan:
User: Tolong cek status tiket CEISA-2026-00123.
AI tidak perlu menebak status tiket. AI dapat memanggil tool MCP seperti berikut:
get_ticket(ticket_number = "CEISA-2026-00123")
MCP Server kemudian mengambil data dari database atau API tiket, lalu mengembalikan hasil terstruktur ke AI. Setelah itu AI menyampaikan hasilnya dengan bahasa yang mudah dipahami pengguna.
Komponen Utama dalam MCP
Ada empat komponen yang perlu dipahami.
| Komponen | Peran |
|---|---|
| User | Memberikan instruksi atau pertanyaan |
| AI Host | Aplikasi yang menjalankan LLM dan mengelola percakapan |
| MCP Client | Penghubung dari AI Host ke MCP Server |
| MCP Server | Aplikasi yang menyediakan tools, resources, atau prompts |
| Tool | Fungsi yang dapat dipanggil AI, misalnya get_ticket |
| Resource | Data seperti file, dokumen, atau referensi yang dapat dibaca AI |
| Prompt | Template instruksi yang disediakan oleh server |
Dalam artikel ini kita fokus pada tools, karena ini adalah bagian paling umum untuk integrasi aplikasi.
Kapan MCP Berguna?
MCP cocok ketika AI perlu berinteraksi dengan data atau proses yang tidak ada di dalam model.
Contohnya:
- Mengambil detail tiket helpdesk.
- Membaca status issue JIRA.
- Mencari SOP berdasarkan kode.
- Mengambil regulasi dari database RAG.
- Membuat draft laporan.
- Mengecek stok, harga, atau pesanan.
- Membuat tiket baru setelah pengguna menyetujui.
- Menjalankan analisis data operasional.
MCP bukan pengganti API. Justru MCP biasanya berada di atas API atau service internal yang sudah ada.
AI
↓
MCP Tool
↓
Service Java / REST API / Database / Elasticsearch / JIRA
Artinya, logika bisnis tetap sebaiknya berada pada service aplikasi. MCP berfungsi sebagai lapisan yang mendeskripsikan fungsi tersebut agar bisa dipahami dan dipanggil oleh AI.
Pilihan Transport: STDIO atau HTTP?
MCP dapat berjalan melalui beberapa cara komunikasi. Dua yang paling sering digunakan adalah STDIO dan HTTP.
| Transport | Cocok untuk | Karakteristik |
|---|---|---|
| STDIO | Tool lokal di laptop/server yang sama | Proses MCP dijalankan langsung oleh aplikasi AI |
| Streamable HTTP | Server terpusat, multi-user, aplikasi enterprise | MCP diakses melalui endpoint HTTP |
| SSE | Implementasi MCP HTTP generasi sebelumnya | Masih ditemui pada beberapa sistem lama |
Untuk belajar dari nol, STDIO paling mudah dipahami. Namun untuk aplikasi seperti PLATO atau PIA yang dipakai banyak pengguna, HTTP biasanya lebih relevan karena MCP Server dapat dipasang sebagai service terpisah.
Catatan penting: pada MCP berbasis STDIO, jangan menulis log menggunakan
System.out.println(). STDOUT dipakai untuk pertukaran pesan JSON-RPC MCP. Gunakan logger yang menulis ke STDERR atau file log.
Teknologi yang Digunakan
Contoh ini menggunakan:
- Java 17 atau lebih baru
- Spring Boot
- Spring AI MCP Server
- Maven
- MCP Inspector atau MCP Client untuk pengujian
Struktur sederhana proyek:
mcp-ticket-server/
├── pom.xml
└── src/
└── main/
├── java/
│ └── id/nirantara/mcp/
│ ├── McpTicketApplication.java
│ ├── TicketTools.java
│ ├── TicketService.java
│ └── TicketResponse.java
└── resources/
└── application.yml
Membuat Project Spring Boot
Buat proyek Spring Boot melalui Spring Initializr atau siapkan struktur Maven secara manual.
Berikut contoh pom.xml.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>id.nirantara</groupId>
<artifactId>mcp-ticket-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
<relativePath/>
</parent>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.1.0</spring-ai.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Versi dependency dapat berubah. Sebelum implementasi produksi, cek dokumentasi Spring AI dan MCP Java SDK untuk versi yang sesuai dengan Spring Boot yang digunakan.
Konfigurasi MCP Server
Buat file src/main/resources/application.yml.
spring:
application:
name: mcp-ticket-server
ai:
mcp:
server:
name: nirantara-ticket-server
version: 1.0.0
protocol: STREAMABLE
server:
port: 8089
logging:
level:
id.nirantara.mcp: INFO
Dengan konfigurasi tersebut, aplikasi akan berjalan sebagai MCP Server melalui HTTP. Nantinya AI Host atau MCP Client dapat mengakses server ini melalui endpoint yang disediakan oleh starter MCP.
Membuat Main Application
Buat file McpTicketApplication.java.
package id.nirantara.mcp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class McpTicketApplication {
public static void main(String[] args) {
SpringApplication.run(McpTicketApplication.class, args);
}
}
Membuat Model Respons Tiket
Buat file TicketResponse.java.
package id.nirantara.mcp;
public record TicketResponse(
String ticketNumber,
String title,
String status,
String application,
String solution,
String updatedAt
) {
}
Pada aplikasi nyata, objek ini dapat berasal dari database, API helpdesk, Elasticsearch, atau service internal lain.
Membuat Service untuk Mengambil Data
Buat file TicketService.java.
package id.nirantara.mcp;
import org.springframework.stereotype.Service;
@Service
public class TicketService {
public TicketResponse findByTicketNumber(String ticketNumber) {
// Contoh data sementara.
// Ganti bagian ini dengan query database atau pemanggilan API internal.
if ("CEISA-2026-00123".equalsIgnoreCase(ticketNumber)) {
return new TicketResponse(
"CEISA-2026-00123",
"OTP tidak diterima oleh pengguna",
"Resolved",
"CEISA 4.0",
"Pastikan nomor telepon terdaftar aktif, lalu lakukan pengiriman OTP ulang.",
"2026-08-11 09:30"
);
}
return null;
}
}
Contoh integrasi dengan REST API internal:
public TicketResponse findByTicketNumber(String ticketNumber) {
String url = "https://ticket-api.internal/api/tickets/" + ticketNumber;
// Gunakan RestClient, WebClient, atau Feign Client.
// Tambahkan timeout, autentikasi, dan penanganan error.
return restClient.get()
.uri(url)
.retrieve()
.body(TicketResponse.class);
}
Jangan menaruh credential API secara langsung di source code. Simpan token atau username/password pada environment variable, secret manager, atau konfigurasi terenkripsi.
Membuat MCP Tool
Bagian paling penting adalah mendefinisikan tool yang dapat ditemukan dan dipanggil oleh AI.
Buat file TicketTools.java.
package id.nirantara.mcp;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
@Component
public class TicketTools {
private final TicketService ticketService;
public TicketTools(TicketService ticketService) {
this.ticketService = ticketService;
}
@Tool(description = """
Mengambil detail tiket berdasarkan nomor tiket.
Gunakan tool ini apabila pengguna meminta status, detail,
solusi, atau informasi tiket tertentu.
""")
public TicketResponse getTicket(
@ToolParam(description = "Nomor tiket, contoh: CEISA-2026-00123")
String ticketNumber
) {
TicketResponse ticket = ticketService.findByTicketNumber(ticketNumber);
if (ticket == null) {
return new TicketResponse(
ticketNumber,
"Tiket tidak ditemukan",
"-",
"-",
"Periksa kembali nomor tiket yang diberikan.",
"-"
);
}
return ticket;
}
}
Anotasi @Tool membuat method tersebut didaftarkan sebagai kemampuan MCP. Deskripsi pada @Tool sangat penting karena AI memakai deskripsi ini untuk menentukan:
- kapan tool perlu dipanggil;
- data apa yang harus dikirim;
- hasil apa yang dapat diharapkan.
Nama method juga sebaiknya jelas. Gunakan kata kerja dan objek yang spesifik.
Contoh nama tool yang baik:
getTicket
searchTickets
getJiraIssue
createTicket
findSop
getTicketStatistics
Contoh nama yang kurang baik:
process
execute
doAction
getData
run
AI lebih mudah memilih tool jika nama dan deskripsinya menggambarkan fungsi bisnis secara langsung.
Mendaftarkan Tool ke MCP Server
Tambahkan konfigurasi berikut agar Spring Boot mengenali tool yang sudah dibuat.
package id.nirantara.mcp;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class McpToolConfiguration {
@Bean
public ToolCallbackProvider ticketToolsProvider(TicketTools ticketTools) {
return MethodToolCallbackProvider.builder()
.toolObjects(ticketTools)
.build();
}
}
Saat aplikasi berjalan, MCP Client dapat melakukan proses discovery dan mengetahui bahwa server memiliki tool bernama getTicket.
Menjalankan Aplikasi
Jalankan aplikasi menggunakan Maven.
./mvnw spring-boot:run
Atau build menjadi JAR.
./mvnw clean package
java -jar target/mcp-ticket-server-0.0.1-SNAPSHOT.jar
Jika berhasil, MCP Server berjalan di port 8089.
Menguji dengan MCP Inspector
MCP Inspector membantu menguji server sebelum dihubungkan ke AI assistant. Dengan Inspector, kita dapat:
- melihat daftar tools;
- memeriksa schema parameter;
- memanggil tool secara manual;
- melihat respons dan error;
- memastikan transport MCP sudah berjalan benar.
Contoh payload ketika memanggil getTicket:
{
"ticketNumber": "CEISA-2026-00123"
}
Contoh hasil:
{
"ticketNumber": "CEISA-2026-00123",
"title": "OTP tidak diterima oleh pengguna",
"status": "Resolved",
"application": "CEISA 4.0",
"solution": "Pastikan nomor telepon terdaftar aktif, lalu lakukan pengiriman OTP ulang.",
"updatedAt": "2026-08-11 09:30"
}
Menghubungkan MCP dengan LLM
Penting untuk dipahami: MCP Server bukan LLM dan tidak melakukan klasifikasi bahasa secara otomatis.
Alurnya biasanya seperti ini:
1. User bertanya:
"Cek status CEISA-2026-00123"
2. AI Host membaca pertanyaan.
3. LLM melihat daftar tools dari MCP Server.
4. LLM memilih:
getTicket(ticketNumber = "CEISA-2026-00123")
5. MCP Client memanggil MCP Server.
6. MCP Server mengambil data dari sistem tiket.
7. Hasil dikembalikan ke LLM.
8. LLM membuat jawaban natural untuk user.
Misalnya hasil akhir yang ditampilkan AI:
Tiket CEISA-2026-00123 saat ini berstatus Resolved. Kendalanya adalah OTP tidak diterima pengguna. Solusi yang dicatat adalah memastikan nomor telepon terdaftar aktif, lalu melakukan pengiriman OTP ulang.
Jadi, LLM berperan sebagai pengambil keputusan dan penyusun jawaban. MCP Server berperan sebagai penyedia kemampuan serta akses yang terkontrol ke sistem internal.
Contoh Tool untuk Sistem Ticketing
Dalam sistem seperti PLATO atau PIA, MCP dapat menyediakan beberapa tool berikut.
@Tool(description = "Mencari tiket berdasarkan kata kunci kendala.")
public List<TicketResponse> searchTickets(String keyword) {
return ticketService.search(keyword);
}
@Tool(description = "Mengambil statistik tiket berdasarkan rentang waktu dan aplikasi.")
public TicketStatisticResponse getTicketStatistics(
String application,
String startDate,
String endDate
) {
return ticketService.getStatistics(application, startDate, endDate);
}
@Tool(description = "Membuat tiket baru setelah data pengguna lengkap dan valid.")
public CreateTicketResponse createTicket(
String title,
String description,
String application,
String reporter
) {
return ticketService.createTicket(title, description, application, reporter);
}
Untuk tool yang mengubah data seperti createTicket, updateTicket, atau closeTicket, tambahkan validasi dan mekanisme persetujuan pengguna. Jangan membiarkan AI membuat perubahan penting tanpa kontrol.
Prinsip Keamanan MCP untuk Aplikasi Internal
MCP memudahkan AI memanggil fungsi aplikasi. Karena itu, desain keamanan harus direncanakan dari awal.
1. Bedakan Tool Baca dan Tool Ubah Data
Tool baca biasanya lebih aman.
getTicket
searchSop
getJiraIssue
getTicketStatistics
Tool yang mengubah data perlu perlindungan lebih ketat.
createTicket
updateTicket
assignTicket
closeTicket
deleteDocument
Untuk operasi perubahan data, gunakan konfirmasi pengguna, audit log, RBAC, dan validasi parameter.
2. Jangan Memberi Akses Database Langsung ke LLM
Arsitektur yang kurang aman:
LLM → Database produksi
Arsitektur yang lebih aman:
LLM → MCP Tool → Service Layer → Database
Dengan service layer, kita dapat membatasi query, memvalidasi input, menyaring data sensitif, dan mencatat aktivitas.
3. Terapkan Role-Based Access Control
Tool yang tersedia sebaiknya menyesuaikan role pengguna.
Contoh:
| Role | Akses |
|---|---|
| Helpdesk | Membaca dan membuat tiket |
| Supervisor | Membaca statistik dan melakukan assignment |
| Admin | Mengubah master data |
| Auditor | Membaca data serta audit log |
Jangan hanya mengandalkan prompt seperti “jangan tampilkan data rahasia”. Pemeriksaan hak akses harus dilakukan di backend Java.
4. Batasi Data yang Dikembalikan
Jangan selalu mengembalikan seluruh data tiket, terutama bila terdapat nomor telepon, email, NIK, token, credential, atau catatan internal sensitif.
Gunakan DTO khusus untuk AI.
public record SafeTicketResponse(
String ticketNumber,
String title,
String status,
String application,
String solution
) {
}
5. Catat Audit Log
Setiap pemanggilan tool perlu dicatat.
waktu
user_id
role
tool_name
parameter
status
durasi
hasil ringkas
Audit log membantu investigasi ketika ada akses tidak wajar atau hasil AI perlu ditelusuri kembali.
Kesalahan yang Sering Terjadi
Menganggap MCP adalah Pengganti API
MCP bukan pengganti REST API, database, atau service bisnis. MCP adalah lapisan integrasi agar AI dapat menggunakan kemampuan sistem secara standar.
Membuat Tool Terlalu Umum
Tool seperti executeQuery(sql) sangat berisiko karena memberi AI kemampuan terlalu luas.
Lebih baik buat tool spesifik:
getTicket(ticketNumber)
getOpenTickets(application)
getTicketStatistics(startDate, endDate)
Deskripsi Tool Tidak Jelas
Deskripsi yang buruk membuat AI salah memilih tool atau salah mengisi parameter.
Kurang jelas:
@Tool(description = "Mengambil data")
Lebih jelas:
@Tool(description = """
Mengambil detail tiket berdasarkan nomor tiket.
Gunakan hanya jika pengguna menyebutkan nomor tiket.
Jangan gunakan untuk pencarian berdasarkan kata kunci.
""")
Terlalu Banyak Log ke STDOUT
Untuk transport STDIO, output sembarangan ke console dapat merusak komunikasi JSON-RPC. Gunakan logging framework seperti SLF4J dan pastikan output log diarahkan ke STDERR atau file.
Pengembangan Berikutnya
Setelah tool pertama berhasil, MCP Server dapat dikembangkan bertahap.
- Menghubungkan
TicketServiceke database atau API sebenarnya. - Menambahkan autentikasi antar-service.
- Menambahkan RBAC berdasarkan pengguna AI.
- Menambahkan audit log.
- Membuat tool pencarian SOP dan regulasi.
- Menambahkan tool statistik tiket.
- Menghubungkan ke JIRA.
- Menambahkan cache untuk query yang sering digunakan.
- Menambahkan monitoring latency dan error rate.
- Memisahkan tool berdasarkan domain: Ticket, SOP, Regulation, JIRA, dan Reporting.
Untuk PIA, pola MCP dapat digunakan seperti berikut:
PIA / LLM
├── MCP Ticket Server
├── MCP SOP Server
├── MCP Regulation Server
├── MCP JIRA Server
└── MCP Reporting Server
Dengan pemisahan ini, tiap domain memiliki akses, validasi, dan audit log sendiri. Sistem menjadi lebih mudah dirawat dibandingkan satu aplikasi AI yang langsung terhubung ke seluruh database dan API.
Penutup
MCP membuat AI dapat berinteraksi dengan sistem nyata secara lebih terstruktur. Pada Java, pendekatan yang praktis adalah memakai Spring Boot sebagai fondasi aplikasi, lalu mendaftarkan method bisnis sebagai MCP tools.
Mulailah dari satu tool yang aman dan spesifik, misalnya getTicket. Setelah alur discovery, pemanggilan tool, dan respons berjalan stabil, barulah tambahkan tool lain seperti pencarian SOP, statistik tiket, integrasi JIRA, atau pembuatan tiket.
Kunci implementasi MCP yang baik bukan hanya membuat AI bisa memanggil fungsi, tetapi memastikan fungsi tersebut memiliki batas akses yang jelas, validasi kuat, audit log, dan data respons yang aman.
Referensi
Published by Nirantara
Nirantara is an Indonesian Enterprise AI company specializing in Enterprise AI, RAG, Intelligent Search, and AI Automation. Article written by jsturana.