The Authdog MCP Dart SDK (`authdog_mcp`) verifies a bearer token presented to your [MCP](https://modelcontextprotocol.io) server. `AuthdogVerifier.verifyToken` calls `GET {baseUrl}/v1/userinfo` with the token and returns an `AuthInfo`. It requires Dart SDK `^3.0.0` and depends on `package:http`. It is a token verifier only, not an OAuth client or an MCP server framework.

## Availability

The Dart SDK is source-available in [`dart/`](https://github.com/authdog/mcp-sdk/tree/main/dart) of [authdog/mcp-sdk](https://github.com/authdog/mcp-sdk). The README shows `authdog_mcp: ^0.1.0`, but publication to pub.dev is unverified and the package may not resolve from the registry yet. Install from source until it does.

## Install

Check out [authdog/mcp-sdk](https://github.com/authdog/mcp-sdk) and use a path dependency in `pubspec.yaml`:

```yaml
dependencies:
  authdog_mcp:
    path: ../mcp-sdk/dart
```

```bash
dart pub get
```

## Configure

```dart
import 'package:authdog_mcp/authdog_mcp.dart';

final verifier = AuthdogVerifier(
  baseUrl: 'https://api.authdog.com',
  timeout: const Duration(seconds: 10),
);
```

| Parameter | Type | Default | Notes |
| --- | --- | --- | --- |
| `baseUrl` | `String` | required | Authdog API base URL. One trailing `/` is stripped. |
| `timeout` | `Duration` | 10 seconds | Per-request timeout. |
| `client` | `http.Client?` | `null` | Injected client, mainly for tests. When omitted, the verifier creates its own. |

Every request sends `User-Agent: authdog-mcp-dart-sdk/0.1.0`. Call `verifier.close()` when you are done to release the HTTP client. Per the SDK docs this applies when the verifier owns the client, that is, when you did not inject one.

## Verify a token

```dart
try {
  final info = await verifier.verifyToken('incoming-access-token');
  print(info.subject);
  print(info.email);
} on AuthenticationException catch (e) {
  // HTTP 401
} on ApiException catch (e) {
  // any other failure
} finally {
  verifier.close();
}
```

It sends `Authorization: Bearer <token>` and, on a 2xx response, returns:

| Field | Type | Source |
| --- | --- | --- |
| `token` | `String` | the verified access token |
| `subject` | `String` | `user.id` (empty string if absent) |
| `username` | `String` | `user.userName` (empty string if absent) |
| `email` | `String?` | first non-empty `user.emails[].value`, else `null` |
| `scopes` | `List<String>` | always empty (userinfo returns no scopes) |
| `expiresAt` | `DateTime?` | UTC, now + `session.remainingSeconds`; `null` if the response has no numeric value |
| `user` | `Map<String, dynamic>` | raw user object from the response |

Unlike the Kotlin and Swift SDKs, the Dart verifier does not use a typed user model, and a 2xx response missing user fields yields empty values rather than an error. Check that `subject` is non-empty if you depend on it. Do not use `scopes` for authorization yet. The verifier does not cache results; each call is one HTTP request.

## Wire into an MCP server

`verifyToken` returns the identity you attach to your transport's request context. Adapt it to your token-verification hook and treat any `AuthdogException` as unauthenticated:

```dart
Future<AuthInfo?> authenticate(String token) async {
  try {
    return await verifier.verifyToken(token);
  } on AuthdogException {
    return null; // invalid token or upstream failure
  }
}
```

Collapsing every failure to `null` also hides outages. Catch `AuthenticationException` and `ApiException` separately if you need to tell a rejected token from an upstream error.

## Errors

All errors extend `AuthdogException`, which exposes a `message` string.

| Exception | When |
| --- | --- |
| `AuthenticationException` | HTTP 401. Message: `Unauthorized - invalid or expired token`. |
| `ApiException` | Any other non-2xx status (message includes the status and body), a transport failure or timeout, or a body that is not a valid JSON object. |
| `AuthdogException` | Base type of both. |

## Related

- [MCP SDKs](/docs/mcp-sdk): all language token verifiers
- [MCP authentication](/docs/mcp-authentication): how Authdog authenticates MCP clients
