AppFunctions Tutorial: Building Android MCP Integrations
Android's transition into an App Intelligence Platform changes what it means to build a "feature." With AppFunctions — Android's equivalent of the Model Context Protocol (MCP) — your app's capabilities become tools that system AI agents like Gemini can discover and invoke on the user's behalf. When a user says "find my package confirmation and add a reminder to my tracker," the OS orchestrates that across apps — but only across apps that have exposed their capabilities properly.
This tutorial walks through building your first AppFunctions integration end to end: project setup, writing and annotating functions, service registration, security, and testing from the ADB shell — with the practical details that determine whether the system agent actually understands your tools. For the strategic overview of the platform shift, see our companion article: Gemini Nano 4 on Android: What Developers Need to Know.
What You Are Building — The Mental Model
An AppFunctions integration has three parts:
- Functions — Kotlin suspend functions exposing discrete capabilities (create a task, search orders, send a message), annotated so the compiler generates tool metadata
- A service — the discoverable endpoint the Android system binds to when an agent wants to invoke your functions
- Metadata — descriptions compiled from your KDoc comments that tell the system LLM when and how to call each function
Prerequisites and Project Setup
Requirements:
- API level 36+ (Android 16 preview) as your target
- Kotlin Symbol Processing (KSP) toolchain — the AppFunctions compiler generates inventory and routing code at build time
build.gradle.kts:
The library is alpha — expect API evolution between releases and pin versions deliberately.
Writing Your First AppFunction
Functions are standard Kotlin suspend functions inside a class, annotated with @AppFunction. Parameters and return types must be primitives or data classes annotated with @AppFunctionSerializable.
The details that matter:
isDescribedByKDoc = true instructs the KSP compiler to compile your KDoc — the function description and parameter documentation — directly into the tool metadata. The system LLM reads exactly this text when deciding whether your function matches the user's intent. This makes KDoc quality a functional requirement, not documentation hygiene.
Writing agent-ready descriptions. Apply prompt-engineering discipline:
- State what the function does and when to use it — including phrasings users might employ
- Describe each parameter's format explicitly ("ISO-8601 date-time string"), since the agent must construct valid arguments
- Keep one function to one capability — agents select better among several narrow tools than one broad one
AppFunctionContext is the system-supplied first parameter carrying invocation context. Your remaining parameters define the tool's schema — keep them primitive-typed or simple serialisable data classes; optional parameters with sensible defaults make your tool callable from sparser user requests.
Return structured results. Agents chain function calls — the output of createTask may feed the next step in a multi-app workflow. Return meaningful structured data (IDs, statuses), not booleans.
Registering the Service
Capabilities become discoverable through an AppFunctionService implementation. The KSP compiler generates the inventory class that routes invocations to your annotated functions — you wire the service into the manifest:
android:permission="android.permission.BIND_APP_FUNCTION_SERVICE" restricts binding to the core Android operating system. Omitting it exposes your functions to invocation by arbitrary third-party apps — turning your convenient tool surface into an attack surface. Treat this as a mandatory checklist item in code review.
Defence-in-depth still applies inside each function: validate parameters as untrusted input, enforce your app's own authorisation state (a deleteAccount function should verify a signed-in, confirmed user regardless of who is calling), and return errors as structured results rather than exceptions where possible.
Testing from the ADB Shell
You do not need to wait for a full system-agent integration to validate your work. Android 16 platform tools include direct debugging entry points:
A practical testing sequence:
- List — confirm your functions registered and inspect the compiled metadata; if a function is missing, the KSP step or manifest wiring is the usual culprit
- Invoke happy paths — verify parameter deserialisation and results
- Invoke hostile inputs — missing optionals, malformed dates, oversized strings; your functions should fail gracefully with structured errors
- Verify side effects — confirm database writes and app state changes behave identically to the same action taken through your UI
Design Guidelines for a Production Tool Surface
Expose verbs, not screens. Audit your app for core user outcomes — search, create, send, book, list — and expose those. Do not mirror your navigation graph; agents compose capabilities, they do not click through flows. Mind the destructive operations. Deletion, payments, and sends deserve explicit confirmation semantics — return a pending state the agent must confirm, or require parameters that make intent unambiguous. Assume the agent occasionally misreads intent, because it will. Version thoughtfully. Once agents rely on your functions, changed parameter schemas break workflows silently. Prefer additive evolution — new optional parameters, new functions — over signature changes. Log invocations. Instrument agent-initiated calls separately from UI-initiated ones. This tells you which capabilities agents actually use, feeds debugging when orchestration misbehaves, and quantifies the channel's business value.Where This Fits Strategically
AppFunctions is discoverability infrastructure. As assistant-driven workflows grow, apps that expose clean tool surfaces get invoked inside agent workflows; apps that do not become invisible to that interaction layer entirely. The engineering cost of a first integration is modest — a few well-chosen functions, careful descriptions, correct security wiring — and it positions your app for an interaction model that is arriving quickly.
If your team wants help designing an agent-ready capability surface — choosing which functions to expose, writing metadata that agents reliably understand, and integrating with the broader on-device AI stack — NetConsulate builds Android AI integrations end to end, from AppFunctions to Gemini Nano 4 features and hybrid inference architectures.
Ready to make your Android app agent-ready? Submit a proposal request and our team will respond with an integration roadmap within 2 business days.