5-minute quickstart

Add the App Use SDK to a .NET app, implement IAppUseSurface, and call AppUseHost.StartAsync at startup. From there, any MCP-capable agent on the same machine finds your app through apps.list — no bespoke per-app integration required.

Step 1 — packages

Reference the abstractions (the contracts you implement) and the SDK (the wire side that hosts your surface):

<PackageReference Include="AiAppUse.Abstractions" Version="0.8.0" />
<PackageReference Include="AiAppUse.Sdk" Version="0.8.0" />

Step 2 — implement the surface

IAppUseSurface is a handful of methods. Most are one-liners that delegate to your app's existing state — describe your screens and elements, then answer reads, value gets/sets, and invokes:

public sealed class HelloSurface : IAppUseSurface
{
    private string _message = "";

    public Task<AppSpec> DescribeAsync(CancellationToken ct = default) => Task.FromResult(AppSpec.Build(
        appName: "Hello", appVersion: "1.0",
        screens: new[] { new AppScreen("home", "Home", "Main page.") },
        elements: new[]
        {
            new AppElement("home.message", "home", "TextBox", "Message text.",
                Array.Empty<string>(), null, new[] { "set_value", "get_value", "focus" }),
            new AppElement("home.send", "home", "Button", "Send the message.",
                Array.Empty<string>(), null, new[] { "invoke" }),
        }));

    public Task<ScreenSnapshot> ReadScreenAsync(CancellationToken ct = default) =>
        Task.FromResult(new ScreenSnapshot("home", new ElementState[]
        {
            new("home.message", "TextBox", _message, true, true),
        }, Array.Empty<string>()));

    public Task<AppUseResult> GetValueAsync(string k, CancellationToken ct = default)
        => Task.FromResult(k == "home.message" ? AppUseResult.Success(_message) : AppUseResult.Failure("unknown_key"));

    public Task<AppUseResult> SetValueAsync(string k, string? v, CancellationToken ct = default)
        { if (k == "home.message") _message = v ?? ""; return Task.FromResult(AppUseResult.Success("ok")); }

    public Task<AppUseResult> InvokeAsync(string k, CancellationToken ct = default)
        { if (k == "home.send") Console.WriteLine($"sending: {_message}"); return Task.FromResult(AppUseResult.Success("ok")); }

    // remaining methods (navigation, window, key/link, capture) return
    // AppUseResult.Success("ok") or NotSupported as appropriate
}

Step 3 — host it

Call AppUseHost.StartAsync once at startup, passing your app identity and the surface instance:

await using var host = await AppUseHost.StartAsync(new AppUseHostOptions
{
    AppId      = "hello",
    AppName    = "Hello",
    AppVersion = "1.0",
    Surface    = new HelloSurface(),
});
Console.WriteLine($"App-Use endpoint: {host.Endpoint.Current!.Url}");
// ... your main loop ...

Step 4 — verify

StartAsync writes an instance-registration file at <AIAPPUSE_HOME>/instances/<id>.json containing the endpoint URL, bearer token, pid, and launch manifest. The hub watches that directory and now sees your app — so apps.list from any connected agent returns it:

$ ls $HOME/.aiappuse/instances/
8c2f...e1.json
$ curl -s -H "Authorization: Bearer <admin-bearer>" \
       http://127.0.0.1:8766/instances | jq .[0].appName
"Hello"