Merka2a Plugins for Microsoft Semantic Kernel
Expose Merka2a search, negotiate, and order as native Semantic Kernel functions so your .NET agent can transact with automatic function calling.
Semantic Kernel turns annotated methods into plugins the LLM can call automatically. There is no dedicated Merka2a SK package, but the REST API is small — a single C# plugin class with three [KernelFunction] methods gives your .NET agent full purchasing power, invoked automatically via FunctionChoiceBehavior.Auto().
What We're Building
A Merka2aPlugin with SearchProducts, Negotiate, and PlaceOrder kernel functions, registered with a Kernel and driven by automatic function calling.
Prerequisites
- .NET 8+
- A Merka2a API key (register here)
- An OpenAI (or Azure OpenAI) key
Installation
dotnet add package Microsoft.SemanticKernel
Step 1: The Plugin
Each method is annotated with [KernelFunction] and [Description]; SK uses these to build the tool schema. The methods call the REST API with Bearer auth.
using System.ComponentModel;
using System.Net.Http.Json;
using Microsoft.SemanticKernel;
public class Merka2aPlugin
{
private readonly HttpClient _http;
public Merka2aPlugin(string apiKey)
{
_http = new HttpClient { BaseAddress = new Uri("https://merka2a.com") };
_http.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", apiKey);
}
[KernelFunction, Description("Search the Merka2a marketplace. maxBudget is in minor units (5000 = £50.00).")]
public async Task<string> SearchProducts(
[Description("Free-text query")] string query = "",
[Description("Category, e.g. electronics.mice")] string category = "",
[Description("Max price in minor units")] int maxBudget = 0,
string currency = "GBP",
int limit = 10)
{
var intent = new Dictionary<string, object?>
{
["query"] = string.IsNullOrEmpty(query) ? null : query,
["category"] = string.IsNullOrEmpty(category) ? null : category,
};
if (maxBudget > 0)
intent["budget"] = new { max = new { amount = maxBudget, currency } };
var resp = await _http.PostAsJsonAsync("/v1/search-intent",
new { intent, pagination = new { limit } });
resp.EnsureSuccessStatusCode();
return await resp.Content.ReadAsStringAsync();
}
[KernelFunction, Description("Negotiate a price on an offer. targetPrice is in minor units.")]
public async Task<string> Negotiate(
string offerId, int targetPrice, string currency = "GBP", int volume = 1)
{
var resp = await _http.PostAsJsonAsync("/v1/negotiate", new
{
offerIds = new[] { offerId },
targetPrice = new { amount = targetPrice, currency },
volume,
});
resp.EnsureSuccessStatusCode();
return await resp.Content.ReadAsStringAsync();
}
[KernelFunction, Description("Place an order. Pass negotiationSessionId to lock a negotiated price.")]
public async Task<string> PlaceOrder(
string offerId,
int quantity = 1,
string negotiationSessionId = "",
string shippingCountry = "GB",
string shippingCity = "",
string shippingPostalCode = "",
string shippingMethod = "standard")
{
var body = new Dictionary<string, object?>
{
["offerId"] = offerId,
["quantity"] = quantity,
["shippingAddress"] = new
{
country = shippingCountry,
city = string.IsNullOrEmpty(shippingCity) ? null : shippingCity,
postalCode = string.IsNullOrEmpty(shippingPostalCode) ? null : shippingPostalCode,
},
["shippingMethod"] = shippingMethod,
};
if (!string.IsNullOrEmpty(negotiationSessionId))
body["negotiationSessionId"] = negotiationSessionId;
var resp = await _http.PostAsJsonAsync("/v1/create-order", body);
resp.EnsureSuccessStatusCode();
return await resp.Content.ReadAsStringAsync();
}
}
Step 2: Register the Plugin
using Microsoft.SemanticKernel;
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion("gpt-4-turbo", Environment.GetEnvironmentVariable("OPENAI_API_KEY")!);
var kernel = builder.Build();
kernel.Plugins.AddFromObject(
new Merka2aPlugin(Environment.GetEnvironmentVariable("MERKA2A_API_KEY")!),
"Merka2a");
Step 3: Automatic Function Calling
FunctionChoiceBehavior.Auto() lets the model call the plugin functions on its own across multiple turns.
using Microsoft.SemanticKernel.Connectors.OpenAI;
var settings = new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
};
var prompt = """
You are a procurement agent for the Merka2a marketplace.
Search, evaluate by price and specs, negotiate when worthwhile, then order.
Prices are in minor units. Each result has an offerId.
Task: Find a wireless mouse under £50, negotiate ~10% off, ship to London UK (EC1A 1BB).
""";
var result = await kernel.InvokePromptAsync(prompt, new(settings));
Console.WriteLine(result);
The kernel orchestrates the calls: SearchProducts → Negotiate → PlaceOrder, feeding each result back to the model until the order is placed.
Python Variant
Semantic Kernel for Python mirrors this with the @kernel_function decorator on an async class, registered via kernel.add_plugin(...) and the same automatic function-calling behavior — the REST calls are identical.
Next Steps
- OpenAI Integration Guide — function calling fundamentals
- Pydantic AI Integration Guide — typed Python agents
- API Reference — full endpoint documentation
Ready to add a marketplace plugin to your kernel? Get your API key →