Two small packages, each referencing the core package and the one Microsoft package it adapts.
RecursiveAI.OneModelContext.Hosting
References Microsoft.Extensions.Hosting.Abstractions only. The abstractions are enough: the hosted services derive from
BackgroundService, tool classes are created with ActivatorUtilities, and the logging bridge uses LoggerMessage. The generic host itself
(Microsoft.Extensions.Hosting) is the app's choice.
builder.Services.AddSingleton<SearchIndex>(); builder.Services.AddContextServer<IndexTools>().UseStdio(); // or .UseListener(port: 3001), or .UseTransport(sp => ...)
- Tool classes (
AddTools<T>()) are generated partial classes. The container supplies the constructor arguments, or the class's own registration is used when it has one. There is one instance for the life of the server, so a constructor takes singletons.AddTools(factory)creates the class without reflection.Configure((server, services) => ...)is for dynamic registration. - Scoped services are not constructor parameters. Every tool, resource and prompt call runs in its own DI scope, and the handler reaches it
with
context.GetRequiredService<T>()(orGetRequestServices()); the scope is disposed when the call ends. The scope travels as an ambient value through the call's async flow, because generated invokers hold their class instance. On the modern era a handler that asks for input is re-run from the start on retry (seemulti-round-trip.md), so it gets a new scope each attempt. - Lifetimes.
UseStdioandUseTransportserve one connection and ask the host to stop when it closes (stdin closed).UseListenerruns the built-in HTTP listener on loopback with its default limits;ContextListener.Startedcompletes with the bound address. Both stop with the host. Standard output carries the protocol in a stdio host, so send the console logger to standard error. - Logging. Diagnostics events become
ILoggerentries in the categoryRecursiveAI.OneModelContext. Only the event text and an exception's type and message are logged (never the exception object or a stack), after bearer tokens, JWTs and token-like parameters (access_token=,code=, ...) are replaced by[redacted]. - Clients.
AddContextClient(...)registers aContextClientProvider;await provider.GetClientAsync()connects on first use (the era is negotiated as usual) and reconnects after a closed connection. - Clock. A
TimeProviderregistered in the container becomes the server's and client's clock.
RecursiveAI.OneModelContext.Extensions.AI
References Microsoft.Extensions.AI.Abstractions only.
client.ToAIFunctionsAsync()lists the server's tools asAIFunctions with the tool's name, description and input schema. The result of an invocation is the structured content when there is some, the text when every block is text, otherwise a list ofAIContent(text,DataContentfor images, audio and blobs,UriContentfor resource links). A tool failure comes back as text starting with "Error: " so the model can react.server.AddAIFunction(f)/AddAIFunctions(tools)serve functions as tools. The function's arguments areJsonElements. An exception in the function is a tool failure with the fixed text "The tool failed.".ChatClientSampling.CreateHandler(chatClient)answerssampling/createMessageforContextClientOptions.OnSample. Sampling is deprecated in 2026-07-28 (OMC0002); the adapter suppresses the warning in its own implementation and your use ofOnSampleraises it at your call site. The server'stoolsandtoolChoiceare not forwarded.- AOT: the adapter is trim- and AOT-annotated. Arguments from code (not from a model) are serialized with the function's
JsonSerializerOptions, so types outside MEAI's defaults need a source-generated context on that function.
Model Context Protocol® is a registered trademark of LF Projects, LLC. OneModelContext is an independent project and is not affiliated with or endorsed by LF Projects, LLC or the Model Context Protocol project.