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: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
workflow_dispatch:

env:
DOTNET_VERSION: '9.0.x'
DOTNET_VERSION: '10.0.x'
SOLUTION_FILE: 'DotNetDevMCP.sln'

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore DotNetDevMCP.sln
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
type: string

env:
DOTNET_VERSION: '9.0.x'
DOTNET_VERSION: '10.0.x'
SOLUTION_FILE: 'DotNetDevMCP.sln'

jobs:
Expand Down
44 changes: 43 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,43 @@
Nothing needs to be added to .gitignore since only a README.md file was modified and no build artifacts, dependencies, or temporary files were detected in the changes.
```
# Build artifacts
**/bin/
**/obj/
**/out/
*.dll
*.exe
*.pdb
*.so
*.dylib
*.nupkg

# Dependencies
packages/
**/node_modules/

# Logs
*.log

# Environment
.env
.env.local
*.env.*

# Editors
.vscode/
.idea/
*.swp
*.swo

# OS generated files
.DS_Store
Thumbs.db

# Test and coverage
coverage/
**/TestResults/
*.coverage

# Local config
**/appsettings.Development.json
**/appsettings.Local.json
```
9 changes: 9 additions & 0 deletions src/DotNetDevMCP.Analysis/DotNetDevMCP.Analysis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,13 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.12.6" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
<PackageReference Include="NuGet.ProjectModel" Version="6.12.0" />
<PackageReference Include="System.Text.Json" Version="10.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Extensions.DependencyInjection;
using DotNetDevMCP.Analysis.Services;

namespace DotNetDevMCP.Analysis.Extensions;

/// <summary>
/// Extension methods for registering Analysis services
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds Analysis services to the service collection
/// </summary>
public static IServiceCollection AddAnalysisServices(this IServiceCollection services)
{
services.AddSingleton<CodeAnalysisService>();
return services;
}
}
115 changes: 115 additions & 0 deletions src/DotNetDevMCP.Analysis/Mcp/Tools/AnalysisTools.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using ModelContextProtocol.Server;
using DotNetDevMCP.Analysis.Services;
using DotNetDevMCP.Analysis.Models;

namespace DotNetDevMCP.Analysis.Mcp.Tools;

