Direct answer

Semantic Kernel Agent Receipts

Add verifiable receipts to Semantic Kernel function calls and every plugin function your kernel invokes leaves a record anyone can check. Two routes work: import the Zambo MCP at https://zambo.dev/mcp as a plugin source and route the calls that matter through it, or register a function invocation filter on the kernel, the hook Semantic Kernel runs every time a KernelFunction is invoked, and forward each invocation through the Zambo MCP from inside the filter. Close the run with one workflow receipt. Capture happens when the function runs, outside the agent's control, so a claim with no receipt behind it is visible as a gap instead of being smoothed over by a summary.

See the artifact first: the live demo runs one real call and hands you its verifiable receipt in about 10 seconds, no signup. That receipt is the same object your kernel function calls will publish.

Updated November 10, 2026.

Install: two routes to receipts

Semantic Kernel is Microsoft's multi-language SDK, with distributions for .NET, Python, and Java: dotnet add package Microsoft.SemanticKernel, pip install semantic-kernel, or the Java artifacts under com.microsoft.semantic-kernel. Its shape is the same in each language: a Kernel holds the AI services and the plugin collection, a plugin is a group of functions exposed to the model, and a native function is a method marked as callable, with the KernelFunction attribute in C#, the kernel_function decorator in Python, or DefineKernelFunction in Java. There is no Semantic Kernel specific Zambo package and none is needed, because both routes below use extension points the SDK already ships.

Route 1, the MCP plugin. Semantic Kernel imports plugins three ways: from native code, from an OpenAPI specification, or from an MCP server. Import the Zambo MCP at https://zambo.dev/mcp as an MCP server plugin source, and the functions it exposes join the kernel's plugin collection next to your native plugins. Calls the model makes to those functions run through the Zambo endpoint, and each one comes back with a verifiable receipt at a public https://zambo.dev/run/{id} URL. Agents built on the Semantic Kernel Agent Framework, such as the ChatCompletionAgent, take their plugins through their Kernel instance, so wiring the kernel wires the agent.

Route 2, the filter. For your own native plugin functions, the capture point is the function invocation filter. Microsoft's filter documentation is explicit about what it does: the filter is executed each time a KernelFunction is invoked, its context carries the function being executed and its arguments, calling the next delegate runs the function itself, and after that call the result sits in the context where the filter can read it. Register the filter, let it pass every invocation through, and send the function name, arguments, and result through your Zambo MCP session before returning. In Python the registration is one call:

from semantic_kernel.filters import FilterTypes, FunctionInvocationContext

async def receipt_filter(context: FunctionInvocationContext, next) -> None:
    await next(context)
    # context.function names the plugin and the function.
    # context.result holds what the function returned.
    # Send both through your Zambo MCP session here and keep
    # the https://zambo.dev/run/ URL the call returns.

kernel.add_filter(FilterTypes.FUNCTION_INVOCATION, receipt_filter)

In .NET the same hook is a class implementing IFunctionInvocationFilter with an OnFunctionInvocationAsync method that takes the context and the next delegate, registered either as a service on the kernel builder or by adding it to the kernel's FunctionInvocationFilters collection. The filter sees prompt functions and method functions alike, because it triggers on invocation, not on how the function was defined.

Wire the kernel's functions through Zambo

The Zambo MCP at zambo.dev/mcp carries 153 tools total, 37 on the default surface, and every call through it returns its result plus a verifiable receipt, captured server side at execution. The record is made by the layer that ran the call, so the agent never gets to edit its own history. The pattern is the one described in MCP server receipts: per-call receipts answer what each function did, in the order it did it.

Whichever route you take, two properties do the work. Capture happens when the function is invoked, not when somebody later exports a log or a chat history. And the receipt states its own limit plainly: it describes what the endpoint recorded and observed, and it does not claim an outside outcome the endpoint did not observe.

Make the first call a search, under your label

A demo tour is not an onboarding. The pattern that turns a first session into a second day is a first call that searches the catalog for the job the kernel actually has, carrying one pinned identity. Every Zambo tool accepts a caller label and a session id as call arguments; usage is counted under that label, and limits and any pass attach to it. Labeled calls go over a raw MCP session, like this:

result = await session.call_tool("capability_search", {
    "q": "the job you need done, in your own words",
    "_caller_label": "your-fleet-or-project-name",
    "_session_id": "your-stable-session-name",
})

In a Semantic Kernel app that search can ride in as one of the functions imported from the MCP server, so the first recorded step in the run is the search that found the tools for the job, under the same label the rest of the run will use. Follow it with one worked call, then a memory and a continuity thread planted under the label, and a second session can read both back before doing new work.

Check the receipts

Every receipt lives at a public URL anyone can open, and checking one is free at zambo.dev/verify with no signup: paste the receipt link or ID and the verifier recomputes the commitment from the saved bytes and compares it with the commitment fixed when the function ran. A match means the saved record is the record made at execution. A mismatch means the record was changed after the fact, and the page says so plainly.

