From c38ff29599b9d1219116f12b51dd3c78666ded7f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 9 Nov 2025 13:54:19 +0000
Subject: [PATCH 1/3] Initial plan
From 804e0f892296e39cac0f3fd985b0bcaae1cea496 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 9 Nov 2025 14:03:28 +0000
Subject: [PATCH 2/3] Fix: Add McpServerToolType attribute to expose PivotTable
tool
- Added [McpServerToolType] attribute to ExcelPivotTableTool class
- Added explicit Name = "excel_pivottable" to [McpServerTool] attribute
- Matches pattern used by all other working MCP tools
- Enables MCP SDK's WithToolsFromAssembly() to discover the tool
The tool implementation was complete but missing the required attributes
for auto-discovery. LLMs can now find and use excel_pivottable.
Co-authored-by: sbroenne <3026464+sbroenne@users.noreply.github.com>
---
src/ExcelMcp.McpServer/Tools/ExcelPivotTableTool.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ExcelMcp.McpServer/Tools/ExcelPivotTableTool.cs b/src/ExcelMcp.McpServer/Tools/ExcelPivotTableTool.cs
index 1d8bb9b9..b6b8ed73 100644
--- a/src/ExcelMcp.McpServer/Tools/ExcelPivotTableTool.cs
+++ b/src/ExcelMcp.McpServer/Tools/ExcelPivotTableTool.cs
@@ -12,11 +12,12 @@ namespace Sbroenne.ExcelMcp.McpServer.Tools;
///
/// MCP tool for Excel PivotTable operations
///
+[McpServerToolType]
public static partial class ExcelPivotTableTool
{
private static readonly JsonSerializerOptions JsonOptions = ExcelToolsBase.JsonOptions;
- [McpServerTool]
+ [McpServerTool(Name = "excel_pivottable")]
[Description(@"Excel PivotTable operations - interactive data analysis and summarization.
DATA SOURCES:
From 555c643cb1e7669e66dcbd7e3624b05451be67aa Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 9 Nov 2025 14:05:19 +0000
Subject: [PATCH 3/3] Add unit tests to verify tool discovery attributes
- Created ToolDiscoveryTests to verify all 11 MCP tools have required attributes
- Tests verify [McpServerToolType] on class and [McpServerTool(Name)] on method
- All 24 tests pass, confirming PivotTable tool is properly configured
- Prevents regression of tool discovery issues
Co-authored-by: sbroenne <3026464+sbroenne@users.noreply.github.com>
---
.../Unit/ToolDiscoveryTests.cs | 93 +++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 tests/ExcelMcp.McpServer.Tests/Unit/ToolDiscoveryTests.cs
diff --git a/tests/ExcelMcp.McpServer.Tests/Unit/ToolDiscoveryTests.cs b/tests/ExcelMcp.McpServer.Tests/Unit/ToolDiscoveryTests.cs
new file mode 100644
index 00000000..a5d05b44
--- /dev/null
+++ b/tests/ExcelMcp.McpServer.Tests/Unit/ToolDiscoveryTests.cs
@@ -0,0 +1,93 @@
+using System.Reflection;
+using ModelContextProtocol.Server;
+using Sbroenne.ExcelMcp.McpServer.Tools;
+using Xunit;
+
+namespace Sbroenne.ExcelMcp.McpServer.Tests.Unit;
+
+///
+/// Tests to verify that all MCP tools are properly decorated with required attributes
+/// for discovery by the MCP SDK's WithToolsFromAssembly() method.
+///
+[Trait("Category", "Unit")]
+[Trait("Speed", "Fast")]
+[Trait("Layer", "McpServer")]
+[Trait("Feature", "ToolDiscovery")]
+public class ToolDiscoveryTests
+{
+ [Fact]
+ public void ExcelPivotTableTool_HasMcpServerToolTypeAttribute()
+ {
+ // Arrange
+ var toolType = typeof(ExcelPivotTableTool);
+
+ // Act
+ var attribute = toolType.GetCustomAttribute();
+
+ // Assert
+ Assert.NotNull(attribute);
+ }
+
+ [Fact]
+ public void ExcelPivotTableTool_HasMcpServerToolAttributeWithName()
+ {
+ // Arrange
+ var toolType = typeof(ExcelPivotTableTool);
+ var method = toolType.GetMethod("ExcelPivotTable", BindingFlags.Public | BindingFlags.Static);
+ Assert.NotNull(method);
+
+ // Act
+ var attribute = method!.GetCustomAttribute();
+
+ // Assert
+ Assert.NotNull(attribute);
+ Assert.Equal("excel_pivottable", attribute!.Name);
+ }
+
+ [Theory]
+ [InlineData(typeof(ExcelConnectionTool), "ExcelConnection", "excel_connection")]
+ [InlineData(typeof(ExcelDataModelTool), "ExcelDataModel", "excel_datamodel")]
+ [InlineData(typeof(ExcelFileTool), "ExcelFile", "excel_file")]
+ [InlineData(typeof(ExcelNamedRangeTool), "ExcelParameter", "excel_namedrange")]
+ [InlineData(typeof(ExcelPivotTableTool), "ExcelPivotTable", "excel_pivottable")]
+ [InlineData(typeof(ExcelPowerQueryTool), "ExcelPowerQuery", "excel_powerquery")]
+ [InlineData(typeof(ExcelQueryTableTool), "ExcelQueryTable", "excel_querytable")]
+ [InlineData(typeof(ExcelRangeTool), "ExcelRange", "excel_range")]
+ [InlineData(typeof(TableTool), "Table", "excel_table")]
+ [InlineData(typeof(ExcelVbaTool), "ExcelVba", "excel_vba")]
+ [InlineData(typeof(ExcelWorksheetTool), "ExcelWorksheet", "excel_worksheet")]
+ public void AllTools_HaveMcpServerToolAttributeWithCorrectName(Type toolType, string methodName, string expectedToolName)
+ {
+ // Arrange
+ var method = toolType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
+ Assert.NotNull(method);
+
+ // Act
+ var attribute = method!.GetCustomAttribute();
+
+ // Assert
+ Assert.NotNull(attribute);
+ Assert.Equal(expectedToolName, attribute!.Name);
+ }
+
+ [Theory]
+ [InlineData(typeof(ExcelConnectionTool))]
+ [InlineData(typeof(ExcelDataModelTool))]
+ [InlineData(typeof(ExcelFileTool))]
+ [InlineData(typeof(ExcelNamedRangeTool))]
+ [InlineData(typeof(ExcelPivotTableTool))]
+ [InlineData(typeof(ExcelPowerQueryTool))]
+ [InlineData(typeof(ExcelQueryTableTool))]
+ [InlineData(typeof(ExcelRangeTool))]
+ [InlineData(typeof(TableTool))]
+ [InlineData(typeof(ExcelVbaTool))]
+ [InlineData(typeof(ExcelWorksheetTool))]
+ public void AllTools_HaveMcpServerToolTypeAttribute(Type toolType)
+ {
+ // Act
+ var attribute = toolType.GetCustomAttribute();
+
+ // Assert
+ Assert.NotNull(attribute);
+ }
+}