Skip to content

Server Specifications and Registered Servers

To run tests you tell FHIR Frog which server to test. For one-off runs that is just a URL. For anything you repeat, you register the server once under a name, optionally tag it with a server specification (what kind of server it is meant to be), and refer to it by name afterwards. This page covers both files, the tools that manage them and how a run picks its target.

Two files live in the FHIR Frog configuration directory (~/.fhir-frog/, or the directory in FROG_CONFIG_DIR):

File Holds Written by
backends.yaml Your registered servers (backends): name, URL, spec, auth frog_server_register, or by hand
server-specs.yaml Your own server specifications (optional) by hand

Registering a server

frog_server_register(name: "qld-ereferral", url: "https://example.org/fhir", spec: "au-core")

The first call returns the plan; repeat it with confirm: true to write the file. The result in backends.yaml:

backends:
  - name: qld-ereferral
    url: https://example.org/fhir
    spec: au-core
    managed: false

Fields of a backend:

Field Meaning
name Unique name used everywhere else (server: "qld-ereferral")
url FHIR base URL
spec Id of the server specification this server is meant to satisfy
conformsTo IG canonical URL; filled from the spec when you give a spec
managed true for servers the MCP starts and owns (the local frog-sut); runs against managed servers need no confirmation
allowWrites Allow write operations although the spec is read-only
auth How to authenticate (below)

Authentication

Credentials are always references to environment variables, never values. A client-credentials backend:

frog_server_register(name: "secure-server", url: "https://example.org/fhir", authType: "client-credentials", tokenUrl: "https://auth.example.org/token", clientId: "frog", clientSecret: "${FROG_SECRET}", scope: "system/*.read")
    auth:
      type: client-credentials
      tokenUrl: https://auth.example.org/token
      clientId: frog
      clientSecret: ${FROG_SECRET}

Set FROG_SECRET in the environment that starts the MCP. A literal secret is refused (secret_not_allowed). For a static bearer token use authType: "bearer" with clientSecret: "${TOKEN_VAR}". Basic authentication is not supported in v0.1.

Server specifications

A specification names a class of server: "an AU Core server", "an AU eRequesting server". It lets you say what a server is meant to be without listing every server, and lets tests find an appropriate server.

List them with frog_server_spec_list. Three are built in:

Id Title Canonical Writes
au-core AU Core http://hl7.org.au/fhir/core read-only
au-ps AU Patient Summary http://hl7.org.au/fhir/ps read-only; extends au-core
au-erequesting AU eRequesting http://hl7.org.au/fhir/ereq write-capable

Add your own in server-specs.yaml. Entries with the same id replace built-ins:

specs:
  - id: qld-referral
    title: "QLD eReferral server"
    conformsTo:
      - http://example.org/fhir/qld-referral
    fhirVersion: R4
    readOnly: false
    capabilities:
      write: true
      resources: [ServiceRequest, Patient]
    extends: [au-core]
    quirks:
      maxPageSize: "50"
Field Meaning
id, title Identifier and display name
conformsTo IG canonicals the spec covers; the first is the primary
fhirVersion R4, R4B, R5
readOnly A read-only spec marks servers not to be used for write-heavy fixtures
capabilities.write, capabilities.resources What the server supports and what the tests exercise
extends Parent specs; a server of a child spec also satisfies the parent's canonicals
quirks Free-form known deviations, shown by frog_server_describe, not enforced

v0.1 specs are descriptive. They classify and document servers; the MCP does not yet refuse a run because a server does not meet its spec. frog_server_check verifies reachability and reports the FHIR version and software, nothing more.

Looking at what you have

frog_server_list()
frog_server_list(spec: "au-core")
frog_server_describe(name: "qld-ereferral")
frog_server_check(name: "qld-ereferral")

frog_server_check fetches /metadata; a redirect or a refused connection is reported as reachable: false with the reason. Secret values never appear in any of these.

How a run chooses its server

frog_run_local and frog_run_remote pick the target in this order and stop at the first that applies:

  1. serverUrl: used as given, with no registry metadata.
  2. server: the backend with that name.
  3. spec: the first registered backend whose spec equals that id.
  4. The test package's canonical: a backend whose spec or conformsTo covers it.
  5. If exactly one backend is registered, that one.

If none applies you get not_found rather than a guess. Non-loopback targets that are not managed or allowWrites need confirm: true because tests can write to them.

frog_run_remote(testPackage: "fhirfrog.au-core-tests#0.1.0", server: "qld-ereferral", confirm: true)

The local test server

frog_server_start_local registers the container it starts as the managed backend frog-sut. Select it with server: "frog-sut": the MCP uses the host address (http://127.0.0.1:8081/fhir) for local runs and the Docker network name (http://frog-sut:8080/fhir) for the runner container, so you do not choose. See Local test server.

What is not covered yet

  • Executing a resetPolicy between runs.
  • Refusing runs on specification violations (planned, v0.2).
  • Vendor or product classes beyond IG-based specs.
  • Multi-server matrix runs (planned, v0.3).