Skip to content

TaricHive MCP server — setup & operations

The MCP server (src/TaricHive.Mcp, image ghcr.io/rousseauxy/tarichive-mcp) exposes TaricHive's tariff intelligence as Model Context Protocol tools over Streamable HTTP at https://mcp.opentaric.eu/mcp. It is an OAuth 2.1 resource server (RFC 9728): every request needs an Authentik-issued access token. It shares the TaricHive SQL database read-only (the Web app owns migrations and imports).

Tools

Tool Scope Purpose
search_goods taric:read Ranked code/text nomenclature search
get_goods_hierarchy taric:read Chapter → heading → code breadcrumb
get_measures taric:read All measures per code (duties, preferences, quotas, remedies, restrictions, national taxes)
compare_sources taric:read MFN duty comparison across EU/GB/CH/NO/SE/PL/TR/…
get_quota taric:read Quota volumes / balance / critical state
get_rulings taric:read EU BTIs + UK ATaRs (classification precedents)
get_notes taric:read Section/chapter legal notes, footnotes, CN explanatory notes
calculate_duty taric:calculate Duty + national-tax calculation for a declaration line
validate_declaration taric:calculate Condition/certificate validation for a declaration line

1. Authentik (auth.xact.cloud)

Create a second provider/application next to the existing tarichive web login:

  1. ProviderOAuth2/OpenID Provider, name tarichive-mcp:
  2. Client type: Public (no client secret; PKCE is enforced for public clients).
  3. Redirect URIs (strict where possible):
    • https://claude.ai/api/mcp/auth_callback
    • https://claude.com/api/mcp/auth_callback
    • Regex: http://localhost:\d+/callback (Claude Code + MCP Inspector loopback)
  4. Signing key: same certificate as the tarichive provider.
  5. Custom scopes (Customization → Property Mappings → Scope Mapping, expression can simply be return {}):
  6. taric:read — "Read tariff data"
  7. taric:calculate — "Calculate duties" Then edit the provider → Advanced protocol settings → add both to Scopes.
  8. Application "TaricHive MCP", slug tarichive-mcp, bound to the provider. Bind the same groups as the web app (Admins/Users) so only known users can authorize.
  9. Note from the provider page:
  10. Issuer: https://auth.xact.cloud/application/o/tarichive-mcp/
  11. Client ID: → Auth__Mcp__StaticClientId

2. Container / compose

  tarichive-mcp:
    image: ghcr.io/rousseauxy/tarichive-mcp:1
    restart: unless-stopped
    mem_limit: 1g
    environment:
      ConnectionStrings__TaricHive: "<same as tarichive web>"
      Auth__Mcp__Authority: "https://auth.xact.cloud/application/o/tarichive-mcp/"
      Auth__Mcp__StaticClientId: "<client id from Authentik>"
      Auth__Mcp__PublicBaseUrl: "https://mcp.opentaric.eu"
    # healthcheck: GET /healthz

DNS: mcp.opentaric.eu → same host as the app; Traefik router → this container :8080 (TLS at Traefik, plain HTTP inside — identical to the web app).

3. Connecting clients

  • claude.ai → Settings → Connectors → Add custom connector → URL https://mcp.opentaric.eu/mcp. No client ID/secret needed — the server implements a DCR shim (see below). Authorize via the Authentik login.
  • Claude Code: claude mcp add --transport http taric https://mcp.opentaric.eu/mcp then /mcp to authenticate.
  • MCP Inspector (debugging): npx @modelcontextprotocol/inspector, connect to the same URL, transport "Streamable HTTP".

4. The DCR shim (temporary)

Authentik does not implement RFC 7591 Dynamic Client Registration (upstream issue goauthentik/authentik#8751, milestoned 2026.8), while MCP clients self-register before the OAuth flow. Auth/McpOAuthFacade.cs bridges this:

  • /.well-known/oauth-protected-resource (SDK) advertises mcp.opentaric.eu itself as the authorization server;
  • /.well-known/oauth-authorization-server re-serves Authentik's discovery document with a registration_endpoint added (issuer rewritten to the facade per RFC 8414 §3.3 — token validation still pins the real Authentik issuer);
  • POST /oauth/register returns the one static public client to every caller.

Authorize/token/JWKS traffic goes directly to Authentik; the facade never sees tokens. When Authentik ships DCR: delete McpOAuthFacade.cs, point ResourceMetadata.AuthorizationServers at the Authentik issuer, and drop Auth__Mcp__StaticClientId.

5. Headless / machine-to-machine clients (Hermes, scripts, services)

Server-side agents can't run the interactive OAuth flow. Instead of a no-auth bypass, they use client_credentials tokens from a second, confidential Authentik provider:

  1. Authentik → new OAuth2/OpenID Provider tarichive-mcp-m2m:
  2. Client type: Confidential (client_credentials needs a secret).
  3. Signing key: the SAME certificate as tarichive-mcp (the MCP server discovers JWKS from the primary provider only — a different key will fail validation).
  4. Add the taric:read / taric:calculate scope mappings to its allowed scopes.
  5. Access-token validity: pick per rotation appetite (e.g. days=90) — headless clients hold the token as a static header, so it lives until expiry.
  6. Application "TaricHive MCP M2M" bound to the provider.
  7. MCP server env — allow the extra issuer/audience:
    Auth__Mcp__AdditionalValidIssuers=https://auth.xact.cloud/application/o/tarichive-mcp-m2m/
    Auth__Mcp__AdditionalValidAudiences=<m2m client id>
    
  8. Mint a token:
    curl -s https://auth.xact.cloud/application/o/token/ \
      -d grant_type=client_credentials \
      -d client_id=<m2m client id> \
      -d client_secret=<m2m client secret> \
      -d scope="taric:read taric:calculate" | jq -r .access_token
    
  9. Configure the client with a static header, e.g. Hermes config.yaml:
    mcp_servers:
      taric:
        url: "https://mcp.dv.opentaric.eu/mcp"
        headers:
          Authorization: "Bearer ${TARIC_MCP_TOKEN}"
    
    with TARIC_MCP_TOKEN in the container environment. Rotation = re-run the curl, update the env, restart the client.

6. Security notes

  • Access is controlled by the Authentik application binding (groups), not by client registration — the static client is public by design (PKCE, no secret to leak).
  • The endpoint policy requires taric:read; calculate_duty/validate_declaration additionally require taric:calculate in the token's scope.
  • Audience validation: Authentik sets aud to the client ID; override with Auth__Mcp__Audience if a dedicated audience is configured later.