diff --git a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/CollectionCommandTools.java b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/CollectionCommandTools.java
index efb89bf227..a55c028a00 100644
--- a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/CollectionCommandTools.java
+++ b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/CollectionCommandTools.java
@@ -22,6 +22,9 @@
* MCP tool provider for collection-level (and table-level) commands {@link
* io.stargate.sgv2.jsonapi.api.model.command.CollectionCommand}. These correspond to the {@link
* io.stargate.sgv2.jsonapi.api.v1.CollectionResource} REST endpoint.
+ *
+ *
The filter and sort arguments have no description here. A {@code @ToolArg} description would
+ * replace the one on their classes, which Swagger also uses.
*/
public class CollectionCommandTools {
@@ -31,7 +34,10 @@ public class CollectionCommandTools {
public Uni alterTable(
@ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the table") String table,
- @ToolArg(description = "The alter table operation") AlterTableOperation operation) {
+ @ToolArg(
+ description =
+ "One change to the table, keyed by add, drop, addVectorize, or dropVectorize, for example {\"add\": {\"columns\": {\"rating\": \"int\"}}}")
+ AlterTableOperation operation) {
var command = new AlterTableCommand(operation);
return mcpResource.processCollectionCommand(keyspace, table, command);
@@ -41,7 +47,7 @@ public Uni alterTable(
public Uni countDocuments(
@ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the collection") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter) {
+ @ToolArg(required = false) FilterDefinition filter) {
var command = new CountDocumentsCommand(filter);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -51,17 +57,22 @@ public Uni countDocuments(
public Uni createIndex(
@ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the table") String table,
- @ToolArg(description = "Name of the new Index") String indexName,
- @ToolArg(description = "Definition of the index to create")
+ @ToolArg(description = "Name of the new index") String indexName,
+ @ToolArg(
+ description =
+ "Column to index and its index options, for example {\"column\": \"status\"}")
RegularIndexDefinitionDesc definition,
@ToolArg(
description =
- "Optional type of the index to create. The only supported value is '"
+ "Type of the index to create. The only supported value is '"
+ ApiIndexType.Constants.REGULAR
+ "'.",
required = false)
String indexType,
- @ToolArg(description = "Options for the command.", required = false)
+ @ToolArg(
+ description =
+ "Set ifNotExists to true to succeed when an index with this name already exists",
+ required = false)
CreateIndexCommand.CreateIndexCommandOptions options) {
var command = new CreateIndexCommand(indexName, definition, indexType, options);
@@ -74,17 +85,22 @@ public Uni createIndex(
public Uni createTextIndex(
@ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the table") String table,
- @ToolArg(description = "Name of the new Index") String indexName,
- @ToolArg(description = "Definition of the index to create")
+ @ToolArg(description = "Name of the new index") String indexName,
+ @ToolArg(
+ description =
+ "Column to index and its index options, for example {\"column\": \"title\"}")
TextIndexDefinitionDesc definition,
@ToolArg(
description =
- "Optional type of the index to create. The only supported value is '"
+ "Type of the index to create. The only supported value is '"
+ ApiIndexType.Constants.TEXT
+ "'.",
required = false)
String indexType,
- @ToolArg(description = "Options for the command.", required = false)
+ @ToolArg(
+ description =
+ "Set ifNotExists to true to succeed when an index with this name already exists",
+ required = false)
CreateTextIndexCommand.CommandOptions options) {
var command = new CreateTextIndexCommand(indexName, definition, indexType, options);
@@ -95,17 +111,22 @@ public Uni createTextIndex(
public Uni createVectorIndex(
@ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the table") String table,
- @ToolArg(description = "Name of the new Index") String indexName,
- @ToolArg(description = "Definition of the index to create")
+ @ToolArg(description = "Name of the new index") String indexName,
+ @ToolArg(
+ description =
+ "Column to index and its index options, for example {\"column\": \"embedding\", \"options\": {\"metric\": \"cosine\"}}")
VectorIndexDefinitionDesc definition,
@ToolArg(
description =
- "Optional type of the index to create. The only supported value is '"
+ "Type of the index to create. The only supported value is '"
+ ApiIndexType.Constants.VECTOR
+ "'.",
required = false)
String indexType,
- @ToolArg(description = "Options for the command.", required = false)
+ @ToolArg(
+ description =
+ "Set ifNotExists to true to succeed when an index with this name already exists",
+ required = false)
CreateVectorIndexCommand.CreateVectorIndexCommandOptions options) {
var command = new CreateVectorIndexCommand(indexName, definition, indexType, options);
@@ -117,11 +138,8 @@ public Uni createVectorIndex(
"Command that finds documents based on the filter and deletes them from a collection")
public Uni deleteMany(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(
- description = "Filter clause based on which documents are identified",
- required = false)
- FilterDefinition filter) {
+ @ToolArg(description = "Name of the collection or table") String collection,
+ @ToolArg(required = false) FilterDefinition filter) {
var command = new DeleteManyCommand(filter);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -130,10 +148,9 @@ public Uni deleteMany(
@Tool(description = "Command that finds a single document and deletes it from a collection")
public Uni deleteOne(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "Filter clause based on which documents are identified")
- FilterDefinition filter,
- @ToolArg(description = "Sort clause", required = false) SortDefinition sort) {
+ @ToolArg(description = "Name of the collection or table") String collection,
+ @ToolArg FilterDefinition filter,
+ @ToolArg(required = false) SortDefinition sort) {
var command = new DeleteOneCommand(filter, sort);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -152,8 +169,6 @@ public Uni estimatedDocumentCount(
public Uni findAndRerank(
@ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the collection") String collection,
- // filter and sort have no description here because it would replace the one on their
- // classes, which Swagger also uses.
@ToolArg(required = false) FilterDefinition filter,
@ToolArg(
description =
@@ -173,11 +188,18 @@ public Uni findAndRerank(
@Tool(description = "Command that finds JSON documents from a collection.")
public Uni find(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter,
- @ToolArg(description = "projection", required = false) JsonNode projection,
- @ToolArg(description = "sort", required = false) SortDefinition sort,
- @ToolArg(description = "options", required = false) FindCommand.Options options) {
+ @ToolArg(description = "Name of the collection or table") String collection,
+ @ToolArg(required = false) FilterDefinition filter,
+ @ToolArg(
+ description =
+ "Fields to include or exclude in the returned documents, for example {\"title\": 1}",
+ required = false)
+ JsonNode projection,
+ @ToolArg(required = false) SortDefinition sort,
+ @ToolArg(
+ description = "Options for result limits, paging, and what the response includes",
+ required = false)
+ FindCommand.Options options) {
var command = new FindCommand(filter, projection, sort, options);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -188,10 +210,14 @@ public Uni find(
"Command that finds a single JSON document from a collection and deletes it. The deleted document is returned")
public Uni findOneAndDelete(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter,
- @ToolArg(description = "sort", required = false) SortDefinition sort,
- @ToolArg(description = "projection", required = false) JsonNode projection) {
+ @ToolArg(description = "Name of the collection") String collection,
+ @ToolArg(required = false) FilterDefinition filter,
+ @ToolArg(required = false) SortDefinition sort,
+ @ToolArg(
+ description =
+ "Fields to include or exclude in the returned document, for example {\"title\": 1}",
+ required = false)
+ JsonNode projection) {
var command = new FindOneAndDeleteCommand(filter, sort, projection);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -202,12 +228,22 @@ public Uni findOneAndDelete(
"Command that finds a single JSON document from a collection and replaces it with the replacement document.")
public Uni findOneAndReplace(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter,
- @ToolArg(description = "sort", required = false) SortDefinition sort,
- @ToolArg(description = "projection", required = false) JsonNode projection,
- @ToolArg(description = "replacement") ObjectNode replacement,
- @ToolArg(description = "options", required = false)
+ @ToolArg(description = "Name of the collection") String collection,
+ @ToolArg(required = false) FilterDefinition filter,
+ @ToolArg(required = false) SortDefinition sort,
+ @ToolArg(
+ description =
+ "Fields to include or exclude in the returned document, for example {\"title\": 1}",
+ required = false)
+ JsonNode projection,
+ @ToolArg(
+ description =
+ "Document that replaces the matching document, for example {\"title\": \"Dune\", \"status\": \"active\"}")
+ ObjectNode replacement,
+ @ToolArg(
+ description =
+ "Options for upsert and whether to return the document before or after the replacement",
+ required = false)
FindOneAndReplaceCommand.Options options) {
var command = new FindOneAndReplaceCommand(filter, sort, projection, replacement, options);
@@ -219,12 +255,20 @@ public Uni findOneAndReplace(
"Command that finds a single JSON document from a collection and updates the values provided in the update clause.")
public Uni findOneAndUpdate(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter,
- @ToolArg(description = "projection", required = false) JsonNode projection,
- @ToolArg(description = "sort", required = false) SortDefinition sort,
- @ToolArg(description = "update") UpdateClause update,
- @ToolArg(description = "options", required = false) FindOneAndUpdateCommand.Options options) {
+ @ToolArg(description = "Name of the collection") String collection,
+ @ToolArg(required = false) FilterDefinition filter,
+ @ToolArg(
+ description =
+ "Fields to include or exclude in the returned document, for example {\"title\": 1}",
+ required = false)
+ JsonNode projection,
+ @ToolArg(required = false) SortDefinition sort,
+ @ToolArg UpdateClause update,
+ @ToolArg(
+ description =
+ "Options for upsert and whether to return the document before or after the update",
+ required = false)
+ FindOneAndUpdateCommand.Options options) {
var command = new FindOneAndUpdateCommand(filter, projection, sort, update, options);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -233,11 +277,16 @@ public Uni findOneAndUpdate(
@Tool(description = "Command that finds a single JSON document from a collection.")
public Uni findOne(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter,
- @ToolArg(description = "projection", required = false) JsonNode projection,
- @ToolArg(description = "sort", required = false) SortDefinition sort,
- @ToolArg(description = "options", required = false) FindOneCommand.Options options) {
+ @ToolArg(description = "Name of the collection or table") String collection,
+ @ToolArg(required = false) FilterDefinition filter,
+ @ToolArg(
+ description =
+ "Fields to include or exclude in the returned document, for example {\"title\": 1}",
+ required = false)
+ JsonNode projection,
+ @ToolArg(required = false) SortDefinition sort,
+ @ToolArg(description = "Options for what the response includes", required = false)
+ FindOneCommand.Options options) {
var command = new FindOneCommand(filter, projection, sort, options);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -247,7 +296,9 @@ public Uni findOne(
public Uni listIndexes(
@ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the table") String table,
- @ToolArg(description = "Options for the `listIndexes` command.", required = false)
+ @ToolArg(
+ description = "Set explain to true to include the properties of each index",
+ required = false)
ListIndexesCommand.Options options) {
var command = new ListIndexesCommand(options);
@@ -257,9 +308,12 @@ public Uni listIndexes(
@Tool(description = "Command that inserts multiple JSON documents to a collection.")
public Uni insertMany(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "JSON documents to insert") List documents,
- @ToolArg(description = "Options for inserting many documents", required = false)
+ @ToolArg(description = "Name of the collection or table") String collection,
+ @ToolArg(
+ description =
+ "Documents or rows to insert, for example [{\"title\": \"Dune\"}, {\"title\": \"Emma\"}]")
+ List documents,
+ @ToolArg(description = "Options for insert order and per-document results", required = false)
InsertManyCommand.Options options) {
var command = new InsertManyCommand(documents, options);
@@ -269,8 +323,11 @@ public Uni insertMany(
@Tool(description = "Command that inserts a single JSON document to a collection.")
public Uni insertOne(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "JSON document to insert") JsonNode document) {
+ @ToolArg(description = "Name of the collection or table") String collection,
+ @ToolArg(
+ description =
+ "Document or row to insert, for example {\"title\": \"Dune\", \"status\": \"active\"}")
+ JsonNode document) {
var command = new InsertOneCommand(document);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -281,10 +338,11 @@ public Uni insertOne(
"Command that finds documents from a collection and updates it with the values provided in the update clause.")
public Uni updateMany(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter,
- @ToolArg(description = "update") UpdateClause update,
- @ToolArg(description = "options", required = false) UpdateManyCommand.Options options) {
+ @ToolArg(description = "Name of the collection") String collection,
+ @ToolArg(required = false) FilterDefinition filter,
+ @ToolArg UpdateClause update,
+ @ToolArg(description = "Options for upsert and paging", required = false)
+ UpdateManyCommand.Options options) {
var command = new UpdateManyCommand(filter, update, options);
return mcpResource.processCollectionCommand(keyspace, collection, command);
@@ -295,11 +353,14 @@ public Uni updateMany(
"Command that finds a single JSON document from a table or collection and updates the values provided in the update clause.")
public Uni updateOne(
@ToolArg(description = "Name of the keyspace") String keyspace,
- @ToolArg(description = "Name of the collection/table") String collection,
- @ToolArg(description = "filter", required = false) FilterDefinition filter,
- @ToolArg(description = "update") UpdateClause update,
- @ToolArg(description = "sort", required = false) SortDefinition sort,
- @ToolArg(description = "options", required = false) UpdateOneCommand.Options options) {
+ @ToolArg(description = "Name of the collection or table") String collection,
+ @ToolArg(required = false) FilterDefinition filter,
+ @ToolArg UpdateClause update,
+ @ToolArg(required = false) SortDefinition sort,
+ @ToolArg(
+ description = "Set upsert to true to insert a document when none matches the filter",
+ required = false)
+ UpdateOneCommand.Options options) {
var command = new UpdateOneCommand(filter, update, sort, options);
return mcpResource.processCollectionCommand(keyspace, collection, command);
diff --git a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/GeneralCommandTools.java b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/GeneralCommandTools.java
index aaf01203ea..c50fb114a6 100644
--- a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/GeneralCommandTools.java
+++ b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/GeneralCommandTools.java
@@ -22,8 +22,8 @@ public class GeneralCommandTools {
@Tool(description = "Command that creates a keyspace.")
public Uni createKeyspace(
- @ToolArg(description = "Required name of the new Keyspace") String name,
- @ToolArg(description = "Options for creating a new keyspace.", required = false)
+ @ToolArg(description = "Name of the new keyspace") String name,
+ @ToolArg(description = "Replication settings for the new keyspace", required = false)
CreateKeyspaceCommand.Options options) {
var command = new CreateKeyspaceCommand(name, options);
@@ -32,7 +32,7 @@ public Uni createKeyspace(
@Tool(description = "Command that deletes a Keyspace.")
public Uni dropKeyspace(
- @ToolArg(description = "Required name of the Keyspace to remove") @NotEmpty String name) {
+ @ToolArg(description = "Name of the keyspace to drop") @NotEmpty String name) {
var command = new DropKeyspaceCommand(name);
return mcpResource.processCommand(mcpResource.buildDatabaseContext(command), command);
@@ -49,7 +49,7 @@ public Uni findKeyspaces() {
public Uni findEmbeddingProviders(
@ToolArg(
description =
- "Optional model status filter: SUPPORTED, DEPRECATED, or END_OF_LIFE. If omitted, only SUPPORTED models are returned.",
+ "Set filterModelStatus to SUPPORTED, DEPRECATED, or END_OF_LIFE to list models with that status, or to an empty string to list all models. Without options, only SUPPORTED models are listed.",
required = false)
FindEmbeddingProvidersCommand.Options options) {
@@ -61,7 +61,7 @@ public Uni findEmbeddingProviders(
public Uni findRerankingProviders(
@ToolArg(
description =
- "Optional model status filter: SUPPORTED, DEPRECATED, or END_OF_LIFE. If omitted, only SUPPORTED models are returned.",
+ "Set filterModelStatus to SUPPORTED, DEPRECATED, or END_OF_LIFE to list models with that status, or to an empty string to list all models. Without options, only SUPPORTED models are listed.",
required = false)
FindRerankingProvidersCommand.Options options) {
diff --git a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/KeyspaceCommandTools.java b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/KeyspaceCommandTools.java
index faec415caa..b637e54eb0 100644
--- a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/KeyspaceCommandTools.java
+++ b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/mcp/KeyspaceCommandTools.java
@@ -24,9 +24,12 @@ public class KeyspaceCommandTools {
*/
@Tool(description = "Command that creates a collection.")
public Uni createCollection(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
+ @ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the new collection") String collection,
- @ToolArg(description = "Configuration options for the collection", required = false)
+ @ToolArg(
+ description =
+ "Collection settings for document IDs, vector search, indexing, lexical search, and reranking",
+ required = false)
CreateCollectionCommand.Options options) {
var command = new CreateCollectionCommand(collection, options);
@@ -35,8 +38,8 @@ public Uni createCollection(
@Tool(description = "Command that deletes a collection if one exists.")
public Uni deleteCollection(
- @ToolArg(description = "Name of the existing Keyspace") String keyspace,
- @ToolArg(description = "Name of the existing Collection") String collection) {
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(description = "Name of the collection to delete") String collection) {
var command = new DeleteCollectionCommand(collection);
return mcpResource.processCommand(mcpResource.buildKeyspaceContext(keyspace, command), command);
@@ -44,8 +47,10 @@ public Uni deleteCollection(
@Tool(description = "Command that lists all available collections in a keyspace.")
public Uni findCollections(
- @ToolArg(description = "Name of the existing Keyspace") String keyspace,
- @ToolArg(description = "include collection properties.", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(
+ description = "Set explain to true to include the properties of each collection",
+ required = false)
FindCollectionsCommand.Options options) {
var command = new FindCollectionsCommand(options);
@@ -57,11 +62,18 @@ public Uni findCollections(
*/
@Tool(description = "Command that alters a user defined type.")
public Uni alterType(
- @ToolArg(description = "Keyspace of the type to alter") String keyspace,
+ @ToolArg(description = "Name of the keyspace") String keyspace,
@ToolArg(description = "Name of the type to alter") String name,
- @ToolArg(description = "Operation to rename fields", required = false)
+ @ToolArg(
+ description =
+ "Fields to rename, mapping old names to new names, for example {\"fields\": {\"zip\": \"postcode\"}}",
+ required = false)
RenameTypeFieldsDesc rename,
- @ToolArg(description = "Operation to add fields", required = false) TypeDefinitionDesc add) {
+ @ToolArg(
+ description =
+ "Fields to add to the type, for example {\"fields\": {\"country\": \"text\"}}",
+ required = false)
+ TypeDefinitionDesc add) {
var command = new AlterTypeCommand(name, rename, add);
return mcpResource.processCommand(mcpResource.buildKeyspaceContext(keyspace, command), command);
@@ -69,10 +81,15 @@ public Uni alterType(
@Tool(description = "Command that creates an API Table.")
public Uni createTable(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
- @ToolArg(description = "Name of the new Table") String table,
- @ToolArg(description = "Table definition") TableDefinitionDesc definition,
- @ToolArg(description = "Configuration options for the table", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(description = "Name of the new table") String table,
+ @ToolArg(
+ description =
+ "Columns and primary key of the new table, for example {\"columns\": {\"id\": \"text\", \"title\": \"text\"}, \"primaryKey\": \"id\"}")
+ TableDefinitionDesc definition,
+ @ToolArg(
+ description = "Set ifNotExists to true to succeed when the table already exists",
+ required = false)
CreateTableCommand.Options options) {
var command = new CreateTableCommand(table, definition, options);
@@ -81,10 +98,15 @@ public Uni createTable(
@Tool(description = "Command that creates a user defined type.")
public Uni createType(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
- @ToolArg(description = "Name of the type to create") String name,
- @ToolArg(description = "Type definition") TypeDefinitionDesc definition,
- @ToolArg(description = "Configuration options for the command", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(description = "Name of the new type") String name,
+ @ToolArg(
+ description =
+ "Fields of the new type, for example {\"fields\": {\"city\": \"text\", \"postcode\": \"int\"}}")
+ TypeDefinitionDesc definition,
+ @ToolArg(
+ description = "Set ifNotExists to true to succeed when the type already exists",
+ required = false)
CreateTypeCommand.Options options) {
var command = new CreateTypeCommand(name, definition, options);
@@ -93,9 +115,11 @@ public Uni createType(
@Tool(description = "Command that drops an index for a column.")
public Uni dropIndex(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
- @ToolArg(description = "Name of the Index to remove") String name,
- @ToolArg(description = "Dropping index command option.", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(description = "Name of the index to drop") String name,
+ @ToolArg(
+ description = "Set ifExists to true to succeed when the index does not exist",
+ required = false)
DropIndexCommand.Options options) {
var command = new DropIndexCommand(name, options);
@@ -104,9 +128,11 @@ public Uni dropIndex(
@Tool(description = "Command that drops a table if one exists.")
public Uni dropTable(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
- @ToolArg(description = "Name of the Table to remove") String table,
- @ToolArg(description = "Optional options for drop command", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(description = "Name of the table to drop") String table,
+ @ToolArg(
+ description = "Set ifExists to true to succeed when the table does not exist",
+ required = false)
DropTableCommand.Options options) {
var command = new DropTableCommand(table, options);
@@ -115,9 +141,11 @@ public Uni dropTable(
@Tool(description = "Command that drops a user defined type if one exists.")
public Uni dropType(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
- @ToolArg(description = "Name of the Type to remove") String name,
- @ToolArg(description = "Options for drop command", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(description = "Name of the type to drop") String name,
+ @ToolArg(
+ description = "Set ifExists to true to succeed when the type does not exist",
+ required = false)
DropTypeCommand.Options options) {
var command = new DropTypeCommand(name, options);
@@ -126,8 +154,10 @@ public Uni dropType(
@Tool(description = "Command that lists all available tables in a keyspace")
public Uni listTables(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
- @ToolArg(description = "Options for the `listTables` command.", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(
+ description = "Set explain to true to include the properties of each table",
+ required = false)
ListTablesCommand.Options options) {
var command = new ListTablesCommand(options);
@@ -136,8 +166,10 @@ public Uni listTables(
@Tool(description = "Command that lists all available types in a keyspace")
public Uni listTypes(
- @ToolArg(description = "Name of the existing keyspace") String keyspace,
- @ToolArg(description = "Options for the `listTypes` command.", required = false)
+ @ToolArg(description = "Name of the keyspace") String keyspace,
+ @ToolArg(
+ description = "Set explain to true to include the fields of each type",
+ required = false)
ListTypesCommand.Options options) {
var command = new ListTypesCommand(options);
diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/mcp/McpClauseSchemaContractTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/mcp/McpClauseSchemaContractTest.java
index 99f5e33de0..372bb3eea0 100644
--- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/mcp/McpClauseSchemaContractTest.java
+++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/mcp/McpClauseSchemaContractTest.java
@@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -331,26 +332,78 @@ void rerankToolUsesSortClassDescription() throws Exception {
schemaMetadata(document, propertySchema(document, "sort"), "description").asText());
}
+ /** Clause arguments take their descriptions from their classes, which Swagger also uses. */
@Test
- void rerankToolUsesFilterClassDescription() throws Exception {
- var description = FilterDefinition.class.getAnnotation(Schema.class).description();
- assertFalse(description.isBlank());
- var document = inputSchema("findAndRerank");
- assertEquals(
- description,
- schemaMetadata(document, propertySchema(document, "filter"), "description").asText());
+ void clauseArgumentsUseClassDescriptions() throws Exception {
+ var filter = FilterDefinition.class.getAnnotation(Schema.class).description();
+ var sort = SortDefinition.class.getAnnotation(Schema.class).description();
+ var checked = 0;
+ for (var tool : toolManager) {
+ var document = inputSchema(tool.name());
+ var properties = document.path("properties");
+ if (properties.has("filter")) {
+ assertEquals(
+ filter,
+ schemaMetadata(document, properties.path("filter"), "description").asText(),
+ tool.name());
+ checked++;
+ }
+ // findAndRerank uses FindAndRerankSort, checked in rerankToolUsesSortClassDescription.
+ if (properties.has("sort") && !tool.name().equals("findAndRerank")) {
+ assertEquals(
+ sort,
+ schemaMetadata(document, properties.path("sort"), "description").asText(),
+ tool.name());
+ checked++;
+ }
+ }
+ assertTrue(checked > 0, "No tool has a filter or sort argument");
}
- /** A description that only repeats the argument name tells a client nothing. */
+ /**
+ * A description that only repeats the argument name tells a client nothing. The schema already
+ * lists required arguments, so descriptions do not start with "Optional" or "Required".
+ */
@Test
- void rerankToolDescribesEveryArgument() throws Exception {
- var document = inputSchema("findAndRerank");
- for (var argument : document.path("properties").properties()) {
- var name = argument.getKey();
- var description = schemaMetadata(document, argument.getValue(), "description").asText();
- assertFalse(description.isBlank(), name);
- assertNotEquals(name, description.toLowerCase(), name);
+ void everyToolDescribesEveryArgument() throws Exception {
+ for (var tool : toolManager) {
+ var document = inputSchema(tool.name());
+ for (var argument : document.path("properties").properties()) {
+ var label = tool.name() + "." + argument.getKey();
+ var description = schemaMetadata(document, argument.getValue(), "description").asText();
+ assertFalse(description.isBlank(), label);
+ assertNotEquals(argument.getKey(), description.toLowerCase(), label);
+ assertFalse(description.matches("(?i)(optional|required)\\b.*"), label);
+ }
+ }
+ }
+
+ /**
+ * Clients copy the example at the end of an argument description, so the server must parse it as
+ * that argument. Several argument schemas still show Java fields rather than the JSON, which
+ * makes the example the only reliable guide.
+ */
+ @Test
+ void argumentDescriptionExamplesDeserialize() throws Exception {
+ var marker = "for example ";
+ // Trailing text after the example would mean the example is not the whole JSON value.
+ var reader = objectMapper.reader().with(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
+ var checked = 0;
+ for (var tool : toolManager) {
+ for (var argument : tool.arguments()) {
+ var start = argument.description().indexOf(marker);
+ if (start < 0) {
+ continue;
+ }
+ var label = tool.name() + "." + argument.name();
+ var example = reader.readTree(argument.description().substring(start + marker.length()));
+ var type = objectMapper.constructType(argument.type());
+ assertNotNull(
+ assertDoesNotThrow(() -> objectMapper.treeToValue(example, type), label), label);
+ checked++;
+ }
}
+ assertTrue(checked > 0, "No argument description has an example");
}
@Test