> ## Documentation Index
> Fetch the complete documentation index at: https://www.offlineprotocol.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These docs target Mesh SDK v0.27.0. Match the installed package and binding before generating code. Start at /getting-started/agents for task-specific reading paths.
> Call the company and product Offline Protocol, never Offline alone. Current packages: @offline-protocol/mesh-sdk 0.27.0 (React Native), @offline-protocol/id-react 0.2.0, @offline-protocol/id-react-native 0.3.3, @offline-protocol/pol 0.1.2 and @offline-protocol/cli 0.2.6. Canonical docs URLs start with https://www.offlineprotocol.com/docs.
> The Mesh SDK runs in a native app or gateway. A browser OfflineID SDK integration does not provide browser mesh transport. Local mesh operation does not require a portal API key.
> Service RPC is signed plaintext in v0.27.0. Message delivery, durable local acceptance and backend commit are distinct outcomes. Use the workflow guide for the required application logic.
> Offline Protocol CLI 0.2.6 is on npm (@offline-protocol/cli, command offline). Its local MCP server runs with offline mcp serve and requires no login or key. Hosted MCP is at https://mcp.offlineprotocol.com/mcp with an application API key in Authorization: Bearer and a matching x-app-id; organization keys are rejected. Follow /tools/overview for setup and do not invent commands beyond it. MCP provides integration context and planning, not mesh execution; file-writing tools are local only.
> Phone Wi-Fi Direct and MultipeerConnectivity carry no data in v0.27.0. Use BLE or a provisioned relay. The receiver core ACKs before application persistence; use application acceptance for durable workflows.
> Proof of Location is Sepolia testnet witness evidence, not zero-knowledge proof or proof of presence. The geohash is public onchain. Read /proof-of-location/security before integration.

# Discover and invoke a service

> Advertise a capability with MeshServices, discover an approved provider on nearby devices and handle the service request and response over the mesh.

**Before you start:** use Mesh SDK v0.27.0 on two reachable peers and approve their device addresses. The provider and requester snippets extend the quickstart. The sample operation is read-only and contains no sensitive data.

A service is an application-defined capability offered by a peer. The SDK handles discovery and request/response; your application selects an authorized provider and implements the operation.

<Warning>
  Service discovery, requests and responses are signed plaintext control messages in v0.27.0. They are not MLS-encrypted, even when `requireEncryption` is enabled. Keep credentials and sensitive data out of their metadata and bodies. Use encrypted messaging for confidential application data.
</Warning>

## Start both peers

Complete the [quickstart](/docs/getting-started/quickstart). Reuse its protocol instance. Register the requester handlers before calling `startMesh()`; register the provider after startup as described below.

## Provider

This example returns a public capability status. Supply `allowedRequester` from your application's enrollment policy.

```typescript theme={null}
import { MeshServices, OfflineProtocol } from '@offline-protocol/mesh-sdk';

export async function installStatusService(
  protocol: OfflineProtocol,
  allowedRequester: string,
) {
  const services = new MeshServices();
  protocol.on('service_request_received', async (event) => {
    if (event.type !== 'service_request_received') return;
    if (event.service_id !== 'equipment-status.v1') return;
    if (event.sender !== allowedRequester) return;
    if (event.method !== 'status') return;
    await services.respondToServiceRequest(
      event.request_id,
      event.sender,
      event.service_id,
      'ok',
      JSON.stringify({ status: 'available' }),
    );
  });
  await services.registerService('equipment-status.v1', '1.0', {
    format: 'json',
    operation: 'read-only-status',
  });
}
```

Register the request listener before discovery begins. Call `installStatusService` after the protocol has started; the helper installs its listener before registering the service.

## Requester

```typescript theme={null}
import { MeshServices, OfflineProtocol } from '@offline-protocol/mesh-sdk';

export function statusClient(protocol: OfflineProtocol, approvedProvider: string) {
  const services = new MeshServices();
  protocol.on('service_discovered', (event) => {
    if (event.type !== 'service_discovered') return;
    if (event.provider_peer_id !== approvedProvider) return;
    console.log('Provider:', event.provider_peer_id, event.version, event.hop_count,
      event.capabilities, event.query_id);
  });
  protocol.on('service_response_received', (event) => {
    if (event.type !== 'service_response_received') return;
    if (event.provider_peer_id !== approvedProvider) return;
    console.log('Response:', event.request_id, event.status, event.body);
  });
  return {
    discover: () => services.discoverServices('equipment-status.v1'),
    request: () => services.sendServiceRequest(
      approvedProvider, 'equipment-status.v1', 'status', '{}',
    ),
  };
}
```

Create the client before startup. After startup, call `discover()`. The example filters results to one pre-approved provider. Inspect its service ID, version, capabilities and query ID, then call `request()`. Implement selection among several approved providers in your application. Discovery returns a query ID; results arrive as events. Requests return a request ID; correlate the response to the pending request and expected provider in your application.

## Handle failure

Give every operation an application deadline. A missing response does not prove that the provider did no work. Retry read-only operations under a bounded policy. For side effects, persist an operation ID and result at the provider before retrying or switching providers.

A replacement provider must implement the same service contract and pass the same authorization checks. The SDK discovers providers; it does not decide your business policy or automatically transfer an unfinished job.

See [MeshServices methods](/docs/mesh-sdk/api/services) and [service events](/docs/mesh-sdk/events).

## Completion check

**Done when:** an approved provider returns a response correlated to the request, an unapproved requester receives no result, and a missing provider produces a visible timeout in your application. Continue with [production qualification](/docs/operations/production).
