Added request/response validation
diff --git a/tools/metadata.go b/tools/metadata.go
index 6fd84b1..c3da813 100644
--- a/tools/metadata.go
+++ b/tools/metadata.go
@@ -6,19 +6,22 @@
 	"strings"
 
 	"github.com/korap/korap-mcp/service"
+	"github.com/korap/korap-mcp/validation"
 	"github.com/mark3labs/mcp-go/mcp"
 	"github.com/rs/zerolog/log"
 )
 
 // MetadataTool implements the Tool interface for KorAP corpus metadata retrieval
 type MetadataTool struct {
-	client *service.Client
+	client    *service.Client
+	validator *validation.Validator
 }
 
 // NewMetadataTool creates a new metadata tool instance
 func NewMetadataTool(client *service.Client) *MetadataTool {
 	return &MetadataTool{
-		client: client,
+		client:    client,
+		validator: validation.New(log.Logger),
 	}
 }
 
@@ -67,20 +70,29 @@
 	// Extract optional corpus parameter
 	corpus := request.GetString("corpus", "")
 
+	// Validate the metadata request using the validation package
+	metadataReq := validation.MetadataRequest{
+		Action: action,
+		Corpus: corpus,
+	}
+
+	if err := m.validator.ValidateMetadataRequest(metadataReq); err != nil {
+		log.Warn().
+			Err(err).
+			Interface("request", metadataReq).
+			Msg("Metadata request validation failed")
+		return nil, fmt.Errorf("invalid metadata request: %w", err)
+	}
+
+	// Sanitize inputs
+	if corpus != "" {
+		corpus = m.validator.SanitizeCorpusID(corpus)
+	}
+
 	log.Debug().
 		Str("action", action).
 		Str("corpus", corpus).
-		Msg("Parsed metadata parameters")
-
-	// Validate parameters before authentication
-	switch action {
-	case "list":
-		// No additional validation needed for list
-	case "statistics":
-		// No additional validation needed for statistics - corpus is optional
-	default:
-		return nil, fmt.Errorf("unknown action: %s", action)
-	}
+		Msg("Parsed and validated metadata parameters")
 
 	// Check if client is available and authenticated
 	if m.client == nil {
@@ -119,6 +131,14 @@
 		return nil, fmt.Errorf("failed to retrieve corpus list: %w", err)
 	}
 
+	// Validate the response
+	if err := m.validator.ValidateCorpusListResponse(&corpusListResp); err != nil {
+		log.Warn().
+			Err(err).
+			Msg("Corpus list response validation failed, but continuing with potentially invalid data")
+		// Continue processing despite validation errors to be resilient
+	}
+
 	log.Info().
 		Int("corpus_count", len(corpusListResp.Corpora)).
 		Msg("Corpus list retrieved successfully")
@@ -150,6 +170,14 @@
 		return nil, fmt.Errorf("failed to retrieve corpus statistics: %w", err)
 	}
 
+	// Validate the response
+	if err := m.validator.ValidateStatisticsResponse(&statsResp); err != nil {
+		log.Warn().
+			Err(err).
+			Msg("Statistics response validation failed, but continuing with potentially invalid data")
+		// Continue processing despite validation errors to be resilient
+	}
+
 	log.Info().
 		Str("corpus", corpus).
 		Int("documents", statsResp.Documents).
diff --git a/tools/metadata_test.go b/tools/metadata_test.go
index 88c7e6d..e5d60cd 100644
--- a/tools/metadata_test.go
+++ b/tools/metadata_test.go
@@ -110,8 +110,9 @@
 
 	_, err := tool.Execute(context.Background(), request)
 	assert.Error(t, err)
-	// The unknown action error should come before authentication
-	assert.Contains(t, err.Error(), "unknown action: unknown")
+	// The validation error should come before authentication
+	assert.Contains(t, err.Error(), "invalid metadata request")
+	assert.Contains(t, err.Error(), "invalid action")
 }
 
 func TestMetadataTool_Execute_StatisticsWithoutCorpus(t *testing.T) {
diff --git a/tools/search.go b/tools/search.go
index c96f407..2a78f8e 100644
--- a/tools/search.go
+++ b/tools/search.go
@@ -6,19 +6,22 @@
 	"strings"
 
 	"github.com/korap/korap-mcp/service"
+	"github.com/korap/korap-mcp/validation"
 	"github.com/mark3labs/mcp-go/mcp"
 	"github.com/rs/zerolog/log"
 )
 
 // SearchTool implements the Tool interface for KorAP corpus search
 type SearchTool struct {
-	client *service.Client
+	client    *service.Client
+	validator *validation.Validator
 }
 
 // NewSearchTool creates a new search tool instance
 func NewSearchTool(client *service.Client) *SearchTool {
 	return &SearchTool{
-		client: client,
+		client:    client,
+		validator: validation.New(log.Logger),
 	}
 }
 
@@ -80,12 +83,34 @@
 	corpus := request.GetString("corpus", "")
 	count := request.GetInt("count", 25)
 
+	// Validate the search request using the validation package
+	searchReq := validation.SearchRequest{
+		Query:         query,
+		QueryLanguage: queryLang,
+		Corpus:        corpus,
+		Count:         count,
+	}
+
+	if err := s.validator.ValidateSearchRequest(searchReq); err != nil {
+		log.Warn().
+			Err(err).
+			Interface("request", searchReq).
+			Msg("Search request validation failed")
+		return nil, fmt.Errorf("invalid search request: %w", err)
+	}
+
+	// Sanitize inputs
+	query = s.validator.SanitizeQuery(query)
+	if corpus != "" {
+		corpus = s.validator.SanitizeCorpusID(corpus)
+	}
+
 	log.Debug().
 		Str("query", query).
 		Str("query_language", queryLang).
 		Str("corpus", corpus).
 		Int("count", count).
-		Msg("Parsed search parameters")
+		Msg("Parsed and validated search parameters")
 
 	// Check if client is available and authenticated
 	if s.client == nil {
@@ -100,7 +125,7 @@
 	}
 
 	// Prepare search request
-	searchReq := service.SearchRequest{
+	korapSearchReq := service.SearchRequest{
 		Query:      query,
 		QueryLang:  queryLang,
 		Collection: corpus,
@@ -109,7 +134,7 @@
 
 	// Perform the search
 	var searchResp service.SearchResponse
-	err = s.client.PostJSON(ctx, "search", searchReq, &searchResp)
+	err = s.client.PostJSON(ctx, "search", korapSearchReq, &searchResp)
 	if err != nil {
 		log.Error().
 			Err(err).
@@ -118,6 +143,14 @@
 		return nil, fmt.Errorf("search failed: %w", err)
 	}
 
+	// Validate the response
+	if err := s.validator.ValidateSearchResponse(&searchResp); err != nil {
+		log.Warn().
+			Err(err).
+			Msg("Search response validation failed, but continuing with potentially invalid data")
+		// Continue processing despite validation errors to be resilient
+	}
+
 	log.Info().
 		Str("query", query).
 		Int("total_results", searchResp.Meta.TotalResults).