Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions servers/Azure.Mcp.Server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ The Azure MCP Server updates automatically by default whenever a new release com

- Fixed problem where help option (`--help`) was showing an error and enabling it across all commands and command groups. [[#583](https://github.com/microsoft/mcp/pull/583)]

- Fixed `azmcp_kusto_table_schema` to return table schema. [[#530](https://github.com/microsoft/mcp/issues/530)]

### Other Changes

## 0.8.2 (2025-09-25)
Expand Down
5 changes: 2 additions & 3 deletions tools/Azure.Mcp.Tools.Kusto/src/Services/KustoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,9 @@ public async Task<string> GetTableSchemaAsync(
databaseName,
$".show table {tableName} cslschema", CancellationToken.None);
var result = KustoResultToStringList(kustoResult);
var schema = result.FirstOrDefault();
if (schema is not null)
if (result.Count > 0)
{
return schema;
return string.Join(Environment.NewLine, result);
}
throw new Exception($"No schema found for table '{tableName}' in database '{databaseName}'.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ public class KustoCommandTests(ITestOutputHelper output)
: CommandTestsBase(output)
{
private const string TestDatabaseName = "ToDoLists";
private const string TestTableName = "ToDoList";

#region Init
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync(); // Initialize the base class first
Expand Down Expand Up @@ -50,7 +52,9 @@ public override async ValueTask InitializeAsync()
Assert.Skip("Skipping until auth fixed for Kusto");
}
}
#endregion

#region Databases
[Fact]
public async Task Should_list_databases_in_cluster()
{
Expand All @@ -66,7 +70,9 @@ public async Task Should_list_databases_in_cluster()
Assert.Equal(JsonValueKind.Array, databasesArray.ValueKind);
Assert.NotEmpty(databasesArray.EnumerateArray());
}
#endregion

#region Tables
[Fact]
public async Task Should_list_kusto_tables()
{
Expand All @@ -84,6 +90,83 @@ public async Task Should_list_kusto_tables()
Assert.NotEmpty(tablesArray.EnumerateArray());
}

[Fact]
public async Task Should_list_tables_with_direct_uri()
{
var clusterInfo = await CallToolAsync(
"azmcp_kusto_cluster_get",
new()
{
{ "subscription", Settings.SubscriptionId },
{ "cluster", Settings.ResourceBaseName }
});

var clusterUri = clusterInfo.AssertProperty("cluster").AssertProperty("clusterUri").GetString();
Assert.NotNull(clusterUri);

var result = await CallToolAsync(
"azmcp_kusto_table_list",
new()
{
{ "cluster-uri", clusterUri },
{ "database", TestDatabaseName }
});

var tablesArray = result.AssertProperty("tables");
Assert.Equal(JsonValueKind.Array, tablesArray.ValueKind);
Assert.NotEmpty(tablesArray.EnumerateArray());
}

[Fact]
public async Task Should_get_table_schema()
{
var result = await CallToolAsync(
"azmcp_kusto_table_schema",
new()
{
{ "subscription", Settings.SubscriptionId },
{ "cluster", Settings.ResourceBaseName },
{ "database", TestDatabaseName },
{ "table", TestTableName }
});

var schema = result.AssertProperty("schema").GetString();
Assert.NotNull(schema);
Assert.Contains("Title:string", schema);
Assert.Contains("IsCompleted:bool", schema);
}

[Fact]
public async Task Should_get_table_schema_with_direct_uri()
{
var clusterInfo = await CallToolAsync(
"azmcp_kusto_cluster_get",
new()
{
{ "subscription", Settings.SubscriptionId },
{ "cluster", Settings.ResourceBaseName }
});

var clusterUri = clusterInfo.AssertProperty("cluster").AssertProperty("clusterUri").GetString();
Assert.NotNull(clusterUri);

var result = await CallToolAsync(
"azmcp_kusto_table_schema",
new()
{
{ "cluster-uri", clusterUri },
{ "database", TestDatabaseName },
{ "table", TestTableName }
});

var schema = result.AssertProperty("schema").GetString();
Assert.NotNull(schema);
Assert.Contains("Title:string", schema);
Assert.Contains("IsCompleted:bool", schema);
}
#endregion

#region Query
[Fact]
public async Task Should_query_kusto()
{
Expand All @@ -94,11 +177,40 @@ public async Task Should_query_kusto()
{ "subscription", Settings.SubscriptionId },
{ "cluster", Settings.ResourceBaseName },
{ "database", TestDatabaseName },
{ "query", "ToDoList | take 1" }
{ "query", $"{TestTableName} | take 1" }
});

var itemsArray = result.AssertProperty("items");
Assert.Equal(JsonValueKind.Array, itemsArray.ValueKind);
Assert.NotEmpty(itemsArray.EnumerateArray());
}

[Fact]
public async Task Should_query_kusto_with_direct_uri()
{
var clusterInfo = await CallToolAsync(
"azmcp_kusto_cluster_get",
new()
{
{ "subscription", Settings.SubscriptionId },
{ "cluster", Settings.ResourceBaseName }
});

var clusterUri = clusterInfo.AssertProperty("cluster").AssertProperty("clusterUri").GetString();
Assert.NotNull(clusterUri);

var result = await CallToolAsync(
"azmcp_kusto_query",
new()
{
{ "cluster-uri", clusterUri },
{ "database", TestDatabaseName },
{ "query", $"{TestTableName} | take 1" }
});

var itemsArray = result.AssertProperty("items");
Assert.Equal(JsonValueKind.Array, itemsArray.ValueKind);
Assert.NotEmpty(itemsArray.EnumerateArray());
}
#endregion
}
Loading