This is an automated email from the ASF dual-hosted git repository.

epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-mcp.git


The following commit(s) were added to refs/heads/main by this push:
     new e4f223e  feat(collection): add create-collection tool and dedicated 
collection package (#57)
e4f223e is described below

commit e4f223e3552086d57f3b8730198e283e76790d57
Author: Aditya Parikh <[email protected]>
AuthorDate: Mon Mar 9 17:11:07 2026 -0400

    feat(collection): add create-collection tool and dedicated collection 
package (#57)
    
    * feat(collection): add create-collection tool and dedicated package
    
    Move CollectionService, CollectionUtils, and Dtos from the metadata
    package into a new dedicated collection package. This separates
    collection management from schema introspection (SchemaService stays
    in metadata).
    
    Add create-collection MCP tool to CollectionService:
    - Accepts name (required), configSet, numShards, replicationFactor
    - Defaults: configSet=_default, numShards=1, replicationFactor=1
    - Uses CollectionAdminRequest.createCollection() for both SolrCloud
      and standalone Solr via Http2SolrClient
    - Returns CollectionCreationResult DTO with name, success, message,
      and createdAt timestamp
    
    Add CollectionCreationResult record to Dtos.java.
    
    Update unit tests with correct 2-arg Mockito stubs to match
    CollectionAdminRequest.process() call signature.
    Add integration test asserting the new collection appears in
    listCollections() after creation.
    
    ---------
    
    Signed-off-by: adityamparikh <[email protected]>
    Signed-off-by: Aditya Parikh <[email protected]>
    Co-authored-by: Claude Sonnet 4.6 <[email protected]>
---
 README.md                                          |   33 +-
 mydata/devnexus-2026.json                          | 1626 ++++++++++++++++++++
 src/main/java/org/apache/solr/mcp/server/Main.java |   41 +-
 .../CollectionService.java                         |   77 +-
 .../{metadata => collection}/CollectionUtils.java  |    9 +-
 .../mcp/server/{metadata => collection}/Dtos.java  |   26 +-
 .../java/org/apache/solr/mcp/server/MainTest.java  |    2 +-
 .../solr/mcp/server/McpToolRegistrationTest.java   |    2 +-
 .../CollectionServiceIntegrationTest.java          |   18 +-
 .../CollectionServiceTest.java                     |   59 +-
 .../CollectionUtilsTest.java                       |    2 +-
 .../ConferenceEndToEndIntegrationTest.java         |  161 ++
 12 files changed, 1998 insertions(+), 58 deletions(-)

diff --git a/README.md b/README.md
index 9dfc30c..488254e 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ A Spring AI Model Context Protocol (MCP) server that provides 
tools for interact
 
 - 🔍 Search Solr collections with filtering, faceting, and pagination
 - 📝 Index documents in JSON, CSV, and XML
+- 📁 Create collections with configurable shards, replicas, and configsets
 - 📊 Manage collections and view statistics
 - 🔧 Inspect schema
 - 🔌 Transports: STDIO (Claude Desktop) and HTTP (MCP Inspector)
@@ -307,14 +308,34 @@ For complete setup instructions, see 
[docs/AUTH0_SETUP.md](docs/AUTH0_SETUP.md)
 
 ## Available MCP tools
 
+### Search
+
+| Tool | Description |
+|------|-------------|
+| `search` | Full-text search with filtering, faceting, sorting, and 
pagination |
+
+### Indexing
+
+| Tool | Description |
+|------|-------------|
+| `index-json-documents` | Index documents from a JSON string into a Solr 
collection |
+| `index-csv-documents` | Index documents from a CSV string into a Solr 
collection |
+| `index-xml-documents` | Index documents from an XML string into a Solr 
collection |
+
+### Collections
+
+| Tool | Description |
+|------|-------------|
+| `create-collection` | Create a new Solr collection (configSet, numShards, 
replicationFactor optional — default to `_default`, `1`, `1`) |
+| `list-collections` | List all available Solr collections |
+| `get-collection-stats` | Get statistics and metrics for a collection |
+| `check-health` | Check the health status of a collection |
+
+### Schema
+
 | Tool | Description |
 |------|-------------|
-| `search` | Search Solr collections with advanced query options |
-| `index_documents` | Index documents from JSON, CSV, or XML |
-| `listCollections` | List all available Solr collections |
-| `getCollectionStats` | Get statistics and metrics for a collection |
-| `checkHealth` | Check the health status of a collection |
-| `getSchema` | Retrieve schema information for a collection |
+| `get-schema` | Retrieve schema information for a collection |
 
 ## Available MCP Resources
 
diff --git a/mydata/devnexus-2026.json b/mydata/devnexus-2026.json
new file mode 100644
index 0000000..8f7d050
--- /dev/null
+++ b/mydata/devnexus-2026.json
@@ -0,0 +1,1626 @@
+[
+  {
+    "id": "devnexus-2026-001",
+    "conference": "DevNexus 2026",
+    "title": "Event Driven Architecture & Event Streaming Workshop",
+    "speakers": ["Daniel Hinojosa"],
+    "track": "Workshop",
+    "room": "TBD",
+    "day": "Day 0",
+    "date": "2026-03-04",
+    "start_time": "09:00",
+    "start_datetime": "2026-03-04T09:00:00Z",
+    "session_type": "Workshop",
+    "tags": ["event-driven", "event-streaming", "architecture", "workshop"]
+  },
+  {
+    "id": "devnexus-2026-002",
+    "conference": "DevNexus 2026",
+    "title": "Fundamentals of Software Engineering In the Age of AI Workshop",
+    "speakers": ["Nathaniel Schutta", "Dan Vega"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 0",
+    "date": "2026-03-04",
+    "start_time": "09:00",
+    "start_datetime": "2026-03-04T09:00:00Z",
+    "session_type": "Workshop",
+    "tags": ["software-engineering", "ai", "practices", "workshop"]
+  },
+  {
+    "id": "devnexus-2026-003",
+    "conference": "DevNexus 2026",
+    "title": "Hands-On: Building Agents with Spring AI, MCP, Java, and Amazon 
Bedrock",
+    "speakers": ["James Ward", "Josh Long"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 0",
+    "date": "2026-03-04",
+    "start_time": "09:00",
+    "start_datetime": "2026-03-04T09:00:00Z",
+    "session_type": "Workshop",
+    "tags": ["spring-ai", "mcp", "java", "amazon-bedrock", "agents", 
"workshop"]
+  },
+  {
+    "id": "devnexus-2026-004",
+    "conference": "DevNexus 2026",
+    "title": "Agentic, Assistive & Predictive AI Patterns",
+    "speakers": ["Rohit Bhardwaj"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 0",
+    "date": "2026-03-04",
+    "start_time": "13:00",
+    "start_datetime": "2026-03-04T13:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "patterns", "predictive-ai"]
+  },
+  {
+    "id": "devnexus-2026-005",
+    "conference": "DevNexus 2026",
+    "title": "Cruising Along with Java: From Java 9 to 25",
+    "speakers": ["Venkat Subramaniam"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 0",
+    "date": "2026-03-04",
+    "start_time": "13:00",
+    "start_datetime": "2026-03-04T13:00:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "java-25", "language-evolution", "jvm"]
+  },
+  {
+    "id": "devnexus-2026-006",
+    "conference": "DevNexus 2026",
+    "title": "Modernize Your Apps in Days with AI Agents",
+    "speakers": ["Brian Benz", "Ayan Gupta"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 0",
+    "date": "2026-03-04",
+    "start_time": "13:00",
+    "start_datetime": "2026-03-04T13:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "modernization", "generative-ai"]
+  },
+  {
+    "id": "devnexus-2026-007",
+    "conference": "DevNexus 2026",
+    "title": "Networking Happy Hour",
+    "speakers": [],
+    "track": "Social",
+    "room": "TBD",
+    "day": "Day 0",
+    "date": "2026-03-04",
+    "start_time": "18:15",
+    "start_datetime": "2026-03-04T18:15:00Z",
+    "session_type": "Social",
+    "tags": ["networking", "social"]
+  },
+  {
+    "id": "devnexus-2026-008",
+    "conference": "DevNexus 2026",
+    "title": "It's Up To Java Developers to Fix Enterprise AI",
+    "speakers": ["Rod Johnson"],
+    "track": "Keynote",
+    "room": "411/412",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "09:00",
+    "start_datetime": "2026-03-05T09:00:00Z",
+    "session_type": "Keynote",
+    "tags": ["keynote", "java", "ai", "enterprise"]
+  },
+  {
+    "id": "devnexus-2026-009",
+    "conference": "DevNexus 2026",
+    "title": "Design Patterns for Multi-Agent Systems",
+    "speakers": ["Brian Sam-Bodden"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "design-patterns", "multi-agent"]
+  },
+  {
+    "id": "devnexus-2026-010",
+    "conference": "DevNexus 2026",
+    "title": "AI for Busy Java Developers",
+    "speakers": ["Frank Greco"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "java", "practical"]
+  },
+  {
+    "id": "devnexus-2026-011",
+    "conference": "DevNexus 2026",
+    "title": "Unbundling of the Cloud Data Warehouse: Open Source Databases 
and Data Lakes",
+    "speakers": ["Zoe Steinkamp"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["architecture", "data-warehouse", "open-source", "data-lakes", 
"cloud"]
+  },
+  {
+    "id": "devnexus-2026-012",
+    "conference": "DevNexus 2026",
+    "title": "To Java 26 and Beyond!",
+    "speakers": ["Billy Korando"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "java-26", "language-evolution", "jvm"]
+  },
+  {
+    "id": "devnexus-2026-013",
+    "conference": "DevNexus 2026",
+    "title": "What's New in Spring Boot 4.0 & What's Arriving in 4.1",
+    "speakers": ["Phil Webb"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-boot", "spring-boot-4", "frameworks"]
+  },
+  {
+    "id": "devnexus-2026-014",
+    "conference": "DevNexus 2026",
+    "title": "Agents, Tools, and MCP, Oh My! Next-Level AI Concepts for 
Developers",
+    "speakers": ["Jennifer Reif"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "mcp", "agents", "generative-ai", "tools"]
+  },
+  {
+    "id": "devnexus-2026-015",
+    "conference": "DevNexus 2026",
+    "title": "The Mentorship Hub",
+    "speakers": ["Bruno Souza", "Luiz Real"],
+    "track": "Community",
+    "room": "Open-Source Cafe",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "09:00",
+    "start_datetime": "2026-03-05T09:00:00Z",
+    "session_type": "Community",
+    "tags": ["mentorship", "community", "career"]
+  },
+  {
+    "id": "devnexus-2026-016",
+    "conference": "DevNexus 2026",
+    "title": "Refactoring RN",
+    "speakers": ["Aaron McClennen"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["refactoring", "practices", "code-quality"]
+  },
+  {
+    "id": "devnexus-2026-017",
+    "conference": "DevNexus 2026",
+    "title": "Life After Dad Joke Apps - Building \"Enterprise Grade\" AI 
Frameworks for Java",
+    "speakers": ["Kevin Strohmeyer", "Josh Long", "Rod Johnson", "Adib 
Saikali"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "java", "ai", "enterprise", "frameworks"]
+  },
+  {
+    "id": "devnexus-2026-018",
+    "conference": "DevNexus 2026",
+    "title": "Zero Migration Java: Stay Current Without Breaking Your App",
+    "speakers": ["Yee-Kang Chang"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "migration", "security", "compatibility"]
+  },
+  {
+    "id": "devnexus-2026-019",
+    "conference": "DevNexus 2026",
+    "title": "Building Engineers or Teaching Technicians?",
+    "speakers": ["Jonathon Graf"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["leadership", "career", "education", "engineering-culture"]
+  },
+  {
+    "id": "devnexus-2026-020",
+    "conference": "DevNexus 2026",
+    "title": "How I Automated My Life with MCP Servers",
+    "speakers": ["Cedric Clyburn"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-05T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["mcp", "automation", "tools", "productivity"]
+  },
+  {
+    "id": "devnexus-2026-021",
+    "conference": "DevNexus 2026",
+    "title": "Brokk: An AI-Native Code Platform for Java, in Java",
+    "speakers": ["Jonathan Ellis"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "java", "tools", "code-platform"]
+  },
+  {
+    "id": "devnexus-2026-022",
+    "conference": "DevNexus 2026",
+    "title": "The Wrong Reasons to Build an MCP Server",
+    "speakers": ["Daniel Oh"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["mcp", "ai", "practical", "architecture"]
+  },
+  {
+    "id": "devnexus-2026-023",
+    "conference": "DevNexus 2026",
+    "title": "JUnit 6 + Exploring the Testing Ecosystem",
+    "speakers": ["Jeanne Boyarsky"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "testing", "junit", "junit-6"]
+  },
+  {
+    "id": "devnexus-2026-024",
+    "conference": "DevNexus 2026",
+    "title": "Spring Data 4: Data Access Revisited",
+    "speakers": ["Chris Bono"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-data", "frameworks", "data-access"]
+  },
+  {
+    "id": "devnexus-2026-025",
+    "conference": "DevNexus 2026",
+    "title": "10 Tools & Tips to Upgrade Your Java Code with AI",
+    "speakers": ["Vinicius Senger", "Jonathan Vogel"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "java", "tools", "generative-ai", "productivity"]
+  },
+  {
+    "id": "devnexus-2026-026",
+    "conference": "DevNexus 2026",
+    "title": "Lean Software Development",
+    "speakers": ["Leigh Griffin"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["lean", "practices", "software-development", "agile"]
+  },
+  {
+    "id": "devnexus-2026-027",
+    "conference": "DevNexus 2026",
+    "title": "Modern API Versioning and Enterprise-Ready AI Enablement with 
Spring Cloud Gateway",
+    "speakers": ["Spencer Gibb", "Chris Sterling"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-cloud", "api", "api-versioning", "gateway", 
"enterprise"]
+  },
+  {
+    "id": "devnexus-2026-028",
+    "conference": "DevNexus 2026",
+    "title": "Bootiful Spring Security",
+    "speakers": ["Josh Long", "Rob Winch"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-security", "security"]
+  },
+  {
+    "id": "devnexus-2026-029",
+    "conference": "DevNexus 2026",
+    "title": "Modern Architectures for Software Development Leaders",
+    "speakers": ["Venkat Subramaniam"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["architecture", "leadership", "software-development"]
+  },
+  {
+    "id": "devnexus-2026-030",
+    "conference": "DevNexus 2026",
+    "title": "Unlocking Engineering Productivity with IDE-Based Coding Agents",
+    "speakers": ["Josh Kurz"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-05T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "ide", "productivity", "tools"]
+  },
+  {
+    "id": "devnexus-2026-031",
+    "conference": "DevNexus 2026",
+    "title": "Fundamentals of Software Engineering In the Age of AI",
+    "speakers": ["Nathaniel Schutta", "Dan Vega"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "software-engineering", "practices", "tools"]
+  },
+  {
+    "id": "devnexus-2026-032",
+    "conference": "DevNexus 2026",
+    "title": "10 Things I Hate About AI",
+    "speakers": ["Cody Frenzel", "Laurie Lay"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "practical", "critique"]
+  },
+  {
+    "id": "devnexus-2026-033",
+    "conference": "DevNexus 2026",
+    "title": "Java Cloud Optimization: Serverless, Native, and CRaC – Unleash 
Peak Performance",
+    "speakers": ["Rustam Mehmandarov"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "cloud", "serverless", "native", "crac", "performance", 
"architecture"]
+  },
+  {
+    "id": "devnexus-2026-034",
+    "conference": "DevNexus 2026",
+    "title": "Java Performance: Beyond Simple Request Latencies",
+    "speakers": ["John Ceccarelli", "Simon Ritter"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "performance", "jvm", "latency"]
+  },
+  {
+    "id": "devnexus-2026-035",
+    "conference": "DevNexus 2026",
+    "title": "Beyond SWE-Bench: Enterprise Java AI Agents and Real-World 
Development Benchmarks",
+    "speakers": ["Mark Pollack"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "java", "enterprise", "benchmarks", "spring"]
+  },
+  {
+    "id": "devnexus-2026-036",
+    "conference": "DevNexus 2026",
+    "title": "Building AI Agents with Spring & MCP",
+    "speakers": ["James Ward", "Josh Long"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-ai", "mcp", "agents", "generative-ai"]
+  },
+  {
+    "id": "devnexus-2026-037",
+    "conference": "DevNexus 2026",
+    "title": "Git Features You Aren't Using",
+    "speakers": ["Raju Gandhi"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["git", "practices", "tools", "version-control"]
+  },
+  {
+    "id": "devnexus-2026-038",
+    "conference": "DevNexus 2026",
+    "title": "The Modern Spring Workflow: Enterprise-Ready Delivery and 
AI-Boosted Coding with Tanzu",
+    "speakers": ["Chris Sterling", "Cora Iberkleid"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "tanzu", "ai", "enterprise", "cloud-native"]
+  },
+  {
+    "id": "devnexus-2026-039",
+    "conference": "DevNexus 2026",
+    "title": "Building Trustworthy and Reliable LLM Applications",
+    "speakers": ["Alex Soto", "Markus Eisele"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["llm", "ai", "security", "reliability", "trust"]
+  },
+  {
+    "id": "devnexus-2026-040",
+    "conference": "DevNexus 2026",
+    "title": "The Accidental Leader: How to Succeed When You Weren't Planning 
to Lead",
+    "speakers": ["Emily Harden"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-05T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["leadership", "career", "management"]
+  },
+  {
+    "id": "devnexus-2026-041",
+    "conference": "DevNexus 2026",
+    "title": "Hands-on Embabel",
+    "speakers": ["Rod Johnson"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "embabel", "tools", "agents"]
+  },
+  {
+    "id": "devnexus-2026-042",
+    "conference": "DevNexus 2026",
+    "title": "Inside MCP: Live Protocol Messages, Real-Time Flows, and Smarter 
Agents",
+    "speakers": ["David Parry"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["mcp", "ai", "agents", "protocol"]
+  },
+  {
+    "id": "devnexus-2026-043",
+    "conference": "DevNexus 2026",
+    "title": "Modular Monoliths: A Happy Middle",
+    "speakers": ["Raju Gandhi"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["architecture", "modular-monolith", "microservices"]
+  },
+  {
+    "id": "devnexus-2026-044",
+    "conference": "DevNexus 2026",
+    "title": "Beyond Default Settings: Optimizing Java on K8s with AI-Driven 
Performance Tuning",
+    "speakers": ["Stefano Doni"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "kubernetes", "performance", "ai", "jvm"]
+  },
+  {
+    "id": "devnexus-2026-045",
+    "conference": "DevNexus 2026",
+    "title": "Supercharge Your Applications with Java, Graphs, and a Touch of 
AI",
+    "speakers": ["Jennifer Reif", "Erin Schnabel"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "graphs", "ai", "frameworks", "neo4j"]
+  },
+  {
+    "id": "devnexus-2026-046",
+    "conference": "DevNexus 2026",
+    "title": "From Monolith to AI Agent: Modernizing Java Systems with MCP",
+    "speakers": ["Theo Lebrun"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["mcp", "ai", "java", "modernization", "agents", "generative-ai"]
+  },
+  {
+    "id": "devnexus-2026-047",
+    "conference": "DevNexus 2026",
+    "title": "Clear Up Messy Code with Refactoring Maneuvers in IntelliJ IDEA",
+    "speakers": ["Ted M. Young"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["refactoring", "intellij", "practices", "code-quality", "ide"]
+  },
+  {
+    "id": "devnexus-2026-048",
+    "conference": "DevNexus 2026",
+    "title": "Building AI Agents with Spring AI and Tanzu Platform",
+    "speakers": ["Josh Long", "Adib Saikali"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-ai", "agents", "tanzu", "ai"]
+  },
+  {
+    "id": "devnexus-2026-049",
+    "conference": "DevNexus 2026",
+    "title": "The Missing Protocol: How MCP Bridges LLMs and Data Streams",
+    "speakers": ["Viktor Gamov"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["mcp", "llm", "data-streaming", "kafka", "security"]
+  },
+  {
+    "id": "devnexus-2026-050",
+    "conference": "DevNexus 2026",
+    "title": "How to Run a 1 on 1 for Everyone (Not Just Managers!)",
+    "speakers": ["Alex Riviere"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["leadership", "management", "one-on-one", "career"]
+  },
+  {
+    "id": "devnexus-2026-051",
+    "conference": "DevNexus 2026",
+    "title": "The Engineer's Guide to Socialization",
+    "speakers": ["Nerando Johnson"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "14:50",
+    "start_datetime": "2026-03-05T14:50:00Z",
+    "session_type": "Talk",
+    "tags": ["soft-skills", "career", "communication"]
+  },
+  {
+    "id": "devnexus-2026-052",
+    "conference": "DevNexus 2026",
+    "title": "The Evolution of Memory in Humans and AI Agents",
+    "speakers": ["Raphael De Lio"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "memory", "tools"]
+  },
+  {
+    "id": "devnexus-2026-053",
+    "conference": "DevNexus 2026",
+    "title": "When One Agent Isn't Enough: Experiments with Multi-Agent AI",
+    "speakers": ["Kenneth Kousen"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "multi-agent", "agents", "practical"]
+  },
+  {
+    "id": "devnexus-2026-054",
+    "conference": "DevNexus 2026",
+    "title": "From Legacy to Cloud-Native: Effective and Scalable Java 
Modernization with Automation",
+    "speakers": ["Emily Jiang"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "cloud-native", "modernization", "automation", 
"architecture"]
+  },
+  {
+    "id": "devnexus-2026-055",
+    "conference": "DevNexus 2026",
+    "title": "Developer Career Masterplan: 15 Steps to Grow Beyond Senior 
Developer",
+    "speakers": ["Bruno Souza"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["career", "java", "developer", "growth"]
+  },
+  {
+    "id": "devnexus-2026-056",
+    "conference": "DevNexus 2026",
+    "title": "What Every Spring Developer Should Know About Jakarta EE",
+    "speakers": ["Ivar Grimstad"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "jakarta-ee", "frameworks", "java"]
+  },
+  {
+    "id": "devnexus-2026-057",
+    "conference": "DevNexus 2026",
+    "title": "Architecting Microservices for Agentic AI Integration",
+    "speakers": ["Rohit Bhardwaj"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["microservices", "ai", "agents", "architecture", "generative-ai"]
+  },
+  {
+    "id": "devnexus-2026-058",
+    "conference": "DevNexus 2026",
+    "title": "The Ultimate Showdown of Database Migration Tools",
+    "speakers": ["Pasha Finkelshteyn", "Anton Arhipov"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["database", "migration", "liquibase", "flyway", "practices"]
+  },
+  {
+    "id": "devnexus-2026-059",
+    "conference": "DevNexus 2026",
+    "title": "Enabling High-Throughput, Low-Latency Inference for Your AI 
Applications",
+    "speakers": ["Cora Iberkleid"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "inference", "performance", "spring", "llm"]
+  },
+  {
+    "id": "devnexus-2026-060",
+    "conference": "DevNexus 2026",
+    "title": "Privacy in Design (PbD) in DevSecOps",
+    "speakers": ["Anitha Dakamarri"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["security", "privacy", "devsecops", "practices"]
+  },
+  {
+    "id": "devnexus-2026-061",
+    "conference": "DevNexus 2026",
+    "title": "Thriving in an Evolving Software Industry",
+    "speakers": ["Nathaniel Schutta", "Glenn Renfro"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["career", "leadership", "software-industry"]
+  },
+  {
+    "id": "devnexus-2026-062",
+    "conference": "DevNexus 2026",
+    "title": "Developer Experience != Developer Productivity",
+    "speakers": ["Jeremy Meiss"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "15:50",
+    "start_datetime": "2026-03-05T15:50:00Z",
+    "session_type": "Talk",
+    "tags": ["developer-experience", "productivity", "tools"]
+  },
+  {
+    "id": "devnexus-2026-063",
+    "conference": "DevNexus 2026",
+    "title": "The OffHeap Podcast. Devnexus Edition (Now with AI Agents)",
+    "speakers": ["Freddy Guime"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "16:50",
+    "start_datetime": "2026-03-05T16:50:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "podcast", "ai", "agents", "community"]
+  },
+  {
+    "id": "devnexus-2026-064",
+    "conference": "DevNexus 2026",
+    "title": "Conference Reception",
+    "speakers": [],
+    "track": "Social",
+    "room": "TBD",
+    "day": "Day 1",
+    "date": "2026-03-05",
+    "start_time": "17:30",
+    "start_datetime": "2026-03-05T17:30:00Z",
+    "session_type": "Social",
+    "tags": ["networking", "social"]
+  },
+  {
+    "id": "devnexus-2026-065",
+    "conference": "DevNexus 2026",
+    "title": "Hacking AI - How to Survive the AI Uprising",
+    "speakers": ["Gant Laborde"],
+    "track": "Keynote",
+    "room": "411/412",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "09:00",
+    "start_datetime": "2026-03-06T09:00:00Z",
+    "session_type": "Keynote",
+    "tags": ["keynote", "ai", "security", "hacking"]
+  },
+  {
+    "id": "devnexus-2026-066",
+    "conference": "DevNexus 2026",
+    "title": "Connecting the Dots with Context Graphs",
+    "speakers": ["Stephen Chin"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "graphs", "context", "rag", "tools"]
+  },
+  {
+    "id": "devnexus-2026-067",
+    "conference": "DevNexus 2026",
+    "title": "Spec Driven Development: Why Your Prompt Chaos Won't Scale",
+    "speakers": ["Simon Maple"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "llm", "prompting", "practical", "development"]
+  },
+  {
+    "id": "devnexus-2026-068",
+    "conference": "DevNexus 2026",
+    "title": "Introduction to Cell Architectures",
+    "speakers": ["Christopher Curtin"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["architecture", "cell-architecture", "distributed-systems"]
+  },
+  {
+    "id": "devnexus-2026-069",
+    "conference": "DevNexus 2026",
+    "title": "Scotty I Need Warp Speed - Ways to Improve JVM Startup",
+    "speakers": ["Gerrit Grunwald"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "jvm", "startup", "performance", "graalvm"]
+  },
+  {
+    "id": "devnexus-2026-070",
+    "conference": "DevNexus 2026",
+    "title": "API Versioning in Spring",
+    "speakers": ["Spencer Gibb"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "api", "api-versioning", "frameworks"]
+  },
+  {
+    "id": "devnexus-2026-071",
+    "conference": "DevNexus 2026",
+    "title": "OK, But What About Predictive AI?",
+    "speakers": ["Brayan Muñoz V.", "José R. Almonte C."],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "predictive-ai", "machine-learning", "generative-ai"]
+  },
+  {
+    "id": "devnexus-2026-072",
+    "conference": "DevNexus 2026",
+    "title": "Maven's Hidden Secrets to Speed Up Your Build",
+    "speakers": ["Ko Turk"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["maven", "build", "practices", "performance"]
+  },
+  {
+    "id": "devnexus-2026-073",
+    "conference": "DevNexus 2026",
+    "title": "Spring Cloud Supercharged for Production-Ready Apps",
+    "speakers": ["Ryan Baxter", "Chris Sterling"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-cloud", "production", "cloud-native"]
+  },
+  {
+    "id": "devnexus-2026-074",
+    "conference": "DevNexus 2026",
+    "title": "The Hidden Security Hazards in Your Java Stack",
+    "speakers": ["Brian Vermeer"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "security", "vulnerabilities", "devsecops"]
+  },
+  {
+    "id": "devnexus-2026-075",
+    "conference": "DevNexus 2026",
+    "title": "Back to the Future of Software: How to Survive the AI Apocalypse 
with Tests, Prompts, and Specs",
+    "speakers": ["Baruch Sadogursky", "Leonid Igolnik"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "testing", "leadership", "prompting", 
"software-engineering"]
+  },
+  {
+    "id": "devnexus-2026-076",
+    "conference": "DevNexus 2026",
+    "title": "BoxLang vs the World: From Zero to Stable in 20 Months",
+    "speakers": ["Luis Majano", "Brad Wood"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "10:00",
+    "start_datetime": "2026-03-06T10:00:00Z",
+    "session_type": "Talk",
+    "tags": ["boxlang", "jvm-languages", "tools"]
+  },
+  {
+    "id": "devnexus-2026-077",
+    "conference": "DevNexus 2026",
+    "title": "Performant GraphRAG: Improving Neo4j to Drive Autonomous AI",
+    "speakers": ["Brandon Tylke", "Jon Gentsch"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "rag", "neo4j", "graphs", "tools", "llm"]
+  },
+  {
+    "id": "devnexus-2026-078",
+    "conference": "DevNexus 2026",
+    "title": "From Microservices to Agent-Services: Architectural Patterns for 
Autonomous System Boundaries",
+    "speakers": ["Mo Haghighi", "Prasanth Kumar Pari"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "microservices", "architecture", "practical"]
+  },
+  {
+    "id": "devnexus-2026-079",
+    "conference": "DevNexus 2026",
+    "title": "Breaking the Monolith Mindset: Hexagonal Architecture vs 
Traditional Layers in Java",
+    "speakers": ["Emmanuel Guzmán", "Jorge Cajas"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["architecture", "hexagonal", "java", "monolith", 
"layered-architecture"]
+  },
+  {
+    "id": "devnexus-2026-080",
+    "conference": "DevNexus 2026",
+    "title": "Trash Talk - Exploring the Memory Management in the JVM",
+    "speakers": ["Gerrit Grunwald"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "jvm", "memory-management", "garbage-collection", 
"performance"]
+  },
+  {
+    "id": "devnexus-2026-081",
+    "conference": "DevNexus 2026",
+    "title": "Autoscaling Spring Boot Apps in Kubernetes with KEDA",
+    "speakers": ["John Coyne"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-boot", "kubernetes", "keda", "autoscaling", 
"cloud-native"]
+  },
+  {
+    "id": "devnexus-2026-082",
+    "conference": "DevNexus 2026",
+    "title": "Integrating LLMs in Java: A Practical Guide to Model Context 
Protocol",
+    "speakers": ["Dan Vega"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["llm", "java", "mcp", "spring-ai", "generative-ai"]
+  },
+  {
+    "id": "devnexus-2026-083",
+    "conference": "DevNexus 2026",
+    "title": "Sociotechnical Platform Engineering",
+    "speakers": ["Chris Corriere"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["platform-engineering", "practices", "devops", "culture"]
+  },
+  {
+    "id": "devnexus-2026-084",
+    "conference": "DevNexus 2026",
+    "title": "Refactoring the ROI of Software: Continuous Modernization with 
Tanzu Platform",
+    "speakers": ["DaShaun Carter"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "tanzu", "modernization", "refactoring", "cloud"]
+  },
+  {
+    "id": "devnexus-2026-085",
+    "conference": "DevNexus 2026",
+    "title": "Implementing MCP Authorization Using Spring Security OAuth 2.1 
Capabilities",
+    "speakers": ["Joe Grandja"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["mcp", "spring-security", "oauth2", "security", "authorization"]
+  },
+  {
+    "id": "devnexus-2026-086",
+    "conference": "DevNexus 2026",
+    "title": "Delivering Value Through Software: A Practical Guide for Tech 
Leads",
+    "speakers": ["Sujith Paul"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["leadership", "career", "tech-lead", "management"]
+  },
+  {
+    "id": "devnexus-2026-087",
+    "conference": "DevNexus 2026",
+    "title": "A Data-Oriented Programming Approach to REST APIs",
+    "speakers": ["Kenneth Kousen"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "11:20",
+    "start_datetime": "2026-03-06T11:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "rest", "api", "data-oriented-programming", "tools"]
+  },
+  {
+    "id": "devnexus-2026-088",
+    "conference": "DevNexus 2026",
+    "title": "Agentic AI for Java Microservices: Cloud Performance 
Optimization at FinTech Scale",
+    "speakers": ["Sibasis Padhi"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "java", "microservices", "fintech", "cloud", 
"performance"]
+  },
+  {
+    "id": "devnexus-2026-089",
+    "conference": "DevNexus 2026",
+    "title": "Conversational AI Semantic Search for E-commerce Using 
Elasticsearch + RAG",
+    "speakers": ["Karthik Govardhanan"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "rag", "semantic-search", "elasticsearch", "e-commerce"]
+  },
+  {
+    "id": "devnexus-2026-090",
+    "conference": "DevNexus 2026",
+    "title": "Durable Execution: Building Apps That Refuse to Die",
+    "speakers": ["Sam Dengler"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["architecture", "resilience", "durable-execution", "reliability"]
+  },
+  {
+    "id": "devnexus-2026-091",
+    "conference": "DevNexus 2026",
+    "title": "Just-in-Time Compilation Isn't Magic",
+    "speakers": ["Douglas Hawkins"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "jvm", "jit", "performance", "compilation"]
+  },
+  {
+    "id": "devnexus-2026-092",
+    "conference": "DevNexus 2026",
+    "title": "I Can See Clearly Now: Observability of JVM & Spring Boot 2-3-4 
Apps",
+    "speakers": ["Jonatan Ivanov"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "spring-boot", "observability", "monitoring", "jvm", 
"opentelemetry"]
+  },
+  {
+    "id": "devnexus-2026-093",
+    "conference": "DevNexus 2026",
+    "title": "From Context Windows to Context Graphs: The Next Generation of 
AI Systems",
+    "speakers": ["Medha Chakraborty", "Srijani Dey"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "graphs", "llm", "generative-ai", "context"]
+  },
+  {
+    "id": "devnexus-2026-094",
+    "conference": "DevNexus 2026",
+    "title": "Better Assertions with AssertJ",
+    "speakers": ["Tim te Beek"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["testing", "assertj", "java", "practices"]
+  },
+  {
+    "id": "devnexus-2026-095",
+    "conference": "DevNexus 2026",
+    "title": "The Golden Path Starts at Home: Engineering Developer Experience 
from Laptop to Production",
+    "speakers": ["Tim Sparg", "DaShaun Carter"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "developer-experience", "production", 
"platform-engineering"]
+  },
+  {
+    "id": "devnexus-2026-096",
+    "conference": "DevNexus 2026",
+    "title": "The Responsible Java Developer: Trustworthy GenAI in Practice",
+    "speakers": ["Brian Benz"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "ai", "generative-ai", "security", "responsible-ai"]
+  },
+  {
+    "id": "devnexus-2026-097",
+    "conference": "DevNexus 2026",
+    "title": "Beyond Code: Behavioral Architecture (Small Changes, Big Wins)",
+    "speakers": ["Sandeep Adinarayana"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["leadership", "architecture", "culture", "organizational-change"]
+  },
+  {
+    "id": "devnexus-2026-098",
+    "conference": "DevNexus 2026",
+    "title": "Advancing with Java",
+    "speakers": ["Rodrigo Graciano", "Chandra Guntur"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "13:20",
+    "start_datetime": "2026-03-06T13:20:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "career", "tools"]
+  },
+  {
+    "id": "devnexus-2026-099",
+    "conference": "DevNexus 2026",
+    "title": "Stop Fighting Your AI: Engineering Prompts That Actually Work",
+    "speakers": ["Martin Rojas"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "prompting", "prompt-engineering", "tools", "llm"]
+  },
+  {
+    "id": "devnexus-2026-100",
+    "conference": "DevNexus 2026",
+    "title": "Real-Time Fraud Detection in Java with Kafka, Streams & Vector 
Similarity",
+    "speakers": ["Tim Kelly", "Ricardo Mello"],
+    "track": "AI in Practice",
+    "room": "311",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "kafka", "streaming", "fraud-detection", "vector-search", 
"ai", "practical"]
+  },
+  {
+    "id": "devnexus-2026-101",
+    "conference": "DevNexus 2026",
+    "title": "Isolation Isn't All Bad, For Your Database",
+    "speakers": ["Sean McNealy"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["database", "isolation", "architecture", "transactions"]
+  },
+  {
+    "id": "devnexus-2026-102",
+    "conference": "DevNexus 2026",
+    "title": "Java's Asynchronous Ecosystem",
+    "speakers": ["Daniel Hinojosa"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "async", "reactive", "virtual-threads", "jvm"]
+  },
+  {
+    "id": "devnexus-2026-103",
+    "conference": "DevNexus 2026",
+    "title": "Extend Your JPA Applications with Relational JSON Documents",
+    "speakers": ["Anders Swanson"],
+    "track": "Frameworks",
+    "room": "313",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "jpa", "json", "database", "spring", "frameworks"]
+  },
+  {
+    "id": "devnexus-2026-104",
+    "conference": "DevNexus 2026",
+    "title": "Choose Your Fighter: Spring AI vs LangChain4j",
+    "speakers": ["Malavika Balamurali"],
+    "track": "Gen AI",
+    "room": "316",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["spring-ai", "langchain4j", "java", "generative-ai", "llm"]
+  },
+  {
+    "id": "devnexus-2026-105",
+    "conference": "DevNexus 2026",
+    "title": "Grow Beyond Senior Through Java Contributions: JUGs, the JCP and 
OpenJDK",
+    "speakers": ["Bruno Souza", "Heather VanCura"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "open-source", "community", "jcp", "openjdk", "career"]
+  },
+  {
+    "id": "devnexus-2026-106",
+    "conference": "DevNexus 2026",
+    "title": "Staying Current: A Journey in Software Maintenance",
+    "speakers": ["Shriyu Gaglani", "Ho Jong Yu"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "maintenance", "upgrades", "production"]
+  },
+  {
+    "id": "devnexus-2026-107",
+    "conference": "DevNexus 2026",
+    "title": "Deep Dive Into Data Streaming Security",
+    "speakers": ["Olena Kutsenko"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["security", "kafka", "data-streaming", "encryption"]
+  },
+  {
+    "id": "devnexus-2026-108",
+    "conference": "DevNexus 2026",
+    "title": "Engineering the Shift: How Technical Leaders Drive Enduring 
Change",
+    "speakers": ["Niranjan Prithviraj"],
+    "track": "Tech Leadership",
+    "room": "303",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["leadership", "management", "organizational-change", "tech-lead"]
+  },
+  {
+    "id": "devnexus-2026-109",
+    "conference": "DevNexus 2026",
+    "title": "How I AI: Building Custom GPTs to Supercharge Everyday Work",
+    "speakers": ["Daneez Zamangil"],
+    "track": "Tools and Techniques",
+    "room": "305",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "14:40",
+    "start_datetime": "2026-03-06T14:40:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "gpt", "productivity", "tools", "automation"]
+  },
+  {
+    "id": "devnexus-2026-110",
+    "conference": "DevNexus 2026",
+    "title": "AI Agents for Java Devs: From Demo to Deployment",
+    "speakers": ["Brian Benz"],
+    "track": "AI Tools",
+    "room": "315",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "15:40",
+    "start_datetime": "2026-03-06T15:40:00Z",
+    "session_type": "Talk",
+    "tags": ["ai", "agents", "java", "tools", "deployment"]
+  },
+  {
+    "id": "devnexus-2026-111",
+    "conference": "DevNexus 2026",
+    "title": "Microservices for Pragmatists",
+    "speakers": ["Hazel Bohon"],
+    "track": "Architecture",
+    "room": "314",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "15:40",
+    "start_datetime": "2026-03-06T15:40:00Z",
+    "session_type": "Talk",
+    "tags": ["microservices", "architecture", "pragmatic"]
+  },
+  {
+    "id": "devnexus-2026-112",
+    "conference": "DevNexus 2026",
+    "title": "Zero to C-Speed with Only Java",
+    "speakers": ["David Vlijmincx"],
+    "track": "Core Java",
+    "room": "301",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "15:40",
+    "start_datetime": "2026-03-06T15:40:00Z",
+    "session_type": "Talk",
+    "tags": ["java", "performance", "jvm", "native", "panama"]
+  },
+  {
+    "id": "devnexus-2026-113",
+    "conference": "DevNexus 2026",
+    "title": "Debugging with IntelliJ IDEA",
+    "speakers": ["Anton Arhipov"],
+    "track": "Practices",
+    "room": "302",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "15:40",
+    "start_datetime": "2026-03-06T15:40:00Z",
+    "session_type": "Talk",
+    "tags": ["intellij", "debugging", "ide", "practices", "java"]
+  },
+  {
+    "id": "devnexus-2026-114",
+    "conference": "DevNexus 2026",
+    "title": "Stop Getting Shift Left'ed On",
+    "speakers": ["DaShaun Carter", "Kevin Strohmeyer"],
+    "track": "Production Ready Spring",
+    "room": "312",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "15:40",
+    "start_datetime": "2026-03-06T15:40:00Z",
+    "session_type": "Talk",
+    "tags": ["spring", "security", "shift-left", "devops", "production"]
+  },
+  {
+    "id": "devnexus-2026-115",
+    "conference": "DevNexus 2026",
+    "title": "Code Your Way to Quantum-Safe Development by Solving Tomorrow's 
Encryption Crisis",
+    "speakers": ["Barry Burd"],
+    "track": "Security",
+    "room": "304",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "15:40",
+    "start_datetime": "2026-03-06T15:40:00Z",
+    "session_type": "Talk",
+    "tags": ["security", "quantum", "encryption", "post-quantum", 
"cryptography"]
+  },
+  {
+    "id": "devnexus-2026-116",
+    "conference": "DevNexus 2026",
+    "title": "Prize Giveaways and Conference Close!",
+    "speakers": [],
+    "track": "Social",
+    "room": "411/412",
+    "day": "Day 2",
+    "date": "2026-03-06",
+    "start_time": "16:40",
+    "start_datetime": "2026-03-06T16:40:00Z",
+    "session_type": "Closing",
+    "tags": ["closing", "social"]
+  }
+]
diff --git a/src/main/java/org/apache/solr/mcp/server/Main.java 
b/src/main/java/org/apache/solr/mcp/server/Main.java
index 943d3e7..f2970f5 100644
--- a/src/main/java/org/apache/solr/mcp/server/Main.java
+++ b/src/main/java/org/apache/solr/mcp/server/Main.java
@@ -16,8 +16,8 @@
  */
 package org.apache.solr.mcp.server;
 
+import org.apache.solr.mcp.server.collection.CollectionService;
 import org.apache.solr.mcp.server.indexing.IndexingService;
-import org.apache.solr.mcp.server.metadata.CollectionService;
 import org.apache.solr.mcp.server.metadata.SchemaService;
 import org.apache.solr.mcp.server.search.SearchService;
 import org.springframework.boot.SpringApplication;
@@ -107,44 +107,7 @@ import 
org.springframework.boot.autoconfigure.SpringBootApplication;
  */
 @SpringBootApplication
 public class Main {
-
-       /**
-        * Main application entry point that starts the Spring Boot application.
-        *
-        * <p>
-        * This method initializes the Spring application context, configures 
all
-        * service beans, establishes Solr connectivity, and begins listening 
for MCP
-        * client connections via standard input/output.
-        *
-        * <p>
-        * <strong>Startup Process:</strong>
-        *
-        * <ol>
-        * <li>Initialize Spring Boot application context
-        * <li>Load configuration properties from various sources
-        * <li>Create and configure SolrClient bean
-        * <li>Initialize all service beans with dependency injection
-        * <li>Register MCP tools from service methods
-        * <li>Start MCP server listening on stdio
-        * </ol>
-        *
-        * <p>
-        * <strong>Error Handling:</strong>
-        *
-        * <p>
-        * Startup failures typically indicate configuration issues such as:
-        *
-        * <ul>
-        * <li>Missing or invalid Solr URL configuration
-        * <li>Network connectivity issues to Solr server
-        * <li>Missing required dependencies or classpath issues
-        * </ul>
-        *
-        * @param args
-        *            command-line arguments passed to the application
-        * @see SpringApplication#run(Class, String...)
-        */
-       public static void main(String[] args) {
+       static void main(String[] args) {
                SpringApplication.run(Main.class, args);
        }
 }
diff --git 
a/src/main/java/org/apache/solr/mcp/server/metadata/CollectionService.java 
b/src/main/java/org/apache/solr/mcp/server/collection/CollectionService.java
similarity index 91%
rename from 
src/main/java/org/apache/solr/mcp/server/metadata/CollectionService.java
rename to 
src/main/java/org/apache/solr/mcp/server/collection/CollectionService.java
index e7912e7..c121914 100644
--- a/src/main/java/org/apache/solr/mcp/server/metadata/CollectionService.java
+++ b/src/main/java/org/apache/solr/mcp/server/collection/CollectionService.java
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.solr.mcp.server.metadata;
+package org.apache.solr.mcp.server.collection;
 
-import static org.apache.solr.mcp.server.metadata.CollectionUtils.getFloat;
-import static org.apache.solr.mcp.server.metadata.CollectionUtils.getInteger;
-import static org.apache.solr.mcp.server.metadata.CollectionUtils.getLong;
+import static org.apache.solr.mcp.server.collection.CollectionUtils.getFloat;
+import static org.apache.solr.mcp.server.collection.CollectionUtils.getInteger;
+import static org.apache.solr.mcp.server.collection.CollectionUtils.getLong;
 import static org.apache.solr.mcp.server.util.JsonUtils.toJson;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -49,6 +49,7 @@ import org.springaicommunity.mcp.annotation.McpComplete;
 import org.springaicommunity.mcp.annotation.McpResource;
 import org.springaicommunity.mcp.annotation.McpTool;
 import org.springaicommunity.mcp.annotation.McpToolParam;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Service;
 
 /**
@@ -251,6 +252,18 @@ public class CollectionService {
        /** Error message prefix for collection not found exceptions */
        private static final String COLLECTION_NOT_FOUND_ERROR = "Collection 
not found: ";
 
+       /** Default configset name used when none is specified */
+       private static final String DEFAULT_CONFIGSET = "_default";
+
+       /** Default number of shards for new collections */
+       private static final int DEFAULT_NUM_SHARDS = 1;
+
+       /** Default replication factor for new collections */
+       private static final int DEFAULT_REPLICATION_FACTOR = 1;
+
+       /** Error message for blank collection name validation */
+       private static final String BLANK_COLLECTION_NAME_ERROR = "Collection 
name must not be blank";
+
        /** SolrJ client for communicating with Solr server */
        private final SolrClient solrClient;
 
@@ -1040,4 +1053,60 @@ public class CollectionService {
                        return new SolrHealthStatus(false, e.getMessage(), 
null, null, new Date(), null, null, null);
                }
        }
+
+       /**
+        * Creates a new Solr collection (SolrCloud) or core (standalone Solr).
+        *
+        * <p>
+        * Automatically detects the deployment type and uses the appropriate 
API:
+        *
+        * <p>
+        * Uses the Collections API, which works with any SolrClient pointing 
to a
+        * SolrCloud deployment.
+        *
+        * <p>
+        * Optional parameters default to sensible values when not provided by 
the MCP
+        * client: configSet defaults to {@value #DEFAULT_CONFIGSET}, numShards 
and
+        * replicationFactor both default to 1.
+        *
+        * @param name
+        *            the name of the collection to create (must not be blank)
+        * @param configSet
+        *            the configset name (optional, defaults to
+        *            {@value #DEFAULT_CONFIGSET})
+        * @param numShards
+        *            number of shards (optional, defaults to 1)
+        * @param replicationFactor
+        *            replication factor (optional, defaults to 1)
+        * @return result describing the outcome of the creation operation
+        * @throws IllegalArgumentException
+        *             if the collection name is blank
+        * @throws SolrServerException
+        *             if Solr returns an error
+        * @throws IOException
+        *             if there are I/O errors during communication
+        */
+       @PreAuthorize("isAuthenticated()")
+       @McpTool(name = "create-collection", description = "Create a new Solr 
collection. "
+                       + "configSet defaults to _default, numShards and 
replicationFactor default to 1.")
+       public CollectionCreationResult createCollection(
+                       @McpToolParam(description = "Name of the collection to 
create") String name,
+                       @McpToolParam(description = "Configset name. Defaults 
to _default.", required = false) String configSet,
+                       @McpToolParam(description = "Number of shards 
(SolrCloud only). Defaults to 1.", required = false) Integer numShards,
+                       @McpToolParam(description = "Replication factor 
(SolrCloud only). Defaults to 1.", required = false) Integer replicationFactor)
+                       throws SolrServerException, IOException {
+
+               if (name == null || name.isBlank()) {
+                       throw new 
IllegalArgumentException(BLANK_COLLECTION_NAME_ERROR);
+               }
+
+               String effectiveConfigSet = configSet != null ? configSet : 
DEFAULT_CONFIGSET;
+               int effectiveShards = numShards != null ? numShards : 
DEFAULT_NUM_SHARDS;
+               int effectiveRf = replicationFactor != null ? replicationFactor 
: DEFAULT_REPLICATION_FACTOR;
+
+               CollectionAdminRequest.createCollection(name, 
effectiveConfigSet, effectiveShards, effectiveRf)
+                               .process(solrClient);
+
+               return new CollectionCreationResult(name, true, "Collection 
created successfully", new Date());
+       }
 }
diff --git 
a/src/main/java/org/apache/solr/mcp/server/metadata/CollectionUtils.java 
b/src/main/java/org/apache/solr/mcp/server/collection/CollectionUtils.java
similarity index 98%
rename from 
src/main/java/org/apache/solr/mcp/server/metadata/CollectionUtils.java
rename to 
src/main/java/org/apache/solr/mcp/server/collection/CollectionUtils.java
index bd6e20a..d79ea24 100644
--- a/src/main/java/org/apache/solr/mcp/server/metadata/CollectionUtils.java
+++ b/src/main/java/org/apache/solr/mcp/server/collection/CollectionUtils.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.solr.mcp.server.metadata;
+package org.apache.solr.mcp.server.collection;
 
 import org.apache.solr.common.util.NamedList;
 
@@ -65,6 +65,9 @@ import org.apache.solr.common.util.NamedList;
  */
 public class CollectionUtils {
 
+       private CollectionUtils() {
+       }
+
        /**
         * Extracts a Long value from a NamedList using the specified key with 
robust
         * type conversion.
@@ -122,7 +125,7 @@ public class CollectionUtils {
 
                try {
                        return Long.parseLong(value.toString());
-               } catch (NumberFormatException e) {
+               } catch (NumberFormatException _) {
                        return null;
                }
        }
@@ -258,7 +261,7 @@ public class CollectionUtils {
 
                try {
                        return Integer.parseInt(value.toString());
-               } catch (NumberFormatException e) {
+               } catch (NumberFormatException _) {
                        return null;
                }
        }
diff --git a/src/main/java/org/apache/solr/mcp/server/metadata/Dtos.java 
b/src/main/java/org/apache/solr/mcp/server/collection/Dtos.java
similarity index 94%
rename from src/main/java/org/apache/solr/mcp/server/metadata/Dtos.java
rename to src/main/java/org/apache/solr/mcp/server/collection/Dtos.java
index 7a04ac3..d5569b6 100644
--- a/src/main/java/org/apache/solr/mcp/server/metadata/Dtos.java
+++ b/src/main/java/org/apache/solr/mcp/server/collection/Dtos.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.solr.mcp.server.metadata;
+package org.apache.solr.mcp.server.collection;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -477,3 +477,27 @@ record SolrHealthStatus(
                /** Additional status information or state description */
                String status) {
 }
+
+/**
+ * Result of a collection creation operation.
+ *
+ * <p>
+ * Returned by the {@code create-collection} MCP tool to communicate the 
outcome
+ * of a collection creation request. On success, {@code success} is {@code 
true}
+ * and {@code createdAt} records when the operation completed.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+record CollectionCreationResult(
+               /** Name of the collection that was created */
+               String name,
+
+               /** Whether the collection was successfully created */
+               boolean success,
+
+               /** Optional message describing the outcome */
+               String message,
+
+               /** Timestamp when the collection was created, formatted as ISO 
8601 */
+               @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = 
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") Date createdAt) {
+}
diff --git a/src/test/java/org/apache/solr/mcp/server/MainTest.java 
b/src/test/java/org/apache/solr/mcp/server/MainTest.java
index db6fdb7..1b9ae42 100644
--- a/src/test/java/org/apache/solr/mcp/server/MainTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/MainTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.solr.mcp.server;
 
+import org.apache.solr.mcp.server.collection.CollectionService;
 import org.apache.solr.mcp.server.indexing.IndexingService;
-import org.apache.solr.mcp.server.metadata.CollectionService;
 import org.apache.solr.mcp.server.metadata.SchemaService;
 import org.apache.solr.mcp.server.search.SearchService;
 import org.junit.jupiter.api.Test;
diff --git 
a/src/test/java/org/apache/solr/mcp/server/McpToolRegistrationTest.java 
b/src/test/java/org/apache/solr/mcp/server/McpToolRegistrationTest.java
index c0861c9..af79754 100644
--- a/src/test/java/org/apache/solr/mcp/server/McpToolRegistrationTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/McpToolRegistrationTest.java
@@ -22,8 +22,8 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Parameter;
 import java.util.Arrays;
 import java.util.List;
+import org.apache.solr.mcp.server.collection.CollectionService;
 import org.apache.solr.mcp.server.indexing.IndexingService;
-import org.apache.solr.mcp.server.metadata.CollectionService;
 import org.apache.solr.mcp.server.metadata.SchemaService;
 import org.apache.solr.mcp.server.search.SearchService;
 import org.junit.jupiter.api.Test;
diff --git 
a/src/test/java/org/apache/solr/mcp/server/metadata/CollectionServiceIntegrationTest.java
 
b/src/test/java/org/apache/solr/mcp/server/collection/CollectionServiceIntegrationTest.java
similarity index 92%
rename from 
src/test/java/org/apache/solr/mcp/server/metadata/CollectionServiceIntegrationTest.java
rename to 
src/test/java/org/apache/solr/mcp/server/collection/CollectionServiceIntegrationTest.java
index 0fa9684..c520bd0 100644
--- 
a/src/test/java/org/apache/solr/mcp/server/metadata/CollectionServiceIntegrationTest.java
+++ 
b/src/test/java/org/apache/solr/mcp/server/collection/CollectionServiceIntegrationTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.solr.mcp.server.metadata;
+package org.apache.solr.mcp.server.collection;
 
 import static org.junit.jupiter.api.Assertions.*;
 
@@ -243,4 +243,20 @@ class CollectionServiceIntegrationTest {
 
                assertEquals("", collectionService.extractCollectionName(""), 
"Empty string should return empty string");
        }
+
+       @Test
+       void createCollection_createsAndListable() throws Exception {
+               String name = "mcp_test_create_" + System.currentTimeMillis();
+
+               CollectionCreationResult result = 
collectionService.createCollection(name, null, null, null);
+
+               assertTrue(result.success(), "Collection creation should 
succeed");
+               assertEquals(name, result.name(), "Result should contain the 
collection name");
+               assertNotNull(result.createdAt(), "Creation timestamp should be 
set");
+
+               List<String> collections = collectionService.listCollections();
+               boolean collectionExists = collections.contains(name)
+                               || collections.stream().anyMatch(col -> 
col.startsWith(name + "_shard"));
+               assertTrue(collectionExists, "Newly created collection should 
appear in list (found: " + collections + ")");
+       }
 }
diff --git 
a/src/test/java/org/apache/solr/mcp/server/metadata/CollectionServiceTest.java 
b/src/test/java/org/apache/solr/mcp/server/collection/CollectionServiceTest.java
similarity index 93%
rename from 
src/test/java/org/apache/solr/mcp/server/metadata/CollectionServiceTest.java
rename to 
src/test/java/org/apache/solr/mcp/server/collection/CollectionServiceTest.java
index 19888ae..ed5bca8 100644
--- 
a/src/test/java/org/apache/solr/mcp/server/metadata/CollectionServiceTest.java
+++ 
b/src/test/java/org/apache/solr/mcp/server/collection/CollectionServiceTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.solr.mcp.server.metadata;
+package org.apache.solr.mcp.server.collection;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.any;
@@ -894,4 +894,61 @@ class CollectionServiceTest {
 
                return mbeans;
        }
+
+       // createCollection tests
+       @Test
+       void createCollection_success_cloudClient() throws Exception {
+               CloudSolrClient cloudClient = mock(CloudSolrClient.class);
+               when(cloudClient.request(any(), any())).thenReturn(new 
NamedList<>());
+
+               CollectionService service = new CollectionService(cloudClient, 
objectMapper);
+               CollectionCreationResult result = 
service.createCollection("new_collection", "_default", 1, 1);
+
+               assertNotNull(result);
+               assertTrue(result.success());
+               assertEquals("new_collection", result.name());
+               assertNotNull(result.createdAt());
+       }
+
+       @Test
+       void createCollection_success_standaloneClient() throws Exception {
+               when(solrClient.request(any(), isNull())).thenReturn(new 
NamedList<>());
+
+               CollectionCreationResult result = 
collectionService.createCollection("new_core", null, null, null);
+
+               assertNotNull(result);
+               assertTrue(result.success());
+               assertEquals("new_core", result.name());
+               assertNotNull(result.createdAt());
+       }
+
+       @Test
+       void createCollection_defaultsApplied() throws Exception {
+               CloudSolrClient cloudClient = mock(CloudSolrClient.class);
+               when(cloudClient.request(any(), any())).thenReturn(new 
NamedList<>());
+
+               CollectionService service = new CollectionService(cloudClient, 
objectMapper);
+               CollectionCreationResult result = 
service.createCollection("defaults_collection", null, null, null);
+
+               assertTrue(result.success());
+               assertEquals("defaults_collection", result.name());
+       }
+
+       @Test
+       void createCollection_blankName_throwsIllegalArgument() {
+               assertThrows(IllegalArgumentException.class, () -> 
collectionService.createCollection("   ", null, null, null));
+       }
+
+       @Test
+       void createCollection_emptyName_throwsIllegalArgument() {
+               assertThrows(IllegalArgumentException.class, () -> 
collectionService.createCollection("", null, null, null));
+       }
+
+       @Test
+       void createCollection_solrException_propagates() throws Exception {
+               when(solrClient.request(any(), isNull())).thenThrow(new 
SolrServerException("Solr error"));
+
+               assertThrows(SolrServerException.class,
+                               () -> 
collectionService.createCollection("fail_core", null, null, null));
+       }
 }
diff --git 
a/src/test/java/org/apache/solr/mcp/server/metadata/CollectionUtilsTest.java 
b/src/test/java/org/apache/solr/mcp/server/collection/CollectionUtilsTest.java
similarity index 99%
rename from 
src/test/java/org/apache/solr/mcp/server/metadata/CollectionUtilsTest.java
rename to 
src/test/java/org/apache/solr/mcp/server/collection/CollectionUtilsTest.java
index 2365494..a4f9a7d 100644
--- a/src/test/java/org/apache/solr/mcp/server/metadata/CollectionUtilsTest.java
+++ 
b/src/test/java/org/apache/solr/mcp/server/collection/CollectionUtilsTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.solr.mcp.server.metadata;
+package org.apache.solr.mcp.server.collection;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
diff --git 
a/src/test/java/org/apache/solr/mcp/server/collection/ConferenceEndToEndIntegrationTest.java
 
b/src/test/java/org/apache/solr/mcp/server/collection/ConferenceEndToEndIntegrationTest.java
new file mode 100644
index 0000000..94f17d4
--- /dev/null
+++ 
b/src/test/java/org/apache/solr/mcp/server/collection/ConferenceEndToEndIntegrationTest.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.mcp.server.collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import org.apache.solr.mcp.server.TestcontainersConfiguration;
+import org.apache.solr.mcp.server.indexing.IndexingService;
+import org.apache.solr.mcp.server.search.SearchResponse;
+import org.apache.solr.mcp.server.search.SearchService;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+/**
+ * End-to-end integration test that exercises the full create, index, and 
search
+ * workflow using the DevNexus 2026 conference schedule sample data.
+ */
+@SpringBootTest
+@Import(TestcontainersConfiguration.class)
+@Testcontainers(disabledWithoutDocker = true)
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class ConferenceEndToEndIntegrationTest {
+
+       private static final String COLLECTION = "conferences";
+
+       private static final int TOTAL_SESSIONS = 116;
+
+       @Autowired
+       private CollectionService collectionService;
+
+       @Autowired
+       private IndexingService indexingService;
+
+       @Autowired
+       private SearchService searchService;
+
+       @BeforeAll
+       void createAndIndexConferences() throws Exception {
+               CollectionCreationResult result = 
collectionService.createCollection(COLLECTION, null, null, null);
+               assertTrue(result.success(), "Collection creation should 
succeed: " + result.message());
+
+               String json = 
Files.readString(Path.of("mydata/devnexus-2026.json"));
+               indexingService.indexJsonDocuments(COLLECTION, json);
+       }
+
+       @Test
+       @Order(1)
+       void collectionAppearsInList() {
+               List<String> collections = collectionService.listCollections();
+               boolean found = collections.contains(COLLECTION)
+                               || collections.stream().anyMatch(c -> 
c.startsWith(COLLECTION + "_shard"));
+               assertTrue(found, "conferences collection should be listed, 
found: " + collections);
+       }
+
+       @Test
+       @Order(2)
+       void collectionHealthIsHealthy() {
+               SolrHealthStatus health = 
collectionService.checkHealth(COLLECTION);
+               assertTrue(health.isHealthy(), "conferences collection should 
be healthy");
+               assertEquals(Long.valueOf(TOTAL_SESSIONS), 
health.totalDocuments(), "Should contain 116 conference sessions");
+       }
+
+       @Test
+       @Order(3)
+       void searchAllDocumentsReturns116() throws Exception {
+               SearchResponse response = searchService.search(COLLECTION, 
"*:*", null, null, null, 0, 0);
+               assertEquals(TOTAL_SESSIONS, response.numFound(), "Total 
results should be 116");
+       }
+
+       @Test
+       @Order(4)
+       void searchByTrackReturnsFilteredResults() throws Exception {
+               SearchResponse response = searchService.search(COLLECTION, 
"*:*", List.of("track:Workshop"), null, null, 0, 10);
+               assertTrue(response.numFound() > 0, "Should find workshop 
sessions");
+               for (Map<String, Object> doc : response.documents()) {
+                       Object track = doc.get("track");
+                       String trackValue = track instanceof List ? ((List<?>) 
track).get(0).toString() : track.toString();
+                       assertEquals("Workshop", trackValue, "All results 
should be workshops");
+               }
+       }
+
+       @Test
+       @Order(5)
+       void searchByKeywordFindsMatchingSessions() throws Exception {
+               SearchResponse response = searchService.search(COLLECTION, 
"title:Spring", null, null, null, 0, 50);
+               assertTrue(response.numFound() > 0, "Should find sessions with 
'Spring' in the title");
+               for (Map<String, Object> doc : response.documents()) {
+                       Object title = doc.get("title");
+                       String titleValue = title instanceof List ? ((List<?>) 
title).get(0).toString() : title.toString();
+                       assertTrue(titleValue.toLowerCase().contains("spring"), 
"Title should contain 'spring': " + titleValue);
+               }
+       }
+
+       @Test
+       @Order(6)
+       void facetByIdReturnsResults() throws Exception {
+               // Facet on 'id' which is always a string type in Solr's 
_default configset;
+               // schema-less text fields (track, day) are tokenized and 
return empty facets.
+               SearchResponse response = searchService.search(COLLECTION, 
"*:*", null, List.of("id"), null, 0, 0);
+               assertNotNull(response.facets(), "Facets should not be null");
+               assertTrue(response.facets().containsKey("id"), "Should have id 
facet");
+
+               Map<String, Long> idFacets = response.facets().get("id");
+               assertFalse(idFacets.isEmpty(), "Id facets should not be 
empty");
+               // Solr default facet.limit is 100, so we get at most 100 
entries
+               assertTrue(idFacets.size() >= 100, "Should have facet entries 
for sessions");
+       }
+
+       @Test
+       @Order(7)
+       void paginationWorks() throws Exception {
+               SearchResponse page1 = searchService.search(COLLECTION, "*:*", 
null, null, null, 0, 10);
+               SearchResponse page2 = searchService.search(COLLECTION, "*:*", 
null, null, null, 10, 10);
+
+               assertEquals(10, page1.documents().size(), "Page 1 should have 
10 documents");
+               assertEquals(10, page2.documents().size(), "Page 2 should have 
10 documents");
+               assertEquals(TOTAL_SESSIONS, page1.numFound(), "Total should be 
116 across pages");
+
+               Object id1 = page1.documents().get(0).get("id");
+               Object id2 = page2.documents().get(0).get("id");
+               assertNotEquals(id1, id2, "Pages should return different 
documents");
+       }
+
+       @Test
+       @Order(8)
+       void collectionStatsShowIndexedDocuments() throws Exception {
+               SolrMetrics metrics = 
collectionService.getCollectionStats(COLLECTION);
+               assertNotNull(metrics, "Metrics should not be null");
+               assertNotNull(metrics.indexStats(), "Index stats should not be 
null");
+               assertEquals(Integer.valueOf(TOTAL_SESSIONS), 
metrics.indexStats().numDocs(),
+                               "Should report 116 indexed documents");
+       }
+
+}

Reply via email to