That gives the kernel owner an acceptance check with teeth, the Walk-Away Test: set the agent a countable multi-step job, walk away, and on return read the record before the summary. Claimed steps versus recorded steps is the whole audit. A function an agent claims but never invoked has no receipt to point to.

Close the run with one workflow receipt

When the run finishes, call workflow_close. The step receipts from the run bind into a single summary receipt whose children list names every step receipt and whose root digest is computed over them, so the whole job verifies as one record: a step added, dropped, or swapped after the fact breaks the root. Per-call receipts answer what this function did; the closed record answers what the kernel did, in full, and it is the link you hand a client or auditor. Need the job continued in a different AI instead? Hand the closed record over with handover and the next AI picks the job up from the same record; picking up a job in another AI is always free.

Cost stays small either way. The free tier gives you 20 calls plus 1 wrap-up free every day. A Day Pass is $0.99 one time and covers unlimited calls for 24 hours. The Zambo Pass is $29 for 30 days, one payment, and $19 for 30 days for $ZAMBO holders. A Lifetime Pass is $250, one payment for good. Humans pay by card or PayPal; agents pay USDC on Base via x402. Checking stays free for anyone you hand a receipt to.

Honest limits

A receipt proves the saved result was not changed since it was saved. It does not prove the function's output was correct, the plan was good, or an outside outcome happened that the endpoint did not observe. It settles what ran, what it was given, and what came back, in a form the kernel owner does not have to take on trust. Judge the work itself against that record.

Frequently asked questions

How do I add execution receipts to a Semantic Kernel app?

Two routes, and neither needs a Semantic Kernel specific Zambo package, because none exists. Route one: import the Zambo MCP at https://zambo.dev/mcp as a plugin source, since Semantic Kernel imports plugins three ways, from native code, from an OpenAPI specification, or from an MCP server, and route the calls that matter through it; every call returns a verifiable receipt at a public https://zambo.dev/run/ URL. Route two: register a function invocation filter on the kernel, the filter Semantic Kernel runs every time a KernelFunction is invoked, and forward each invocation and its result through the Zambo MCP from inside the filter. Either way, call workflow_close at the end of the run so the step receipts bind into one chained record.

Can I verify what each function or agent in my kernel did?

Yes, function by function. Every call routed through the Zambo MCP becomes its own receipt: the plugin and function name, the arguments it was given, and the output the endpoint recorded and observed, committed under a SHA-256 hash at the moment the call ran and published at a URL anyone can fetch. Recompute the commitment from the receipt's canonical bytes; a match means the saved record is the record made when the function ran. An agent that claims a function it never invoked has no receipt to point to, and that absence is visible in the run's record instead of hidden in a summary.

Do Semantic Kernel function outputs come with proof?

Not by default. Semantic Kernel gives you the outputs its functions produce, the chat history, and its own logs, and all of them are records the application itself controls: an output can be retold, trimmed, or regenerated later and nothing in the framework marks the change. Proof appears when the output is captured at execution time by a layer outside the agent's control and committed under a hash: the output bytes saved as recorded, a digest over them, and a public URL where anyone can fetch the record and recompute the digest. That is the record a call through the Zambo MCP adds. It proves the saved output is the output that was recorded when the function ran; whether the output was any good remains a judgment the receipt does not make for you.

What does a Semantic Kernel run receipt contain?

One receipt per routed invocation, in the AER-1 format: the plugin and function name, the arguments the function was given, the output the endpoint recorded and observed, a timestamp, and the SHA-256 commitments (the canonical bytes and the output hash) that make the record checkable by recompute. Closing the run with workflow_close binds the step receipts into one summary receipt whose children list names every step receipt and whose root digest is computed over them. AER-1 is an open IETF Internet-Draft (draft -26), so the format is public text, not a vendor schema.

What does it cost to receipt a Semantic Kernel run?

The free tier gives you 20 calls plus 1 wrap-up free every day, and picking up a job in another AI is always free, so you can wire the kernel and see real receipts before paying anything. A Day Pass is $0.99 one time and covers unlimited calls for 24 hours. Ongoing use is the Zambo Pass at $29 for 30 days, one payment, and $19 for 30 days for $ZAMBO holders. A Lifetime Pass is $250, one payment for good. Checking a receipt is always free at https://zambo.dev/verify/ with no signup, so clients and auditors never need a plan to check your kernel's work.

Run it on a record instead

Reading about the record is one thing; having it under your own work is the point. Work run through the Zambo MCP endpoint at zambo.dev/mcp saves its result at execution and returns a verifiable AER-1 receipt for every call. The Day Pass is $0.99 for 24 hours of the full endpoint, the Pass is $29 for 30 days, one payment, and checking any receipt is always free at zambo.dev/verify.

Related

Proof works best when it travels with the work itself. The AER-1 badge kit turns verifiable receipts into an embeddable badge for project pages, docs, and profiles, so anyone who sees the claim can reach the check in one click.