Authdog

MCP SDK: Swift

Last updated Oct 13, 2026
View as Markdown

The Authdog MCP Swift SDK verifies a bearer token presented to your MCP server. AuthdogVerifier.verifyToken calls GET {baseURL}/v1/userinfo with the token and returns an AuthInfo. It needs Swift 5.9+ and targets iOS 13, macOS 10.15, watchOS 6, and tvOS 13 or later. It is a token verifier only, not an OAuth client or an MCP server framework.

Availability

The Swift SDK is source-available in `swift/` of authdog/mcp-sdk. The README shows a SwiftPM dependency on the repository URL from: "0.1.0", but no release tag was verified, and Package.swift lives in the swift/ subdirectory rather than at the repository root. A URL dependency may not resolve yet. Install from source until it does.

Install

Check out authdog/mcp-sdk and add the swift/ directory as a local package in your Package.swift:

dependencies: [
    .package(path: "../mcp-sdk/swift")
],
targets: [
    .target(
        name: "MyMCPServer",
        dependencies: [
            .product(name: "AuthdogMCP", package: "swift")
        ]
    )
]

The package name is AuthdogMCP in its manifest, but SwiftPM identifies a local path package by its directory name, so the package: value above is swift. If you rename the checkout directory, change it to match. The library has no third-party dependencies.

Configure

import AuthdogMCP

var config = AuthdogVerifierConfig(baseURL: "https://api.authdog.com")
config.timeout = 30

let verifier = AuthdogVerifier(config: config)
Field Type Default Notes
baseURL String required Authdog API base URL. Leading and trailing / characters are trimmed.
timeout TimeInterval 10 Seconds. Applied to the request and, on the default session, as both request and resource timeout.

AuthdogVerifier(config:session:) also accepts an optional URLSession, mainly for tests. A supplied session replaces the default one. Every request sends User-Agent: authdog-mcp-swift-sdk/0.1.0.

Verify a token

do {
    let auth = try await verifier.verifyToken("the-bearer-token")
    print(auth.subject, auth.username, auth.email ?? "n/a")
} catch AuthdogError.authentication(let message) {
    // HTTP 401
} catch AuthdogError.api(let message) {
    // any other failure
}

It sends Authorization: Bearer <token> and, on a 2xx response, maps the body to AuthInfo:

Field Type Source
token String the verified access token
subject String user.id
username String user.userName
email String? first user.emails value, else nil
scopes [String] always [] (userinfo returns no scopes)
expiresAt Date? now + session.remainingSeconds
user User full decoded user record

Do not use scopes for authorization yet. The verifier does not cache results; each call is one HTTP request.

The response is decoded with a strict Codable model. User.phoneNumbers and User.addresses are typed [String], so a userinfo response where those arrays contain objects would fail to decode and surface as AuthdogError.api.

Wire into an MCP server

Use the verifier in your transport's authorization hook. Extract the bearer token, verify it, and reject on failure:

func authenticate(authorizationHeader: String?) async throws -> AuthInfo {
    guard let header = authorizationHeader,
          header.hasPrefix("Bearer ") else {
        throw AuthdogError.authentication("Missing bearer token")
    }
    let token = String(header.dropFirst("Bearer ".count))
    return try await verifier.verifyToken(token)
}

The prefix check is case-sensitive.

Errors

AuthdogError is an enum conforming to Error and LocalizedError.

Case When
.authentication(String) HTTP 401. Message: Unauthorized - invalid or expired token.
.api(String) Invalid base URL, transport failure, non-HTTP response, any other non-2xx status (includes the body's error string when present), or a 2xx body that fails to decode.