lugautier/calendar-mcp-service
If you are the rightful owner of calendar-mcp-service and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
This is a Model Context Protocol (MCP) server that provides a standardized interface for Microsoft 365 Calendar operations using the official MCP Java SDK.
Calendar MCP Service
MCP (Model Context Protocol) server that exposes Microsoft 365 Calendar operations using the official MCP Java SDK.
Overview
This Spring Boot service provides a standardized MCP interface for calendar operations, enabling AI assistants (like Claude) to interact with Microsoft 365 calendars through a dedicated orchestrator.
Key Technologies:
- Java 21 LTS + Spring Boot 3.5.6
- Official MCP Java SDK 0.12.1 (handles all protocol operations)
- Microsoft Graph SDK 6.15.0 (calendar integration)
Protocol: The MCP SDK automatically handles JSON-RPC 2.0, transport (SSE/HTTP), and method routing. We only implement business logic.
Architecture
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā MCP Client (NestJS Orchestrator) ā
ā {"method": "tools/call", "params": {...}} ā
āāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā HTTP/SSE
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā McpServer (SDK - Spring Bean) ā
ā āā Transport Layer (mcp-spring-webmvc) ā
ā āā Protocol Parser (JSON-RPC 2.0) ā
ā āā Method Router ā
āāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā CalendarToolsProvider ā
ā āā get_events handler ā
ā āā block_dates handler ā
ā āā find_available_slots handler ā
ā āā reschedule_event handler ā
āāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā CalendarService (Business Logic) ā
ā āā Date validation ā
ā āā Event transformation ā
ā āā Slot detection algorithms ā
āāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā GraphAPIService (MS Graph Integration) ā
ā āā OAuth2 authentication ā
ā āā Token management ā
ā āā MS Graph SDK calls ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Features
The service exposes 4 MCP tools:
1. get_events
Query calendar events by date range with optional filters.
Input Schema:
{
"start_date": "2025-10-15", // ISO8601: yyyy-MM-dd
"end_date": "2025-10-31",
"filter": "optional filter string"
}
2. block_dates
Create "Out of Office" events to block time slots.
Input Schema:
{
"start_date": "2025-10-20",
"end_date": "2025-10-22",
"reason": "Vacation"
}
3. find_available_slots
Analyze calendar and detect free time slots for scheduling.
Input Schema:
{
"duration": 60, // minutes
"date_range": {
"start": "2025-10-15",
"end": "2025-10-31"
},
"participants": ["optional", "list", "of", "emails"]
}
4. reschedule_event
Move existing meeting to new time slot.
Input Schema:
{
"event_id": "uuid-of-event",
"new_start_date": "2025-10-16T14:00:00",
"new_end_date": "2025-10-16T15:00:00"
}
Tech Stack
Core
- Java: 21.0.5 (Eclipse Temurin LTS)
- Spring Boot: 3.5.6
- Maven: 3.9.9 with Toolchains
MCP SDK
- mcp-bom: 0.12.1 (Bill of Materials)
- mcp: 0.12.1 (Core protocol & default transports)
- mcp-spring-webmvc: 0.12.1 (Spring SSE/HTTP transport)
- mcp-test: 0.12.1 (Testing utilities)
Microsoft Integration
- microsoft-graph: 6.15.0 (MS Graph Java SDK)
- azure-identity: 1.13.2 (OAuth2 client credentials)
Utilities
- lombok: 1.18.34 (Reduce boilerplate)
- springdoc-openapi: 2.6.0 (Swagger UI)
Prerequisites
- Java 21+
- Maven 3.9+ (wrapper included:
./mvnw
) - Azure AD Application with calendar permissions
- Microsoft 365 Account for testing
Setup
1. Clone & Build
git clone <repository-url>
cd calendar-mcp-service
./mvnw clean install
2. Configure Azure Credentials
Edit .env
:
MS_TENANT_ID=your-azure-tenant-id
MS_CLIENT_ID=your-app-client-id
MS_CLIENT_SECRET=your-client-secret
3. Azure AD Permissions
Your Azure AD app requires these Application-level permissions:
Calendars.ReadWrite
- Read and write calendar eventsUser.Read.All
- Read user profiles (for multi-user availability)
Grant admin consent in Azure Portal.
Run
# Development mode
./mvnw spring-boot:run
# With dev profile (DEBUG logging)
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
# Production JAR
./mvnw clean package
java -jar target/calendar-mcp-service-0.0.1-SNAPSHOT.jar
Service runs on: http://localhost:8080
Health check:
curl http://localhost:8080/actuator/health
How It Works (SDK Integration)
1. McpServer Configuration
The SDK's McpServer
is configured as a Spring bean:
@Configuration
public class McpServerConfig {
@Bean
public McpServer mcpServer(CalendarToolsProvider toolsProvider) {
return McpServer.builder()
.serverInfo(new ServerInfo("calendar-mcp-service", "1.0.0"))
.capabilities(ServerCapabilities.builder()
.tools(ToolsCapability.builder().build())
.build())
.toolsProvider(toolsProvider::getTools)
.build();
}
@Bean
public McpTransport mcpTransport() {
return new SpringWebMvcSseServerTransport();
}
}
2. Tool Registration
Tools are registered via CalendarToolsProvider
:
@Component
@RequiredArgsConstructor
public class CalendarToolsProvider {
private final CalendarService calendarService;
private final ObjectMapper objectMapper;
public List<Tool> getTools() {
return List.of(
buildGetEventsTool(),
buildBlockDatesTool(),
// ... other tools
);
}
private Tool buildGetEventsTool() {
return Tool.builder()
.name("get_events")
.description("Query calendar events by date range")
.inputSchema(GetEventsSchema.create())
.handler(this::handleGetEvents)
.build();
}
private CallToolResult handleGetEvents(Map<String, Object> arguments) {
String startDate = (String) arguments.get("start_date");
String endDate = (String) arguments.get("end_date");
List<CalendarEvent> events = calendarService.getEvents(startDate, endDate);
return CallToolResult.content(
TextContent.of(objectMapper.writeValueAsString(events))
);
}
}
3. JSON Schema Definition
Each tool has a JSON Schema for input validation:
public class GetEventsSchema {
public static JsonNode create() {
return JsonNodeFactory.instance.objectNode()
.put("type", "object")
.set("properties", JsonNodeFactory.instance.objectNode()
.set("start_date", JsonNodeFactory.instance.objectNode()
.put("type", "string")
.put("description", "Start date (ISO8601: yyyy-MM-dd)"))
.set("end_date", JsonNodeFactory.instance.objectNode()
.put("type", "string")
.put("description", "End date (ISO8601: yyyy-MM-dd)"))
)
.set("required", JsonNodeFactory.instance.arrayNode()
.add("start_date")
.add("end_date"));
}
}
4. SDK Automatic Handling
When a client sends:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_events",
"arguments": {
"start_date": "2025-10-15",
"end_date": "2025-10-31"
}
},
"id": 1
}
The SDK:
- Parses the JSON-RPC request
- Finds the
get_events
tool - Calls
handleGetEvents(arguments)
- Wraps the result in JSON-RPC response
- Sends via transport
Testing
# Run all tests
./mvnw test
# Run specific test class
./mvnw test -Dtest=CalendarToolsProviderTest
# Integration tests
./mvnw verify
Test Structure
src/test/java/
āāā mcp/
ā āāā CalendarToolsProviderTest.java # Tool registration tests
āāā service/
ā āāā CalendarServiceTest.java # Business logic tests
ā āāā GraphAPIServiceTest.java # MS Graph integration tests
āāā integration/
āāā McpServerIntegrationTest.java # E2E tests with mcp-test
Manual Testing with cURL
List available tools
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
}'
Call get_events tool
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_events",
"arguments": {
"start_date": "2025-10-15",
"end_date": "2025-10-31"
}
},
"id": 2
}'
Project Structure
calendar-mcp-service/
āāā src/main/java/com/enterprise/calendar/
ā āāā CalendarMCPApplication.java
ā āāā config/
ā ā āāā McpServerConfig.java # MCP SDK configuration
ā ā āāā GraphConfig.java # MS Graph OAuth2 config
ā āāā mcp/
ā ā āāā CalendarToolsProvider.java # Tool registration
ā ā āāā schema/ # JSON schemas for tools
ā āāā service/
ā ā āāā CalendarService.java # Business logic
ā ā āāā GraphAPIService.java # MS Graph integration
ā āāā model/
ā ā āāā calendar/ # DTOs (CalendarEvent, etc.)
ā āāā exception/
ā ā āāā GraphAPIException.java
ā āāā util/
ā āāā DateUtils.java
āāā src/main/resources/
ā āāā application.yml
ā āāā application-dev.yml
āāā pom.xml
āāā .env.example
āāā README.md
Note: No controller/
or model/mcp/
packages - the SDK handles the protocol layer!
API Documentation
Swagger UI: http://localhost:8080/swagger-ui.html
MCP Communication
Protocol: JSON-RPC 2.0 (handled by SDK) Transport: SSE (Server-Sent Events) or Streamable-HTTP Port: 8080
Designed to work with: NestJS MCP orchestrator that routes Claude's tool calls to this service.
Multi-Version Java Setup
This project uses Maven Toolchains for multi-version Java management.
Configuration: See pom.xml
and ~/.m2/toolchains.xml
License
MIT