.NET SDK
Purpose
The .NET SDK provides a IAiApiMapperClient abstraction and orchestrator adapters for Microsoft.Extensions.AI, Semantic Kernel, and Azure AI Foundry Agents.
Main Capabilities
- Singleton client registered via
IServiceCollection - Automatic MCP session management and tool pagination
- System prompt and tool list fetching (opt-in in-memory cache via
CacheTools/CacheSystemPrompt) - Three authentication modes: API key, OAuth2 client credentials, delegated bearer
- Structured logging via
ILogger<ApiMapperClient> - Resilience pipeline via
Microsoft.Extensions.Http.Resilience - Adapters for Microsoft.Extensions.AI, Semantic Kernel 1.73, Azure AI Foundry Agents
Packages
| Package | Description |
|---|---|
CodedProjects.AI.ApiMapper.Client |
Core client |
CodedProjects.AI.ApiMapper.Client.MicrosoftExtensionsAI |
ME.AI AIFunction adapter |
CodedProjects.AI.ApiMapper.Client.SemanticKernel |
SK KernelPlugin adapter |
CodedProjects.AI.ApiMapper.Client.AzureAIFoundry |
Azure AI Foundry toolset and run loop |
Registration
Register the client in Program.cs or Startup.cs. It is registered as a singleton.
builder.Services
.AddApiMapperClient(opts =>
{
opts.BaseUrl = configuration["ApiMapper:BaseUrl"];
opts.TenantId = Guid.Parse(configuration["ApiMapper:TenantId"]);
opts.ClientId = "my-app";
opts.SystemPromptResourceUri = "apimapper://toolsets/system-prompt";
})
.WithApiKey(configuration["ApiMapper:ApiKey"]);
See SDK Authentication for OAuth2 and delegated bearer options.
Raw Tool Loop (01-raw-mcp-client)
Fetch the system prompt, load tools, and drive a manual OpenAI tool-call loop.
var systemPrompt = await client.GetSystemPromptAsync();
var tools = await client.GetToolsAsync();
var chatTools = tools.Select(t => ChatTool.CreateFunctionTool(
t.Name, t.Description, BinaryData.FromObjectAsJson(t.InputSchema))).ToList();
var messages = new List<ChatMessage>
{
new SystemChatMessage(systemPrompt ?? "You are a helpful assistant."),
new UserChatMessage(userMessage)
};
while (true)
{
var response = await openai.CompleteChatAsync(messages,
new ChatCompletionOptions { Tools = { chatTools } });
if (response.Value.FinishReason == ChatFinishReason.ToolCalls)
{
messages.Add(new AssistantChatMessage(response.Value));
foreach (var call in response.Value.ToolCalls)
{
var args = JsonSerializer.Deserialize<Dictionary<string, object>>(call.FunctionArguments.ToString());
var result = await client.InvokeToolAsync(call.FunctionName, args);
messages.Add(new ToolChatMessage(call.Id, result?.ToText() ?? ""));
}
continue;
}
Console.WriteLine(response.Value.Content[0].Text);
break;
}
Microsoft.Extensions.AI (02-microsoft-extensions-ai)
ApiMapperAIFunctionFactory.CreateFunctionsAsync converts tools to AIFunction instances. Pass them to any IChatClient.
var systemPrompt = await client.GetSystemPromptAsync();
var functions = await ApiMapperAIFunctionFactory.CreateFunctionsAsync(client);
var messages = new List<ChatMessage>
{
new(ChatRole.System, systemPrompt ?? "You are a helpful assistant."),
new(ChatRole.User, userMessage)
};
var options = new ChatOptions { Tools = [..functions] };
ChatResponse response;
do
{
response = await chatClient.GetResponseAsync(messages, options);
messages.AddRange(response.Messages);
}
while (response.FinishReason == ChatFinishReason.ToolCalls);
Console.WriteLine(response.Text);
Semantic Kernel (03-semantic-kernel)
AddApiMapperPluginAsync registers all Runtime tools as a named KernelPlugin with automatic function calling.
await kernel.AddApiMapperPluginAsync(client, "RuntimeTools");
var systemPrompt = await client.GetSystemPromptAsync()
?? "You are a helpful assistant.";
var settings = new OpenAIPromptExecutionSettings
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
var result = await kernel.InvokePromptAsync(
$"<system>{systemPrompt}</system>\n\n{userMessage}",
new KernelArguments(settings));
Console.WriteLine(result);
Azure AI Foundry Agents (04-azure-ai-foundry)
ApiMapperFoundryToolset converts tools to Azure AI Agents FunctionToolDefinition instances. AgentRunLoop.RunAsync drives the submit → poll → tool call loop.
var systemPrompt = await client.GetSystemPromptAsync()
?? "You are a helpful assistant.";
var toolset = await ApiMapperFoundryToolset.CreateAsync(client);
var agent = await agentsClient.Administration.CreateAgentAsync(
model: modelDeployment,
instructions: systemPrompt,
tools: toolset.Definitions);
var thread = await agentsClient.Threads.CreateThreadAsync();
var answer = await AgentRunLoop.RunAsync(agentsClient, agent.Value, thread.Value, toolset, userMessage);
Console.WriteLine(answer);
Logging
The client uses ILogger<ApiMapperClient>. Configure your preferred sink in appsettings.json. Auth headers and secrets are never written to logs.
{
"Logging": {
"LogLevel": {
"CodedProjects.AI.ApiMapper.Client": "Information"
}
}
}
Set to Debug to see MCP handshakes, per-tool invocation messages, and cache hits (when caching is explicitly enabled).
