본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2026. 2. 1. · 7 Views
MCP 어노테이션 기반 개발 완벽 가이드
Spring AI와 MCP(Model Context Protocol)를 활용한 어노테이션 기반 도구 개발 방법을 알아봅니다. 선언적 프로그래밍으로 AI 에이전트용 도구를 쉽게 만드는 방법을 초급자도 이해할 수 있게 설명합니다.
목차
1. Spring 어노테이션 패턴
김개발 씨는 입사 첫 주에 Spring 프로젝트의 코드를 보다가 신기한 것을 발견했습니다. 클래스 위에 붙어있는 @Controller, @Service 같은 표시들이 도대체 무엇인지 궁금했습니다.
선배에게 물어보니 "그게 바로 어노테이션이야. Spring의 핵심이지"라는 대답이 돌아왔습니다.
어노테이션은 코드에 메타데이터를 추가하는 선언적 방식입니다. 마치 책에 붙이는 포스트잇처럼, 코드가 어떤 역할을 해야 하는지 프레임워크에게 알려주는 표식입니다.
이를 통해 설정 코드를 직접 작성하지 않고도 원하는 동작을 선언만으로 구현할 수 있습니다.
다음 코드를 살펴봅시다.
// Spring의 대표적인 어노테이션 패턴
@RestController // 이 클래스가 REST API를 처리한다고 선언
@RequestMapping("/api/users") // 기본 URL 경로 설정
public class UserController {
@Autowired // 의존성을 자동으로 주입해달라고 요청
private UserService userService;
@GetMapping("/{id}") // GET 요청을 처리하는 메서드
public User getUser(@PathVariable Long id) {
// PathVariable: URL의 {id} 부분을 파라미터로 받음
return userService.findById(id);
}
}
김개발 씨는 입사 3개월 차 주니어 개발자입니다. 어느 날 레거시 프로젝트의 XML 설정 파일을 보다가 머리가 아파왔습니다.
수백 줄에 달하는 설정 파일을 이해하려면 하루 종일 걸릴 것 같았습니다. 그때 옆자리 박시니어 씨가 다가와 말했습니다.
"요즘은 그렇게 안 해도 돼요. 어노테이션을 쓰면 훨씬 간단해져요." 그렇다면 어노테이션이란 정확히 무엇일까요?
쉽게 비유하자면, 어노테이션은 마치 택배 상자에 붙이는 스티커와 같습니다. "취급주의", "냉장보관", "이 면을 위로" 같은 스티커를 보면 택배 기사님이 어떻게 처리해야 할지 바로 알 수 있습니다.
마찬가지로 @Controller 어노테이션을 보면 Spring 프레임워크가 "아, 이 클래스는 컨트롤러로 등록해야겠구나"라고 이해합니다. 어노테이션이 없던 시절에는 어땠을까요?
개발자들은 모든 설정을 XML 파일에 일일이 작성해야 했습니다. 빈(Bean) 하나를 등록하려면 XML에 여러 줄의 설정을 추가해야 했고, 오타라도 나면 애플리케이션이 실행조차 되지 않았습니다.
코드와 설정이 분리되어 있어서 "이 클래스가 어떤 역할을 하는지" 파악하려면 두 파일을 번갈아 봐야 했습니다. 바로 이런 문제를 해결하기 위해 어노테이션 기반 설정이 등장했습니다.
어노테이션을 사용하면 코드와 설정이 한 곳에 모입니다. 클래스를 보는 순간 이것이 컨트롤러인지, 서비스인지, 리포지토리인지 바로 알 수 있습니다.
또한 IDE의 자동완성 기능도 사용할 수 있어서 오타 걱정도 줄어듭니다. 위의 코드를 살펴보겠습니다.
먼저 @RestController는 이 클래스가 REST API를 처리하는 컨트롤러라고 선언합니다. 이 한 줄로 Spring은 이 클래스의 메서드 반환값을 자동으로 JSON으로 변환해줍니다.
@RequestMapping은 이 컨트롤러가 처리할 URL 경로를 지정합니다. @GetMapping은 HTTP GET 요청을 처리하는 메서드임을 나타냅니다.
실제 현업에서는 이 패턴이 거의 모든 Spring 프로젝트에 사용됩니다. 예를 들어 쇼핑몰을 개발한다면 ProductController, OrderController, CartController 등 수십 개의 컨트롤러가 필요합니다.
어노테이션이 없다면 각각에 대한 XML 설정을 별도로 관리해야 하는데, 어노테이션 덕분에 클래스 위에 @RestController만 붙이면 끝입니다. 하지만 주의할 점도 있습니다.
어노테이션을 과도하게 사용하면 오히려 코드가 복잡해질 수 있습니다. 하나의 클래스에 너무 많은 어노테이션이 붙어있다면, 그 클래스가 너무 많은 책임을 지고 있다는 신호일 수 있습니다.
박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "그래서 모든 곳에 @가 붙어있었군요!" 이제 MCP에서도 이 익숙한 패턴을 활용하게 됩니다.
실전 팁
💡 - 어노테이션은 컴파일 타임에 검증되므로 런타임 오류를 줄일 수 있습니다
- 커스텀 어노테이션을 만들어 반복되는 로직을 추상화할 수 있습니다
2. @McpTool 어노테이션
김개발 씨가 AI 에이전트용 도구를 개발하라는 미션을 받았습니다. "MCP라는 프로토콜을 사용해서 만들어야 해"라는 말에 막막했지만, Spring AI의 @McpTool 어노테이션을 알게 된 후로 상황이 달라졌습니다.
익숙한 Spring 스타일로 AI 도구를 만들 수 있다니, 신세계가 열린 기분이었습니다.
@McpTool은 Spring AI MCP 서버에서 제공하는 핵심 어노테이션입니다. 이 어노테이션을 메서드에 붙이면 해당 메서드가 AI 에이전트가 호출할 수 있는 도구로 자동 등록됩니다.
마치 @GetMapping이 HTTP 요청을 처리하듯, @McpTool은 AI 에이전트의 요청을 처리합니다.
다음 코드를 살펴봅시다.
@Service
public class WeatherTool {
// AI 에이전트가 호출할 수 있는 도구로 등록
@McpTool(name = "get_weather",
description = "특정 도시의 현재 날씨를 조회합니다")
public WeatherInfo getWeather(
@McpParam(description = "날씨를 조회할 도시명")
String city) {
// 실제 날씨 API 호출 로직
return weatherService.fetchWeather(city);
}
// 여러 도구를 하나의 클래스에 정의 가능
@McpTool(name = "get_forecast",
description = "5일간의 날씨 예보를 조회합니다")
public List<Forecast> getForecast(String city, int days) {
return weatherService.fetchForecast(city, days);
}
}
김개발 씨는 MCP 프로토콜 문서를 읽다가 한숨을 쉬었습니다. JSON-RPC 스펙, 프로토콜 핸드셰이크, 도구 스키마 정의...
이 모든 것을 직접 구현해야 한다니 막막했습니다. 그때 박시니어 씨가 다가와 화면을 보더니 말했습니다.
"굳이 그렇게 힘들게 할 필요 없어요. Spring AI MCP를 쓰면 어노테이션 하나로 끝나요." **MCP(Model Context Protocol)**는 AI 에이전트가 외부 도구와 통신하기 위한 표준 프로토콜입니다.
쉽게 비유하자면, MCP는 마치 통역사와 같습니다. AI 모델이 "날씨 알려줘"라고 말하면, MCP가 이를 적절한 함수 호출로 번역하고, 결과를 다시 AI가 이해할 수 있는 형태로 전달해줍니다.
개발자는 통역의 세부 사항을 몰라도, 그냥 한국어로 말하면 됩니다. 그렇다면 @McpTool은 어떻게 동작할까요?
이 어노테이션을 메서드에 붙이면 Spring AI가 해당 메서드를 스캔합니다. 그리고 자동으로 MCP 프로토콜에 맞는 도구 정의를 생성하고, 도구 목록에 등록합니다.
AI 에이전트가 "사용 가능한 도구 목록을 알려줘"라고 요청하면, Spring은 @McpTool이 붙은 모든 메서드 정보를 응답합니다. 위 코드에서 핵심을 살펴보겠습니다.
name 속성은 AI 에이전트가 도구를 호출할 때 사용하는 식별자입니다. "get_weather"라고 지정하면 AI가 이 이름으로 도구를 호출합니다.
description은 AI가 이 도구가 무엇을 하는지 이해하는 데 사용됩니다. 이 설명을 보고 AI가 "아, 날씨가 필요할 때 이 도구를 쓰면 되겠구나"라고 판단합니다.
@McpParam도 중요한 역할을 합니다. 이 어노테이션은 각 파라미터가 무엇인지 설명합니다.
AI 에이전트는 이 설명을 보고 어떤 값을 전달해야 하는지 이해합니다. "날씨를 조회할 도시명"이라는 설명을 보고 AI는 사용자가 "서울 날씨"라고 물었을 때 city 파라미터에 "서울"을 넣어야 한다고 판단합니다.
실제 현업에서는 다양한 도구를 이 방식으로 개발합니다. 데이터베이스 조회, 외부 API 호출, 파일 처리, 이메일 발송 등 AI 에이전트가 수행해야 할 모든 작업을 @McpTool로 정의할 수 있습니다.
기존에 만들어둔 서비스 메서드에 어노테이션만 추가하면 바로 AI 도구가 됩니다. 주의할 점이 있습니다.
description을 대충 작성하면 AI가 도구를 제대로 선택하지 못합니다. "날씨 조회"보다 "특정 도시의 현재 기온, 습도, 날씨 상태를 조회합니다"처럼 구체적으로 작성해야 합니다.
김개발 씨는 감탄했습니다. "진짜 Spring 컨트롤러 만들듯이 AI 도구를 만들 수 있네요!" 박시니어 씨가 웃으며 말했습니다.
"그게 바로 Spring AI의 매력이에요."
실전 팁
💡 - description은 AI가 도구를 선택하는 기준이므로 명확하고 구체적으로 작성하세요
- 하나의 도구는 하나의 명확한 책임만 갖도록 설계하세요
3. 자동 스키마 생성
김개발 씨가 MCP 도구를 구현하다가 문서를 보니 "JSON Schema를 정의해야 합니다"라는 문구가 있었습니다. 파라미터 타입, 필수 여부, 설명을 일일이 JSON으로 작성해야 한다니 머리가 아팠습니다.
하지만 Spring AI MCP는 이 모든 것을 자동으로 생성해준다는 사실을 알게 되었습니다.
자동 스키마 생성은 Java 메서드 시그니처를 분석하여 MCP 프로토콜에 필요한 JSON Schema를 자동으로 만들어주는 기능입니다. 개발자는 평소처럼 Java 코드를 작성하면 되고, 프레임워크가 타입 정보를 읽어 AI에게 전달할 스키마를 생성합니다.
수동 작업으로 인한 오류를 원천 차단할 수 있습니다.
다음 코드를 살펴봅시다.
@McpTool(name = "create_order",
description = "새로운 주문을 생성합니다")
public OrderResult createOrder(
// Java 타입에서 자동으로 스키마 생성
@McpParam(description = "고객 ID", required = true)
Long customerId,
@McpParam(description = "주문할 상품 목록")
List<OrderItem> items,
@McpParam(description = "배송 주소")
Address shippingAddress,
@McpParam(description = "쿠폰 코드 (선택사항)", required = false)
String couponCode
) {
// 비즈니스 로직 처리
return orderService.create(customerId, items, shippingAddress, couponCode);
}
// 자동 생성되는 JSON Schema (개발자가 작성할 필요 없음):
// { "type": "object", "properties": { "customerId": { "type": "integer" }, ... }}
김개발 씨는 예전에 REST API 문서를 수동으로 작성하다가 고생한 적이 있습니다. 코드를 수정할 때마다 문서도 함께 수정해야 했는데, 어느 순간 코드와 문서가 따로 놀기 시작했습니다.
버그 리포트가 들어오면 문서가 틀렸는지, 코드가 틀렸는지 확인하느라 시간을 허비했습니다. 박시니어 씨가 그때를 떠올리며 말했습니다.
"그래서 요즘은 코드가 곧 문서인 방식을 선호해요. MCP에서도 마찬가지예요." 자동 스키마 생성의 원리는 간단합니다.
Spring AI는 리플렉션을 사용하여 @McpTool이 붙은 메서드를 분석합니다. 파라미터의 타입이 Long이면 JSON Schema에서 "integer"로, String이면 "string"으로, List<T>면 "array"로 변환합니다.
개발자가 Java로 작성한 타입 정보가 그대로 AI에게 전달될 스키마가 되는 것입니다. 마치 번역가가 자동으로 일해주는 것과 같습니다.
여러분이 한국어로 책을 쓰면 번역가가 알아서 영어, 일본어, 중국어 버전을 만들어줍니다. 여러분은 한국어에만 집중하면 됩니다.
마찬가지로 개발자는 Java 코드에만 집중하면 되고, Spring AI가 알아서 MCP 스키마를 생성해줍니다. 위 코드에서 주목할 점을 살펴보겠습니다.
Long customerId는 자동으로 { "type": "integer" }로 변환됩니다. List<OrderItem> items는 { "type": "array", "items": { ...
} }로 변환되고, OrderItem 클래스의 필드도 재귀적으로 분석됩니다. Address shippingAddress처럼 복잡한 객체도 내부 구조가 자동으로 스키마화됩니다.
@McpParam의 속성들도 스키마에 반영됩니다. required = true로 설정하면 JSON Schema의 required 배열에 해당 필드가 추가됩니다.
description은 스키마의 description 필드로 들어갑니다. 이 정보를 바탕으로 AI 에이전트는 "아, customerId는 필수고, couponCode는 선택이구나"라고 판단할 수 있습니다.
이 기능의 진정한 가치는 유지보수에서 드러납니다. 파라미터 타입을 Long에서 String으로 변경하면?
스키마도 자동으로 업데이트됩니다. 새 파라미터를 추가하면?
스키마에도 자동으로 반영됩니다. 코드와 스키마가 항상 동기화되므로 "문서와 코드가 다른" 문제가 원천적으로 발생하지 않습니다.
주의할 점도 있습니다. 너무 복잡한 객체 구조는 AI가 이해하기 어려울 수 있습니다.
3단계 이상의 중첩된 객체보다는 평평한(flat) 구조가 AI 에이전트의 정확도를 높입니다. 김개발 씨는 안도의 한숨을 쉬었습니다.
"JSON Schema를 직접 안 써도 되다니... 정말 다행이에요."
실전 팁
💡 - 복잡한 객체는 별도의 DTO로 분리하고 명확한 필드명을 사용하세요
- Enum 타입을 활용하면 허용 가능한 값 목록이 스키마에 자동 포함됩니다
4. 파라미터 검증
어느 날 김개발 씨가 만든 MCP 도구에서 오류가 발생했습니다. AI 에이전트가 음수 값을 보내왔는데, 서비스 로직이 이를 처리하지 못했던 것입니다.
"입력값 검증을 안 했구나..." 반성하던 김개발 씨에게 박시니어 씨가 Bean Validation과 MCP를 결합하는 방법을 알려주었습니다.
파라미터 검증은 AI 에이전트가 전달한 입력값이 유효한지 확인하는 과정입니다. Spring AI MCP는 Java Bean Validation(JSR-380)과 통합되어 @NotNull, @Min, @Max 같은 표준 어노테이션을 그대로 사용할 수 있습니다.
검증 실패 시 명확한 오류 메시지가 AI에게 전달됩니다.
다음 코드를 살펴봅시다.
@McpTool(name = "transfer_money",
description = "계좌 간 송금을 실행합니다")
public TransferResult transferMoney(
@McpParam(description = "출금 계좌번호")
@NotBlank(message = "출금 계좌번호는 필수입니다")
@Pattern(regexp = "\\d{10,14}", message = "계좌번호는 10-14자리 숫자입니다")
String fromAccount,
@McpParam(description = "입금 계좌번호")
@NotBlank String toAccount,
@McpParam(description = "송금 금액 (원)")
@NotNull
@Min(value = 1000, message = "최소 송금액은 1,000원입니다")
@Max(value = 50000000, message = "1회 최대 송금액은 5천만원입니다")
Long amount
) {
// 검증을 통과한 안전한 값으로 비즈니스 로직 실행
return bankService.transfer(fromAccount, toAccount, amount);
}
김개발 씨는 금융 서비스의 송금 기능을 MCP 도구로 개발했습니다. 테스트할 때는 잘 동작했는데, 실제로 AI 에이전트가 사용하기 시작하니 이상한 요청이 들어왔습니다.
송금액이 -10000원? 계좌번호가 "abc"?
AI가 환각(hallucination)을 일으킨 것인지, 아니면 사용자가 이상한 요청을 한 것인지 알 수 없었습니다. 박시니어 씨가 조언했습니다.
"AI를 100% 신뢰하면 안 돼요. 사람 입력과 마찬가지로 항상 검증해야 해요." 파라미터 검증이 중요한 이유가 바로 여기에 있습니다.
마치 공항의 보안 검색대와 같습니다. 탑승객이 아무리 "저는 괜찮은 사람이에요"라고 말해도, 보안 검색대를 통과해야 합니다.
AI 에이전트가 보낸 데이터도 마찬가지입니다. "AI가 보냈으니까 괜찮겠지"가 아니라, 반드시 검증을 거쳐야 합니다.
Spring AI MCP는 Bean Validation을 완벽하게 지원합니다. Java EE 표준인 JSR-380 어노테이션을 @McpParam과 함께 사용할 수 있습니다.
@NotNull, @NotBlank, @Min, @Max, @Size, @Pattern 등 익숙한 어노테이션을 그대로 활용하면 됩니다. 검증 로직을 별도로 작성할 필요가 없습니다.
위 코드를 분석해보겠습니다. @NotBlank는 null도 아니고 빈 문자열도 아니어야 한다는 의미입니다.
@Pattern은 정규표현식으로 형식을 검증합니다. 계좌번호가 숫자 10-14자리인지 확인하는 것이죠.
@Min과 @Max는 숫자의 범위를 제한합니다. 1,000원 미만이나 5천만원 초과 송금은 거부됩니다.
검증에 실패하면 어떻게 될까요? Spring AI MCP는 검증 실패 시 명확한 오류 메시지를 AI 에이전트에게 반환합니다.
"최소 송금액은 1,000원입니다"라는 메시지를 받은 AI는 이 정보를 사용자에게 전달하거나, 수정된 값으로 다시 시도할 수 있습니다. 모호한 "오류 발생" 대신 구체적인 피드백을 제공하는 것이죠.
실무에서는 계층별 검증을 권장합니다. MCP 도구 레벨에서 기본적인 형식 검증을 하고, 서비스 레벨에서 비즈니스 규칙 검증을 합니다.
예를 들어 "계좌번호 형식"은 MCP에서, "잔액 충분 여부"는 서비스에서 검증하는 식입니다. 주의할 점도 있습니다.
오류 메시지에 민감한 정보를 포함하면 안 됩니다. "계좌 잔액이 150만원이라 200만원 송금 불가"처럼 구체적인 잔액을 노출하는 것은 보안상 위험합니다.
"잔액이 부족합니다" 정도로만 표현하세요. 김개발 씨는 모든 MCP 도구에 검증 어노테이션을 추가했습니다.
"이제 AI가 이상한 값을 보내도 안심이에요!"
실전 팁
💡 - 커스텀 검증이 필요하면 @Constraint 어노테이션으로 직접 Validator를 구현할 수 있습니다
- 오류 메시지는 AI가 이해하고 수정할 수 있도록 구체적으로 작성하세요
5. 개발 생산성 향상
프로젝트 마감이 코앞으로 다가왔습니다. 김개발 씨는 아직 10개의 MCP 도구를 더 만들어야 했습니다.
예전 같았으면 야근 각오를 했겠지만, Spring AI MCP의 어노테이션 기반 개발 덕분에 정시 퇴근이 가능했습니다. "이게 진짜 생산성이구나" 하고 감탄했습니다.
어노테이션 기반 개발은 보일러플레이트 코드를 획기적으로 줄여 개발 생산성을 높입니다. 개발자는 비즈니스 로직에만 집중하고, 프로토콜 처리, 스키마 생성, 직렬화/역직렬화는 프레임워크가 담당합니다.
기존 Spring 경험을 그대로 활용할 수 있어 학습 곡선도 완만합니다.
다음 코드를 살펴봅시다.
// Before: 수동으로 MCP 도구 구현 (약 50줄 이상)
public class ManualWeatherTool implements McpToolHandler {
@Override
public ToolDefinition getDefinition() {
return ToolDefinition.builder()
.name("get_weather")
.description("...")
.inputSchema(JsonSchema.builder()
.addProperty("city", StringSchema.builder()...)
// ... 수십 줄의 스키마 정의
.build();
}
// ... 더 많은 보일러플레이트
}
// After: 어노테이션 기반 (5줄)
@McpTool(name = "get_weather", description = "현재 날씨를 조회합니다")
public Weather getWeather(@McpParam(description = "도시명") String city) {
return weatherApi.fetch(city);
}
김개발 씨는 과거를 회상했습니다. 첫 직장에서 REST API를 개발할 때 서블릿을 직접 사용했던 기억이 납니다.
HttpServletRequest에서 파라미터를 꺼내고, JSON으로 변환하고, 응답 헤더를 설정하고... 간단한 API 하나에 50줄이 넘는 코드가 필요했습니다.
그러다 Spring MVC를 처음 만났을 때의 충격은 잊을 수 없었습니다. @GetMapping 하나면 끝이라니!
MCP 개발에서도 같은 혁신이 일어났습니다. 수동으로 MCP 도구를 구현하려면 해야 할 일이 많습니다.
ToolDefinition 객체를 생성하고, InputSchema를 JSON Schema 빌더로 정의하고, 파라미터 파싱 로직을 작성하고, 결과 직렬화 코드를 추가해야 합니다. 도구 하나당 50-100줄의 코드가 필요합니다.
어노테이션 기반으로 바꾸면 어떻게 될까요? @McpTool과 @McpParam 어노테이션을 붙이면 끝입니다.
5-10줄이면 충분합니다. 나머지 40-90줄의 코드는 프레임워크가 자동으로 처리합니다.
이것이 10배의 생산성 향상입니다. 마치 공장 자동화와 같습니다.
예전에는 숙련공이 직접 부품을 조립했지만, 지금은 로봇이 대부분의 작업을 수행합니다. 사람은 로봇이 못하는 고도의 판단만 하면 됩니다.
마찬가지로 개발자는 비즈니스 로직이라는 "고도의 판단"에 집중하고, 반복적인 코드 생성은 프레임워크에게 맡깁니다. 생산성 향상의 또 다른 측면은 학습 곡선입니다.
이미 Spring을 알고 있는 개발자라면 @Controller가 @McpTool로, @RequestParam이 @McpParam으로 바뀐 것뿐입니다. 새로운 패러다임을 처음부터 배울 필요가 없습니다.
기존 지식을 90% 이상 재사용할 수 있습니다. 유지보수 관점에서도 이점이 있습니다.
코드가 짧으면 버그가 숨을 곳도 적어집니다. 50줄의 보일러플레이트 중간에 숨어있던 버그를 찾는 것과, 5줄의 핵심 로직에서 버그를 찾는 것.
어느 쪽이 쉬울까요? 코드 리뷰도 빨라지고, 온보딩도 쉬워집니다.
팀 레벨에서의 효과도 큽니다. 10개의 MCP 도구를 개발해야 하는 상황에서, 수동 방식이라면 5,000줄의 코드가 필요합니다.
어노테이션 방식이라면 500줄이면 됩니다. 코드 리뷰에 걸리는 시간, 테스트 작성 시간, 버그 수정 시간 모두 10분의 1로 줄어듭니다.
김개발 씨는 정시에 퇴근하며 생각했습니다. "좋은 도구를 쓰는 것도 개발자의 실력이야."
실전 팁
💡 - 기존 서비스 메서드에 어노테이션만 추가하면 바로 MCP 도구가 됩니다
- 반복되는 패턴은 커스텀 어노테이션으로 추상화하여 더 간결하게 만들 수 있습니다
6. 베스트 프랙티스
김개발 씨가 MCP 도구 개발에 익숙해질 무렵, 팀에 새로운 주니어 개발자가 들어왔습니다. 김개발 씨는 이제 가르치는 입장이 되었습니다.
"내가 겪었던 시행착오를 후배는 안 겪게 해줘야지." 그는 베스트 프랙티스를 정리하기 시작했습니다.
베스트 프랙티스는 현업에서 검증된 최선의 개발 방법입니다. MCP 어노테이션 기반 개발에서는 명확한 네이밍, 상세한 설명, 적절한 도구 분리, 에러 처리, 보안 고려 등이 핵심입니다.
이 원칙들을 따르면 AI 에이전트가 도구를 더 정확하게 사용하고, 유지보수도 쉬워집니다.
다음 코드를 살펴봅시다.
// 베스트 프랙티스를 적용한 MCP 도구 예시
@Service
@Slf4j // 로깅 추가
public class CustomerTool {
private final CustomerService customerService;
private final AuditLogger auditLogger; // 감사 로깅
// 1. 명확하고 구체적인 이름과 설명
@McpTool(
name = "search_customers",
description = "이름, 이메일, 전화번호로 고객을 검색합니다. " +
"최대 50명까지 반환되며, 정확히 일치하는 결과만 포함됩니다."
)
// 2. 결과 타입을 명확하게 (List<Customer>가 아닌 SearchResult)
public CustomerSearchResult searchCustomers(
@McpParam(description = "검색할 고객 이름 (2자 이상)", required = false)
@Size(min = 2, message = "검색어는 2자 이상이어야 합니다")
String name,
@McpParam(description = "검색할 이메일 주소", required = false)
@Email String email
) {
// 3. 로깅으로 디버깅 용이성 확보
log.info("고객 검색 요청: name={}, email={}", name, email);
// 4. 비즈니스 로직은 서비스 계층에 위임
return customerService.search(name, email);
}
}
김개발 씨는 후배에게 첫 번째 원칙을 알려주었습니다. "이름과 설명이 반이야." AI 에이전트는 코드를 보지 못합니다.
오직 name과 description만 보고 어떤 도구를 사용할지 결정합니다. "search"보다 "search_customers"가 낫고, "고객 검색"보다 "이름, 이메일, 전화번호로 고객을 검색합니다"가 낫습니다.
마치 도서관 책 제목처럼, 내용을 보지 않아도 무슨 책인지 알 수 있어야 합니다. 두 번째 원칙은 "하나의 도구는 하나의 일만"입니다.
searchAndUpdateCustomer처럼 여러 기능을 합치면 AI가 혼란스러워합니다. 검색만 할 때도 이 도구를 써야 하나?
업데이트만 할 때는? 차라리 searchCustomers와 updateCustomer를 분리하는 것이 낫습니다.
유닉스 철학의 "한 가지를 잘하라"는 원칙과 같습니다. 세 번째는 "결과 타입을 명확하게"입니다.
List<Customer>를 반환하면 AI가 "이게 전체 결과야? 일부야?
정렬되어 있어?"라고 혼란스러워할 수 있습니다. CustomerSearchResult라는 래퍼 객체를 만들어 totalCount, hasMore, items 같은 메타데이터를 함께 제공하면 AI가 결과를 더 잘 해석할 수 있습니다.
네 번째는 "에러 처리를 명확하게"입니다. 예외가 발생했을 때 스택 트레이스가 AI에게 그대로 전달되면 좋지 않습니다.
사용자에게 불필요한 기술 정보가 노출되고, AI도 어떻게 대응해야 할지 알 수 없습니다. 비즈니스 예외는 명확한 메시지로 변환하고, 시스템 예외는 로깅 후 일반적인 오류 메시지를 반환하세요.
다섯 번째는 "보안을 항상 고려하라"입니다. AI 에이전트가 호출한다고 해서 보안 검사를 생략하면 안 됩니다.
사용자 인증/인가 확인, 입력값 검증, SQL 인젝션 방지 등 웹 개발에서 하던 보안 조치를 동일하게 적용해야 합니다. AI가 악의적인 프롬프트에 속아 위험한 요청을 보낼 수도 있습니다.
여섯 번째는 "로깅으로 디버깅을 준비하라"입니다. AI 에이전트와의 상호작용은 디버깅하기 어렵습니다.
어떤 파라미터로 호출되었는지, 어떤 결과가 반환되었는지 로그로 남겨두면 문제 발생 시 원인 파악이 쉬워집니다. 단, 개인정보는 마스킹하는 것을 잊지 마세요.
일곱 번째는 "비즈니스 로직은 서비스 계층에"입니다. MCP 도구 메서드 안에 복잡한 비즈니스 로직을 넣으면 테스트가 어려워집니다.
도구는 파라미터를 받아서 서비스에 위임하고 결과를 반환하는 얇은 계층으로 유지하세요. 후배 개발자가 고개를 끄덕였습니다.
"형이 겪었던 시행착오 덕분에 저는 바로 제대로 된 방법을 배우네요." 김개발 씨가 웃으며 말했습니다. "이게 팀워크지.
나도 박시니어 씨한테 배운 거야."
실전 팁
💡 - 도구 이름은 동사_명사 형식으로 통일하세요 (search_customers, create_order)
- 정기적으로 도구 사용 로그를 분석하여 AI가 자주 실패하는 패턴을 개선하세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
AI 에이전트의 Task Decomposition & Planning 완벽 가이드
AI 에이전트가 복잡한 작업을 어떻게 분해하고 계획하는지 알아봅니다. 작업 분해 전략부터 동적 재계획까지, 에이전트 개발의 핵심 개념을 실무 예제와 함께 쉽게 설명합니다.
에이전트 강화 미세조정 RFT 완벽 가이드
AI 에이전트가 스스로 학습하고 적응하는 강화 미세조정(RFT) 기법을 알아봅니다. 온라인/오프라인 학습부터 A/B 테스팅까지 실무에서 바로 적용할 수 있는 핵심 개념을 다룹니다.
Voice Clone 구현 완벽 가이드
음성 복제(Voice Clone) 기술을 활용하여 특정 화자의 목소리를 재현하는 방법을 알아봅니다. 참조 오디오 준비부터 실전 구현까지, 초급 개발자도 따라할 수 있도록 단계별로 설명합니다.
Qwen3-TTS 프로젝트 소개
알리바바가 공개한 최신 텍스트-음성 변환 프로젝트 Qwen3-TTS를 소개합니다. 음성 복제부터 10개 언어 지원까지, 차세대 TTS 기술의 핵심을 초급 개발자 눈높이에서 살펴봅니다.
AI 에이전트 패턴 완벽 가이드
LLM 기반 AI 에이전트를 프로덕션 환경에서 성공적으로 구축하기 위한 핵심 패턴들을 소개합니다. 튜토리얼과 실제 제품 사이의 간극을 메우고, 8가지 카테고리로 정리된 패턴들을 통해 실무에서 바로 적용할 수 있는 지식을 전달합니다.