feat: expose current date and time via HTTP and MCP

Adds GET /datetime and an MCP get_current_datetime tool returning the
current date/time in Europe/Paris, alongside the existing calendar
endpoints. Both share the same CurrentDateTime payload shape.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hu8wwahgecuCGfesTKCfEd
This commit is contained in:
2026-09-05 10:58:38 +02:00
co-authored by Claude Sonnet 5
parent e5468ef654
commit 383c889cab
7 changed files with 101 additions and 7 deletions
+35
View File
@@ -0,0 +1,35 @@
package main
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
)
func TestDateTimeHandler_ServeHTTP(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/datetime", nil)
rec := httptest.NewRecorder()
(&DateTimeHandler{}).ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
var got CurrentDateTime
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
t.Fatalf("unable to decode response: %v", err)
}
now := time.Now().In(location)
if diff := now.Sub(got.DateTime); diff < -time.Second || diff > time.Second {
t.Errorf("DateTime = %v, want close to %v", got.DateTime, now)
}
_, wantOffset := now.Zone()
_, gotOffset := got.DateTime.Zone()
if gotOffset != wantOffset {
t.Errorf("DateTime UTC offset = %d, want %d", gotOffset, wantOffset)
}
}
+21
View File
@@ -88,6 +88,26 @@ func (c *CalendarHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
}
}
type CurrentDateTime struct {
DateTime time.Time `json:"date_time"`
}
type DateTimeHandler struct{}
func (d *DateTimeHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
content, err := json.Marshal(CurrentDateTime{DateTime: time.Now().In(location)})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
zap.S().Errorf("unable to marshall response %v, %v", content, err)
} else {
_, err = w.Write(content)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
zap.S().Errorf("unable to marshall response %v, :%v", content, err)
}
}
}
func main() {
var port int
var host string
@@ -173,6 +193,7 @@ func main() {
)
http.Handle("/status", healthz.Handler())
http.Handle("/mcp", newMCPHandler())
http.Handle("/datetime", &DateTimeHandler{})
signChan := make(chan os.Signal, 1)
go func() {
+9
View File
@@ -38,6 +38,10 @@ func calendarDayFor(day time.Time) CalendarDay {
}
}
func handleCurrentDateTime(_ context.Context, _ *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, CurrentDateTime, error) {
return nil, CurrentDateTime{DateTime: time.Now().In(location)}, nil
}
func handleCalendarToday(_ context.Context, _ *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, CalendarDay, error) {
return nil, calendarDayFor(time.Now().In(location)), nil
}
@@ -64,6 +68,11 @@ func newMCPHandler() http.Handler {
Version: "1.0.0",
}, nil)
mcp.AddTool(server, &mcp.Tool{
Name: "get_current_datetime",
Description: "Get the current date and time",
}, handleCurrentDateTime)
mcp.AddTool(server, &mcp.Tool{
Name: "get_calendar_today",
Description: "Get calendar information for today: working day, French public holiday (ferie), personal holiday (from CalDAV) and weekday",
+13 -2
View File
@@ -26,13 +26,24 @@ func TestMCPEndToEnd(t *testing.T) {
if err != nil {
t.Fatalf("list tools failed: %v", err)
}
if len(tools.Tools) != 3 {
t.Fatalf("got %d tools, want 3", len(tools.Tools))
if len(tools.Tools) != 4 {
t.Fatalf("got %d tools, want 4", len(tools.Tools))
}
for _, tool := range tools.Tools {
t.Logf("tool: %s - %s", tool.Name, tool.Description)
}
now, err := session.CallTool(ctx, &mcp.CallToolParams{
Name: "get_current_datetime",
})
if err != nil {
t.Fatalf("call get_current_datetime failed: %v", err)
}
if now.IsError {
t.Fatalf("get_current_datetime returned an error result: %v", now.Content)
}
t.Logf("current datetime structured content: %+v", now.StructuredContent)
result, err := session.CallTool(ctx, &mcp.CallToolParams{
Name: "get_calendar_for_date",
Arguments: map[string]any{"date": "2020-01-01"},
+12
View File
@@ -66,6 +66,18 @@ func TestCalendarDayFor(t *testing.T) {
}
}
func TestHandleCurrentDateTime(t *testing.T) {
_, dt, err := handleCurrentDateTime(context.Background(), nil, struct{}{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
now := time.Now().In(location)
if diff := now.Sub(dt.DateTime); diff < -time.Second || diff > time.Second {
t.Errorf("DateTime = %v, want close to %v", dt.DateTime, now)
}
}
func TestHandleCalendarToday(t *testing.T) {
withTestCalendar(t)