The Java MCP SDK (`com.authdog:authdog-mcp-sdk`) is a bearer-token verifier for [Model Context Protocol](https://modelcontextprotocol.io) servers. `AuthdogVerifier` takes the access token an MCP client presents, calls Authdog `GET /v1/userinfo` with it, and returns an immutable `AuthInfo` you can attach to your server's auth context. It requires Java 11 or higher and uses OkHttp and Jackson.

## Availability

The SDK is source-available in [github.com/authdog/mcp-sdk](https://github.com/authdog/mcp-sdk) (`java/`). Publication on Maven Central is unverified, so the coordinates below may not resolve from a registry yet. Until they do, build and install it from source.

## Install

Clone the repository and install the artifact into your local Maven repository:

```bash
git clone https://github.com/authdog/mcp-sdk.git
cd mcp-sdk/java
mvn clean install
```

Then depend on it:

```xml
<dependency>
    <groupId>com.authdog</groupId>
    <artifactId>authdog-mcp-sdk</artifactId>
    <version>0.1.0</version>
</dependency>
```

```gradle
implementation 'com.authdog:authdog-mcp-sdk:0.1.0'
```

For Gradle, add `mavenLocal()` to your repositories to pick up the locally installed artifact. `mvn clean package` builds the jar without installing it.

## Configure

Pass the API base URL to the constructor. There is no options object:

```java
// 10 second default timeout
AuthdogVerifier verifier = new AuthdogVerifier("https://api.authdog.com");

// custom timeout, in milliseconds
AuthdogVerifier verifier = new AuthdogVerifier("https://api.authdog.com", 30000);
```

The timeout is applied as the OkHttp connect, read, and write timeout. A trailing `/` on the base URL is removed. `AuthdogVerifier` implements `AutoCloseable`; `close()` shuts down the HTTP client's executor and evicts pooled connections. Share one instance across requests and close it on shutdown.

## Verify a token

`verifyToken(String accessToken)` sends `GET {baseUrl}/v1/userinfo` with `Authorization: Bearer <token>` and `User-Agent: authdog-mcp-java-sdk/0.1.0`:

```java
import com.authdog.mcp.AuthdogVerifier;
import com.authdog.mcp.AuthInfo;
import com.authdog.mcp.exceptions.ApiException;
import com.authdog.mcp.exceptions.AuthenticationException;

try (AuthdogVerifier verifier = new AuthdogVerifier("https://api.authdog.com")) {
    AuthInfo auth = verifier.verifyToken("the-bearer-token");
    System.out.println("Subject:  " + auth.getSubject());
    System.out.println("Username: " + auth.getUsername());
    System.out.println("Email:    " + auth.getEmail());
    System.out.println("Expires:  " + auth.getExpiresAt());
} catch (AuthenticationException e) {
    // 401: invalid or expired token
} catch (ApiException e) {
    // any other failure
}
```

`AuthInfo` is immutable:

| Accessor | Type | Source |
| --- | --- | --- |
| `getToken()` | `String` | The access token that was verified. |
| `getSubject()` | `String` | `user.id` |
| `getUsername()` | `String` | `user.userName` |
| `getEmail()` | `String` | First `user.emails[].value`, or `null`. |
| `getScopes()` | `List<String>` | Unmodifiable. Always empty. |
| `getExpiresAt()` | `Instant` | Now plus `session.remainingSeconds`. `null` when the response has no session. |
| `getUser()` | `User` | The full user record. |

## Wire into an MCP server

The SDK does not integrate with a specific Java MCP framework. Adapt `AuthdogVerifier` to whatever token-verifier hook your server exposes. This is the pattern from the SDK README:

```java
public class AuthdogMcpAuth {

    private final AuthdogVerifier verifier =
            new AuthdogVerifier("https://api.authdog.com");

    public AuthInfo authenticate(String bearerToken) {
        if (bearerToken == null || bearerToken.isBlank()) {
            throw new SecurityException("Missing bearer token");
        }
        try {
            return verifier.verifyToken(bearerToken);
        } catch (AuthenticationException e) {
            // 401: refuse the connection or tool call
            throw new SecurityException("Unauthorized", e);
        } catch (ApiException e) {
            // upstream failure: surface as a server error
            throw new IllegalStateException("Auth backend error", e);
        }
    }
}
```

Inside a tool or request handler, use `auth.getSubject()` and `auth.getUsername()` to enforce per-tool access or audit by caller.

## Errors

All exceptions are in `com.authdog.mcp.exceptions`. They are unchecked: `AuthdogException` extends `RuntimeException`, and `verifyToken` declares but does not force you to catch the two subclasses.

| Exception | When | Message |
| --- | --- | --- |
| `AuthenticationException` | HTTP 401 | `Unauthorized - invalid or expired token` |
| `ApiException` | Other non-2xx response | `HTTP error <status>: <body>` |
| `ApiException` | I/O failure, including timeout (`IOException`) | `Request failed: <cause>` |
| `ApiException` | Body cannot be parsed as the userinfo response | `Failed to parse response: <cause>` |

Catch `AuthdogException` to handle any SDK error at once.

## Related

- [MCP SDK](/docs/mcp-sdk)
- [MCP authentication](/docs/mcp-authentication)
