This guide explains how to update existing MCP tools to automatically use extra properties without manual service instantiation. The new pattern eliminates boilerplate code and provides automatic extra properties injection.
The BaseToolImplementation class now includes:
- Optional
IBuiltInToolExtraPropertiesServiceinjection in constructor GetExtraProperties()method with automatic fallbackExecuteWithExtraProperties()helper method for MCP tools
- Tools no longer need to manually instantiate
IBuiltInToolExtraPropertiesService - Extra properties are automatically fetched using the correct tool name format
- Fallback mechanism works in both DI and non-DI contexts
Look for MCP tool methods that follow this pattern:
[McpServerTool, Description("Tool description")]
public async Task<string> ToolMethodName([Description("JSON parameters")] string parameters = "{}")
{
try
{
// OPTION A: Manual service instantiation (needs updating)
var service = (IBuiltInToolExtraPropertiesService)Activator.CreateInstance(typeof(BuiltInToolExtraPropertiesService));
var latestExtraProps = service.GetExtraProperties("toolname");
var result = await ProcessAsync(parameters, latestExtraProps);
// OPTION B: Empty dictionary (needs updating)
var result = await ProcessAsync(parameters, new Dictionary<string, string>());
if (!result.WasProcessed)
{
return "Tool was not processed successfully.";
}
return result.ResultMessage ?? "Tool executed successfully with no output.";
}
catch (Exception ex)
{
return $"Error executing tool: {ex.Message}";
}
}Replace the entire method body with:
[McpServerTool, Description("Tool description")]
public async Task<string> ToolMethodName([Description("JSON parameters")] string parameters = "{}")
{
return await ExecuteWithExtraProperties(parameters);
}Search for files containing [McpServerTool to identify tools that need updating.
Search Command:
grep -r "McpServerTool.*Description" --include="*.cs"
For each file found:
- Locate the MCP method (marked with
[McpServerTool, Description(...)]) - Identify the pattern:
- Look for
ProcessAsync(parameters, new Dictionary<string, string>()) - Look for manual
IBuiltInToolExtraPropertiesServiceinstantiation - Look for try/catch blocks with error handling
- Look for
- Replace the entire method body with:
return await ExecuteWithExtraProperties(parameters);
[McpServerTool, Description("Gets a second opinion from another AI model")]
public async Task<string> SecondAiOpinion([Description("JSON parameters for SecondAiOpinion")] string parameters = "{}")
{
try
{
var service = (IBuiltInToolExtraPropertiesService)Activator.CreateInstance(typeof(BuiltInToolExtraPropertiesService));
var latestExtraProps = service.GetExtraProperties("secondAiOpinion");
var result = await ProcessAsync(parameters, latestExtraProps);
if (!result.WasProcessed)
{
return "Tool was not processed successfully.";
}
return result.ResultMessage ?? "Tool executed successfully with no output.";
}
catch (Exception ex)
{
return $"Error executing tool: {ex.Message}";
}
}[McpServerTool, Description("Gets a second opinion from another AI model")]
public async Task<string> SecondAiOpinion([Description("JSON parameters for SecondAiOpinion")] string parameters = "{}")
{
return await ExecuteWithExtraProperties(parameters);
}[McpServerTool, Description("Searches YouTube for videos")]
public async Task<string> YouTubeSearch([Description("JSON parameters for YouTubeSearch")] string parameters = "{}")
{
try
{
var result = await ProcessAsync(parameters, new Dictionary<string, string>());
if (!result.WasProcessed)
{
return "Tool was not processed successfully.";
}
return result.ResultMessage ?? "Tool executed successfully with no output.";
}
catch (Exception ex)
{
return $"Error executing YouTubeSearch: {ex.Message}";
}
}[McpServerTool, Description("Searches YouTube for videos")]
public async Task<string> YouTubeSearch([Description("JSON parameters for YouTubeSearch")] string parameters = "{}")
{
return await ExecuteWithExtraProperties(parameters);
}Based on the search results, these files contain MCP tools that need updating:
-
AiStudio4\Core\Tools\YouTube\YouTubeSearchTool.cs -
AiStudio4\Core\Tools\WindowsSandboxTool.cs -
AiStudio4\Core\Tools\ReadPartialFilesTool.cs -
AiStudio4\Core\Tools\GeminiGoogleSearchTool.cs -
AiStudio4\Core\Tools\ReadFilesTool.cs -
AiStudio4\Core\Tools\LaunchUrlTool.cs -
AiStudio4\Core\Tools\FileRegExSearchTool.cs -
AiStudio4\Core\Tools\ModifyFilesTool.cs -
AiStudio4\Core\Tools\GoogleCustomSearchApiTool.cs -
AiStudio4\Core\Tools\CreateNewFilesTool.cs -
AiStudio4\Core\Tools\ListFilesTool.cs -
AiStudio4\Core\Tools\GitCloneTool.cs -
AiStudio4\Core\Tools\GitCommitTool.cs -
AiStudio4\Core\Tools\GitDiffTool.cs -
AiStudio4\Core\Tools\GitLogTool.cs -
AiStudio4\Core\Tools\GitPushTool.cs -
AiStudio4\Core\Tools\GitStatusTool.cs -
AiStudio4\Core\Tools\PresentResultsAndAwaitUserInputTool.cs -
AiStudio4\Core\Tools\SecondAiOpinionTool.cs✅ (Already updated)
-
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPullRequestByIdTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPipelineRunsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetRepositoriesTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPipelineResourcesTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsSearchWikiTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPullRequestThreadsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPipelineDefinitionsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsQueryWorkItemsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetCommitDiffsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPullRequestsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetItemContentTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetCommitsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPullRequestIterationsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetWorkItemUpdatesTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsCreateOrUpdateWikiPageTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetWikiPagesTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetWikiPageContentTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetPullRequestChangesTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetWorkItemCommentsTool.cs -
AiStudio4\Core\Tools\AzureDevOps\AzureDevOpsGetWorkItemsTool.cs
-
AiStudio4\Core\Tools\Vite\StartViteDevServerTool.cs -
AiStudio4\Core\Tools\Vite\OpenBrowserTool.cs -
AiStudio4\Core\Tools\Vite\NpmRunScriptTool.cs -
AiStudio4\Core\Tools\Vite\NpmInstallTool.cs
-
AiStudio4\Core\Tools\GitHub\GitHubSearchRepositoriesTool.cs -
AiStudio4\Core\Tools\GitHub\GitHubGetRepositoryInfoTool.cs -
AiStudio4\Core\Tools\GitHub\GitHubSearchIssuesTool.cs -
AiStudio4\Core\Tools\GitHub\GitHubGetFileContentTool.cs -
AiStudio4\Core\Tools\GitHub\GitHubGetPullRequestsTool.cs -
AiStudio4\Core\Tools\GitHub\GitHubGetCommitsTool.cs -
AiStudio4\Core\Tools\GitHub\GitHubGetIssuesTool.cs
-
ProtectedMCPServer\Tools\WeatherTools.cs(GetAlerts, GetForecast) -
AiStudio4\Services\ProtectedMcpServer\WeatherTools.cs(GetAlerts, GetForecast)
Total Tools to Update: ~50+ tools across multiple categories
After making changes:
- Compilation Check: Ensure all modified files compile without errors
- Method Signature: Verify the method signature remains unchanged (only the body changes)
- Attribute Preservation: Ensure
[McpServerTool, Description(...)]attributes are preserved - Parameter Names: Ensure parameter names and descriptions are preserved
- Automatic Extra Properties: Tools automatically get the latest extra properties
- Reduced Boilerplate: From ~15 lines to 1 line per MCP method
- Consistent Error Handling: Centralized in the base class
- Maintainability: Single point of change for MCP execution logic
- Future Proof: New tools automatically benefit from the pattern
- Only change MCP tool methods: Don't modify the main
ProcessAsyncmethod - Preserve attributes: Keep all
[McpServerTool, Description(...)]attributes exactly as they are - Keep parameter names: Don't change parameter names or descriptions
- Test thoroughly: Verify tools still work with their configured extra properties
If a tool doesn't work after the change:
- Check that the tool inherits from
BaseToolImplementation - Verify the tool's
ProcessAsyncmethod handles extra properties correctly - Ensure the tool name in extra properties storage matches the expected format (first letter lowercase)
- Check that required extra properties are configured in the tool's settings
The ExecuteWithExtraProperties method:
- Calls
GetExtraProperties()to fetch the latest extra properties for the tool - Passes them to the tool's
ProcessAsyncmethod - Handles success/failure logic consistently
- Provides centralized error handling
- Returns the appropriate string response for MCP
This eliminates the need for manual service instantiation and provides a clean, consistent pattern for all MCP tools.