Functions in Semantic Kernel — Overview
⚡ Functions Overview
Semantic Kernel (SK) lets you compose an agent from different kinds of functions. A function is just a capability the Kernel can invoke — like “summarize text”, “get calendar events”, or “post to CRM”. Functions can be defined in code, by a prompt, from OpenAPI specs, or via the Microsoft Copilot Protocol (MCP). Plugins are just named collections of functions.
Function types at a glance
| Type | Description | Definition Source | Typical Use |
|---|---|---|---|
| 🔹 Native (Code) Function | A normal method in your host language (C#, Python, JS, etc.) exposed to SK. | Written directly in code. | Logic like calling an API, reading a file, or performing calculations. |
| 🔹 Prompt Function | A function defined by a text prompt template (can include system prompt + inputs). | Defined in .txt, .skprompt.txt, or inline string templates. | LLM-powered behaviors (“Summarize this email”, “Translate text”). |
| 🔹 OpenAPI Function | A function defined from an OpenAPI/Swagger specification. | Imported from a JSON/YAML OpenAPI file or URL. | Connect to REST APIs declaratively. |
| 🔹 MCP (Microsoft Copilot Protocol) Function | A function exposed via MCP to talk to Copilot plugins or MCP-enabled services. | Registered via the MCP interface/endpoint. | Connect external copilots or services (e.g., M365 Copilot, Fabric). |
| 🔹 Plugin | A named collection (folder) of functions (any type above). | Folder structure or declarative registration. | Group related functions (“CalendarPlugin”, “CRMPlugin”). |
Native (code) functions
Use native functions when you need determinism, local IO, or secure service access.
- Pros: Full control, testable, easy debugging, no model cost, strong typing, secure secrets handling.
- Cons: You must write the logic; less flexible than prompts for text reasoning.
C# example:
public class MathPlugin
{
[KernelFunction("add")]
public double Add(double x, double y) => x + y;
}
var builder = Kernel.CreateBuilder();
builder.Plugins.AddFromType<MathPlugin>();
var kernel = builder.Build();
DI lifetimes for native functions (.NET)
You’re referring to the three standard service lifetimes in .NET dependency injection (DI) — they define how long a service instance lives and when it’s created/disposed.
| Lifetime | Keyword | Description | Typical Use |
|---|---|---|---|
| 🟦 Singleton | AddSingleton<TService, TImplementation>() | Created once for the entire application lifetime (shared instance). | Shared configuration, logging, caching, HTTP clients. |
| 🟩 Scoped | AddScoped<TService, TImplementation>() | Created once per request (or per scope). | Web request–specific services, database contexts (e.g., EF Core DbContext). |
| 🟨 Transient | AddTransient<TService, TImplementation>() | Created every time it’s requested. | Lightweight, stateless services, formatters, calculators, etc. |
Example:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfigService, ConfigService>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddTransient<IEmailFormatter, EmailFormatter>();
}
IConfigService→ one instance for the entire app.IUserRepository→ new instance per HTTP request.IEmailFormatter→ new instance every time it’s injected.
Bonus tip (hosted services): when using BackgroundService, create a scope to resolve scoped services:
using (var scope = _serviceProvider.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<MyDbContext>();
// use db here
}
OBO (on‑behalf‑of) auth flow tip
- Keep
HttpClientcreation viaIHttpClientFactory(registered as singleton factory) and inject typed clients into functions. - Use a scoped token acquisition service (e.g.,
ITokenAcquisitionfrom Microsoft.Identity.Web) so each request/user gets the right access token. - Never capture a scoped service in a singleton; inject abstractions where needed and create scopes when running outside HTTP pipelines.
Prompt functions
Prompt functions are text templates executed by an LLM.
- Pros: Fast to prototype, flexible, great for summarization, extraction, translation.
- Cons: Non‑deterministic, requires model access, prompt/guardrail engineering, higher latency/cost.
Example:
const string prompt = """
Summarize the following text in one sentence:
{{$input}}
""";
var summarize = kernel.CreateFunctionFromPrompt(prompt, "summarize");
var result = await kernel.InvokeAsync(summarize, new() { ["input"] = text });
OpenAPI functions
Import REST APIs as callable functions.
- Pros: Declarative, discoverable, encourages least‑privilege API usage, consistent shapes.
- Cons: Spec quality matters; some APIs need auth wiring; advanced flows may still need native code.
var weather = await kernel.ImportPluginFromOpenApiAsync(
"weather",
new Uri("https://api.weatherapi.com/v1/openapi.json")
);
var forecast = await kernel.InvokeAsync(weather["getForecast"], new() { ["location"] = "Vienna" });
OpenAPI vs. Native — when to choose what?
- Choose OpenAPI if:
- The API has a solid OpenAPI spec you trust.
- You want declarative, low‑code connect‑and‑call.
- Governance requires explicit API contracts.
- Choose Native if:
- You need custom auth flows (e.g., complex OBO, mTLS), retries, or circuit breakers.
- Business rules or transformations are complex.
- You need full testability and rich telemetry.
MCP (Microsoft Copilot Protocol) functions
Connect SK to Copilot plugins or MCP‑enabled services (e.g., Microsoft 365 Copilot, Fabric).
- Pros: Standardized capability discovery and invocation; enterprise‑grade connectors.
- Cons: Requires MCP endpoints and proper app registration/permissions.
var builder = Kernel.CreateBuilder();
// Example shape — actual registration depends on SDK updates
builder.AddMcpServer("fabric", new Uri("https://fabric.microsoft.com/mcp"));
var kernel = builder.Build();
Plugins (function collections)
A plugin is a named group of functions (any mix of types) plus metadata.
- Pros: Organization, reuse, permissions scoping, easy enable/disable.
- Cons: Keep boundaries clear; over‑large plugins become hard to reason about.
Typical folder:
/Plugins
└── CalendarPlugin
├── GetEvents.skprompt.txt
├── CreateEvent.skprompt.txt
└── manifest.json
Register:
kernel.Plugins.AddFromPromptDirectory("Plugins/CalendarPlugin");