diff --git a/README.md b/README.md index 0d0c1f7c..1fafa419 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Using a different client, or want STDIO/HTTP/Docker options? See the per-client | `index-json-documents` | Index documents from a JSON string into a collection | | `index-csv-documents` | Index documents from a CSV string into a collection | | `index-xml-documents` | Index documents from an XML string into a collection | -| `index-markdown-documents` | Index a markdown document into a collection, extracting front matter, title, headings, and body text | +| `index-markdown-documents` | Index markdown documents into a collection (one array element per document), extracting front matter, title, headings, and body text | | `create-collection` | Create a collection (configSet, numShards, replicationFactor optional — default `_default`, `1`, `1`) | | `list-collections` | List all available Solr collections | | `get-collection-stats` | Get statistics and metrics for a collection | diff --git a/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java b/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java index 13504967..9aa3c5ef 100644 --- a/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java +++ b/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java @@ -18,6 +18,7 @@ import io.micrometer.observation.annotation.Observed; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -400,7 +401,8 @@ public String indexXmlDocuments(@McpToolParam(description = "Solr collection to } /** - * Indexes a document from a markdown string into a specified Solr collection. + * Indexes markdown documents into a specified Solr collection, one array + * element per document. * *

* This method serves as the primary entry point for markdown document indexing @@ -447,9 +449,8 @@ public String indexXmlDocuments(@McpToolParam(description = "Solr collection to * * @param collection * the name of the Solr collection to index documents into - * @param markdown - * markdown string to index, optionally starting with YAML front - * matter + * @param documents + * the markdown documents, one string per document matter * @throws IOException * if there are critical errors in Solr communication * @throws SolrServerException @@ -461,14 +462,21 @@ public String indexXmlDocuments(@McpToolParam(description = "Solr collection to @McpTool( name = "index-markdown-documents", annotations = @McpTool.McpAnnotations(idempotentHint = true), - description = "Index a document from markdown String into Solr collection, extracting front matter, title, headings, and body text. " + description = "Index markdown documents into Solr collection, one array element per document, extracting front matter, title, headings, and body text from each. " + + "Pass many documents in one call rather than one call per document. " + "Do NOT use for JSON/CSV/XML input; use index-json-documents, index-csv-documents, or index-xml-documents instead. " + "Only convert source content to markdown when there is no dedicated tool for the source format, and supply a stable 'id' in the YAML front matter when doing so.") public String indexMarkdownDocuments(@McpToolParam(description = "Solr collection to index into") String collection, @McpToolParam( - description = "Markdown string to index, optionally starting with YAML front matter") String markdown) + description = "Markdown documents to index, one string per document, each optionally starting with YAML front matter") List documents) throws IOException, SolrServerException { - List schemalessDoc = indexingDocumentCreator.createSchemalessDocumentsFromMarkdown(markdown); + if (documents == null) { + throw new IllegalArgumentException("documents cannot be null"); + } + List schemalessDoc = new ArrayList<>(); + for (String markdown : documents) { + schemalessDoc.addAll(indexingDocumentCreator.createSchemalessDocumentsFromMarkdown(markdown)); + } int successCount = indexDocuments(collection, schemalessDoc); return "Successfully indexed " + successCount + " of " + schemalessDoc.size() + " documents into collection '" + collection + "'"; @@ -620,7 +628,7 @@ private static IndexTool resolveIndexTool(String format) { case "json" -> new IndexTool("index-json-documents", "json"); case "csv" -> new IndexTool("index-csv-documents", "csv"); case "xml" -> new IndexTool("index-xml-documents", "xml"); - case "markdown", "md" -> new IndexTool("index-markdown-documents", "markdown"); + case "markdown", "md" -> new IndexTool("index-markdown-documents", "documents"); default -> throw new IllegalArgumentException("format must be one of json/csv/xml/markdown, got: " + format); }; @@ -691,7 +699,7 @@ public String indexDataPrompt( Next step suggestion: once data is indexed, the `search-collection` prompt drives searching it. - """.formatted(indexTool.paramName(), collection, collection, sampleSection, indexTool.name(), + """.formatted(format.trim().toLowerCase(), collection, collection, sampleSection, indexTool.name(), collection, indexTool.paramName(), collection); } } diff --git a/src/test/java/org/apache/solr/mcp/server/McpClientIntegrationTestBase.java b/src/test/java/org/apache/solr/mcp/server/McpClientIntegrationTestBase.java index 3b9f2302..25c025d8 100644 --- a/src/test/java/org/apache/solr/mcp/server/McpClientIntegrationTestBase.java +++ b/src/test/java/org/apache/solr/mcp/server/McpClientIntegrationTestBase.java @@ -418,7 +418,7 @@ void indexMarkdownDocumentAndFindItById() throws Exception { """; CallToolResult indexResult = mcpClient.callTool(new CallToolRequest("index-markdown-documents", - Map.of("collection", COLLECTION, "markdown", markdown))); + Map.of("collection", COLLECTION, "documents", List.of(markdown)))); assertNotNull(indexResult); assertNotError(indexResult); diff --git a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java index b1491d16..3d887213 100644 --- a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java +++ b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java @@ -324,6 +324,20 @@ private List createMockDocuments(int count) { return docs; } + @Test + void indexMarkdownDocuments_IndexesEachElementAsItsOwnDocument() throws Exception { + when(indexingDocumentCreator.createSchemalessDocumentsFromMarkdown("# One")).thenReturn(createMockDocuments(1)); + when(indexingDocumentCreator.createSchemalessDocumentsFromMarkdown("# Two")).thenReturn(createMockDocuments(1)); + when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null); + + String result = indexingService.indexMarkdownDocuments("test_collection", List.of("# One", "# Two")); + + assertTrue(result.contains("2 of 2"), result); + verify(indexingDocumentCreator).createSchemalessDocumentsFromMarkdown("# One"); + verify(indexingDocumentCreator).createSchemalessDocumentsFromMarkdown("# Two"); + verify(solrClient, times(1)).add(eq("test_collection"), any(Collection.class)); + } + @Test void indexDataPrompt_jsonPath_referencesIndexJsonDocuments() { String sample = """