fai-mcp-csharp-generator — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited fai-mcp-csharp-generator (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Scaffold a production-ready C#/.NET MCP server.
{SERVER_NAME}/
├── {SERVER_NAME}.csproj # NuGet refs: ModelContextProtocol, Azure.Identity
├── Program.cs # Host builder with MCP server setup
├── Tools/
│ └── ExampleTools.cs # [McpServerTool] sample implementations
├── Services/
│ └── IExampleService.cs # DI interface pattern
├── Dockerfile
├── README.md
└── appsettings.json # Non-secret configuration// Program.cs
var builder = Host.CreateApplicationBuilder(args);
builder.Services
.AddMcpServer()
.WithStdioTransport()
.WithTools<ExampleTools>();
builder.Services.AddSingleton<IExampleService, ExampleService>();
var host = builder.Build();
await host.RunAsync();dotnet build compiles without errorsdotnet run starts MCP server on stdio[McpServerTool, Description("Search FAI solution plays by keyword")]
public static async Task<string> SearchPlays(
[Description("Search query")] string query,
[Description("Max results (1-20)")] int maxResults = 5,
IPlaySearchService searchService = null!)
{
ArgumentException.ThrowIfNullOrWhiteSpace(query);
maxResults = Math.Clamp(maxResults, 1, 20);
var results = await searchService.SearchAsync(query, maxResults);
return JsonSerializer.Serialize(results, new JsonSerializerOptions
{ WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
}builder.Configuration.AddAzureKeyVault(
new Uri("https://my-vault.vault.azure.net/"),
new DefaultAzureCredential());builder.Services.AddSingleton(_ => new AzureOpenAIClient(
new Uri(config["AzureOpenAI:Endpoint"]!),
new DefaultAzureCredential()));builder.Services.AddSingleton(_ => new SearchClient(
new Uri(config["Search:Endpoint"]!),
config["Search:IndexName"],
new DefaultAzureCredential()));[Fact]
public async Task SearchPlays_ReturnsResults()
{
var mockService = new Mock<IPlaySearchService>();
mockService.Setup(s => s.SearchAsync("rag", 5))
.ReturnsAsync(new[] { new PlayResult("01", "Enterprise RAG") });
var result = await ExampleTools.SearchPlays("rag", 5, mockService.Object);
Assert.Contains("Enterprise RAG", result);
}| Package | Version | Purpose |
|---|---|---|
| ModelContextProtocol | 0.1.0-preview | MCP server SDK |
| Azure.Identity | 1.13.x | Managed Identity auth |
| Microsoft.Extensions.Hosting | 9.0.x | Host builder pattern |
| Azure.AI.OpenAI | 2.1.x | Azure OpenAI client |
| Azure.Search.Documents | 11.7.x | AI Search client |
{
"McpServer": { "Name": "my-fai-mcp", "Version": "1.0.0", "Transport": "stdio" },
"AzureOpenAI": { "Endpoint": "https://my-oai.openai.azure.com/", "DeploymentName": "gpt-4o" },
"Search": { "Endpoint": "https://my-search.search.windows.net", "IndexName": "fai-knowledge" }
}~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.