/// <summary>
/// MCP tools for code analysis and metrics
/// </summary>
[McpServerToolType]
public sealed class AnalysisTools(
CodeAnalysisService analysisService,
ILogger<AnalysisTools> logger)
{
private readonly CodeAnalysisService _analysisService = analysisService;
private readonly ILogger<AnalysisTools> _logger = logger;

/// <summary>
/// Analyzes a .NET project or solution and returns comprehensive code metrics
/// </summary>
/// <param name="path">Path to the project file (.csproj), solution file (.sln), or directory</param>
/// <param name="includeMetrics">Include detailed code metrics (default: true)</param>
/// <param name="includeDependencies">Include dependency information (default: true)</param>
[McpServerTool(Name = "dotnet_analyze_project")]
public async Task<AnalysisResult> AnalyzeProjectAsync(
string path,
bool includeMetrics = true,
bool includeDependencies = true,
CancellationToken cancellationToken = default)
{
_logger.LogInformation("MCP: Analyzing project at {Path}", path);

if (!Directory.Exists(path) && !File.Exists(path))
{
throw new FileNotFoundException($"Path not found: {path}");
}

return await _analysisService.AnalyzeAsync(path, cancellationToken);
}

/// <summary>
/// Gets dependency information for a .NET project
/// </summary>
/// <param name="projectPath">Path to the project file (.csproj)</param>
[McpServerTool(Name = "dotnet_get_dependencies")]
public async Task<DependencyInfo> GetDependenciesAsync(
string projectPath,
CancellationToken cancellationToken = default)
{
_logger.LogInformation("MCP: Getting dependencies for {Path}", projectPath);

if (!File.Exists(projectPath))
{
throw new FileNotFoundException($"Project file not found: {projectPath}");
}

return await _analysisService.GetDependenciesAsync(projectPath, cancellationToken);
}

/// <summary>
/// Analyzes code quality and identifies potential issues
/// </summary>
/// <param name="path">Path to the project or directory to analyze</param>
[McpServerTool(Name = "dotnet_analyze_quality")]
public async Task<CodeQualityMetrics> AnalyzeQualityAsync(
string path,
CancellationToken cancellationToken = default)
{
_logger.LogInformation("MCP: Analyzing code quality at {Path}", path);

if (!Directory.Exists(path) && !File.Exists(path))
{
throw new FileNotFoundException($"Path not found: {path}");
}

return await _analysisService.AnalyzeQualityAsync(path, cancellationToken);
}

/// <summary>
/// Scans for outdated NuGet packages in a project
/// </summary>
/// <param name="projectPath">Path to the project file (.csproj)</param>
[McpServerTool(Name = "dotnet_scan_outdated_packages")]
public async Task<IReadOnlyList<PackageDependency>> ScanOutdatedPackagesAsync(
string projectPath,
CancellationToken cancellationToken = default)
{
_logger.LogInformation("MCP: Scanning for outdated packages in {Path}", projectPath);

var deps = await _analysisService.GetDependenciesAsync(projectPath, cancellationToken);

// In a real implementation, this would check NuGet.org for latest versions
// For now, return all direct dependencies as potentially outdated
return deps.PackageDependencies
.Where(d => d.IsDirect)
.ToList()
.AsReadOnly();
}

/// <summary>
/// Detects circular dependencies in a solution
/// </summary>
/// <param name="solutionPath">Path to the solution file (.sln)</param>
[McpServerTool(Name = "dotnet_detect_circular_dependencies")]
public async Task<bool> DetectCircularDependenciesAsync(
string solutionPath,
CancellationToken cancellationToken = default)
{
_logger.LogInformation("MCP: Detecting circular dependencies in {Path}", solutionPath);

// Simplified implementation - would need full graph analysis in production
var deps = await _analysisService.GetDependenciesAsync(solutionPath, cancellationToken);
return deps.HasCircularDependencies;
}
}
91 changes: 91 additions & 0 deletions src/DotNetDevMCP.Analysis/Models/AnalysisModels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
namespace DotNetDevMCP.Analysis.Models;

/// <summary>
/// Represents the result of a code analysis operation
/// </summary>
public sealed record AnalysisResult(
string ProjectPath,
int TotalFiles,
int TotalLines,
int CodeLines,
int CommentLines,
int BlankLines,
int Classes,
int Methods,
double MaintainabilityIndex,
double CyclomaticComplexity,
DateTime AnalyzedAt
);

/// <summary>
/// Represents code quality metrics for a project
/// </summary>
public sealed record CodeQualityMetrics(
string ProjectPath,
double TechnicalDebtHours,
int CodeSmells,
int Bugs,
int Vulnerabilities,
double Coverage,
double Duplication,
IReadOnlyList<CodeIssue> Issues,
DateTime AnalyzedAt
);

/// <summary>
/// Represents a single code issue
/// </summary>
public sealed record CodeIssue(
string RuleId,
string Message,
string Severity,
string FilePath,
int LineNumber,
int ColumnNumber,
string? Suggestion = null
);

/// <summary>
/// Represents dependency information for a project
/// </summary>
public sealed record DependencyInfo(
string ProjectPath,
IReadOnlyList<PackageDependency> PackageDependencies,
IReadOnlyList<ProjectReference> ProjectReferences,
IReadOnlyList<string> FrameworkReferences,
bool HasCircularDependencies,
DateTime AnalyzedAt
);

/// <summary>
/// Represents a NuGet package dependency
/// </summary>
public sealed record PackageDependency(
string Name,
string Version,
bool IsDirect,
bool IsDevelopmentDependency,
string? LicenseUrl = null,
bool? HasKnownVulnerabilities = null
);

/// <summary>
/// Represents a project reference
/// </summary>
public sealed record ProjectReference(
string Name,
string Path,
bool IsProjectReference
);

/// <summary>
/// Request model for code analysis
/// </summary>
public sealed record AnalysisRequest(
string Path,
bool IncludeMetrics = true,
bool IncludeDependencies = true,
bool IncludeIssues = true,
string? Configuration = null,
string? Platform = null
);
Loading
Loading