---
title: Pinax
type: service
layer: platform
status: draft
owner: Jasper Middendorp
scope: The overarching, Agno-exclusive service layer that fronts N1's MCP servers — owning configuration, Agno integration, discovery/registration, auth configuration, and external dependency management
tracker: TBD
related: MCP Data-Fetching Service; trusted-services registry (Eyad)
---
 
# Pinax
 
The overarching service layer that fronts N1's MCP servers. Pinax owns the cross-cutting
concerns every MCP server would otherwise re-solve on its own — configuration, Agno integration,
discovery/registration, auth configuration, and external dependency management — so standing up or
changing a server is a registration, not bespoke plumbing. Pinax is **Agno-exclusive** and lives at
**configuration/build time**: it is never in the data call path and never holds a patient token.
 
**The metaphor: Pinax is the chamber of commerce for N1's MCP servers** — a *specialized* one, for a
single trade: it serves MCP servers and only MCP servers (the data-fetching service is one member);
agents and infrastructure are outside its concern. A server registers once and the chamber sets it up
with everything — directory listing, settings on file, auth references, dependencies kept current — so
onboarding is joining, not bespoke plumbing.
 
Two boundaries the metaphor must keep honest: it is **not a checkpoint** (a server *could* operate
unregistered — nobody stops it — but it forgoes the setup and is off-policy; Principle 5), and it is
**never your storefront** — the chamber sets members up but never serves their customers (the agents).
That second line is the out-of-path boundary: Pinax is build-time, never in the call path, and does not
deal with agents at all (Principles 1, 3, 4). The roles and principles below make this precise.
 
## Problem
 
N1's MCP servers — the data-fetching service today, more coming — are each wired into Agno
independently, and every one re-solves the same cross-cutting concerns alone: discoverability (being
found and attached by agents), Agno integration (the MCPTools wiring and connection setup), its own
scattered settings, the auth configuration it needs to obtain and present tokens, and keeping its
external dependency versions current by hand.
 
This scales badly on two axes. Per server, the same integration is rebuilt each time, with no single
source of truth for settings or auth configuration — so each server configures itself slightly
differently and the configuration drifts. Across the fleet the wiring is combinatorial: every agent
must know about and attach every server it needs. And the servers — though isolated from each other —
each independently depend on the same **external** building blocks (the Agno framework, shared N1
libraries, the MCP SDK) that **evolve on their own**; without a central authority each server lags or
pins differently and falls out of currency with the moving outside world. There is no
overarching layer that owns discovery, the Agno binding, shared settings and auth configuration, and
the external dependency versions — so standing up a new MCP server is bespoke plumbing instead of a
registration.
 
## Outcome
 
Any N1 MCP server plugs into one overarching layer that owns its configuration, its Agno integration,
its discovery/registration, and the external dependency versions it builds against. Configuration has a
single authoritative source instead of being re-derived per server; discovery is centrally
maintained and made available to Agno at configuration time; the shared external dependencies are
pinned in one place and kept current there, so as the outside world changes a version bump propagates
from that one place rather than each isolated server falling out of currency on its own.
 
Onboarding or changing a server collapses to: register it with Pinax — discovery, the Agno wiring,
settings, auth configuration, and the dictated external dependency versions follow. No per-server
integration code is hand-written or hand-maintained.
 
**"Done looks like":** a new MCP server is registered with Pinax and becomes available to Agno —
discoverable, correctly configured, and correctly auth-wired — without touching per-server integration
code; and a change to a centrally-managed dependency or to auth configuration propagates from one
authoritative place. _(The concrete bar is in Acceptance criteria; the method is in Verification.)_
 
## Core principles
 
Five principles govern every scope decision. 1–2 fix *where Pinax sits* and *how hard it grips*; 3–4
fix the *boundaries* (what is Agno's, what is the consumer's); 5 fixes the *mechanism* (how it acts).
3–5 exist because they are the easy mistakes — letting Pinax creep into Agno's or the consumers' work,
or assuming it conforms servers by force.
 
### 1. Centralized configuration, distributed execution
 
Pinax owns *configuration*; it executes nothing. Execution is **Agno's** (connection lifecycle,
reconnection, auth-session establishment, composing agents) and the **servers'** (serving data,
validating tokens). Pinax is **build-time, baked into the artifact — never in the data call path,
never on the boot path**; a deployed fleet runs with Pinax down. Consequence: Pinax **never holds,
brokers, or mints a token** — it configures *how* auth is set up, never touches the token (the
rejected token-broker model is in the Security gate).
 
### 2. Manage it, or don't touch it
 
For any concern Pinax either **manages** it (owns it, is the single authoritative source) or **doesn't
touch it** — no soft middle, no optional "best-practice" library a server may or may not adopt (that
is the drift this layer removes). "Single authoritative source" describes *ownership* — one managed
source of each thing — **not** enforcement; how conformance happens is Principle 5. Collapsing the
many per-server re-implementations into one integration is the de-duplication, and is in scope.
Anything Pinax does not manage is a non-goal.
 
> Relationship to the data-fetching service: that spec defines a single MCP server (a governed
> read-only door); Pinax is the chamber of commerce all such businesses register with (see the
> metaphor at the top).
 
### 3. Agno's job is Agno's
 
If Agno already does something, Pinax does not reinvent or wrap it — it supplies that mechanism's
*configuration* and stops. Agno owns the connection/session lifecycle, reconnection, auth-session
establishment, runtime multiplexing, and **composing agents from the available servers**. Test:
*does Agno already own this?* If yes, Pinax's only move is to provide the config Agno consumes.
 
### 4. Consumers are opaque to Pinax
 
The servers and agents are **consumers**. Pinax knows servers *exist* and holds their config; it does
not reason about consumer *behaviour* — what an agent does, which servers it composes, what a setting
means in use. Test: *am I describing what a consumer does with this?* If yes, it is out of Pinax.
 
### 5. Pinax acts by incentive and policy, not enforcement
 
Pinax conforms servers by being **the path of least resistance backed by company policy** — register
once, get everything (config, Agno integration, auth wiring, dependency management) automatically,
strictly less work than hand-rolling. It does **not** gate, discover, or compel; "conforming" means
*took the sanctioned easy path*, not *was prevented from doing otherwise*. A server that goes around
Pinax simply forgoes the free setup and is off-policy. Test: *am I trying to enforce or prevent?* Then
it is the wrong mechanism — and anyway impossible, since Pinax is build-time and out of the path.
 
 
## Core roles — the concerns Pinax manages
 
Pinax manages exactly five concerns. This is the authoritative list (Scope references it; everything
outside it is, by Principle 2, a non-goal). Each role below is defined to the same template — purpose,
what Pinax owns, the authority model, inputs→outputs, who executes it (Agno and/or the server, never
Pinax), the verification hook, the boundary, and what is left to the design session. Discovery and
auth configuration are distinct concerns *applied through* the Agno-integration role at the wiring
step; they are defined separately because each is managed in its own right.
 
### 1. Settings
 
**Purpose.** Give every MCP server one authoritative source for its operational configuration, so
settings don't live scattered and slightly different across N server repos.
 
**What Pinax owns.** The authoritative *values* of each registered server's environment-invariant
application config — what the server *is* as an N1 MCP server, the same wherever it deploys. The
preliminary set (the authoritative per-server list is confirmed at the design session against each
server and api-backend; some entries are owned conceptually by another role and only *surface* here):
 
- *Connection / transport* — transport binding (Streamable HTTP), the server's endpoint, request
  timeouts.
- *api-backend access* — base URL / which endpoints this server reads, the shared `n1_api_client`
  config surface, pagination defaults.
- *Safety limits* — result caps, max page size, query timeouts. These are settings **and** security
  controls; owning them centrally gives a fleet-wide safety floor (see Security gate).
- *Caching* — enable plus per-content-type TTLs / freshness bounds and invalidation-policy hooks
  (caching is integral-from-v1 in the data-fetching service).
- *Auth wiring* — registry endpoint, the scope(s) this server requests, `header_provider` parameters,
  and the secret-manager **reference** (which key) — never the secret value. *(Defined under role 4;
  surfaces here as values.)*
- *Agno / connection-lifecycle* — the `refresh_connection` policy and the connection/session
  parameters Agno exposes. *(Agno executes; Pinax sets the values.)*
- *Registry / identity* — the server's name/identity and its advertised entry *(role 2)*, and the
  inverted-pin reference *(role 5)*.
- *Operational* — log level and the server's own operational-logging settings (per the observability
  split).
**Authority & ownership model.** Single source of truth: a server carries no settings of its own and
cannot override Pinax's. Values reach the server only through the one mandatory integration and are
**baked into the image at build** (build-pull). There is exactly one place each value is stated, keyed
on server identity — drift is structurally impossible.
 
**Inputs → outputs.** *In:* the registered server's identity plus its setting values in Pinax's
config. *Out (at build):* those values baked into the server's deploy artifact. No runtime emission.
 
**Executed by.** The **server**, reading its baked-in settings at runtime. Pinax neither holds nor
serves settings live.
 
**Verification hook.** The deterministic *single source* check: a server's emitted settings match
Pinax's authoritative values exactly, and a change to a value at that one source flows to the fleet on
the next build (a Pinax change is fleet-wide — see build-pull).
 
**Boundary.** Pinax owns *which values*, not what a setting *means* or *does* — semantics and effect
are the server's. **Secrets are out**: only the secret-manager reference is Pinax's; the secret value
is delivered by Helm / the secret manager at deploy (see Relationship to Helm). **Infra is out**:
replicas, resources, probes, namespace are Helm's, never Pinax settings.
 
**Open at design session.** The concrete per-server settings schema (the exact keys each server type
exposes), read off the servers and api-backend; and any value that sits on the line between a setting
and another role's concern (e.g. a cap that is also a security control — owned here as a value,
governed by the Security gate).
 
### 2. Discovery / registration
 
**Purpose.** Be the one authoritative answer to "what MCP servers exist and how is each reached," so a
new server becomes available to the fleet by registering with Pinax rather than by editing consumers,
and no agent hard-wires standing knowledge of every server.
 
**What Pinax owns.** The **registry** — the authoritative record of every MCP server in the fleet:
its identity and the connect metadata Agno needs to attach it (endpoint/transport, and a handle to the
per-server config the other roles own). Registration *is* adding a server to this record. The registry
records *that a server exists and how to reach it* — not a detailed catalogue of the server's tools:
a server's tool list/capabilities are discovered over the connection at the MCP handshake (they live
inside the server, e.g. the data-fetching service's own `list`/`describe`), not in Pinax.
 
**Authority & ownership model.** Pinax is the **single central place an MCP registers, and registering
gets it everything automatically** — no per-server discovery wiring. It is the authoritative source
for the registry; conformance comes from this being the path of least resistance backed by company
policy (Principle 5), not from gating — Pinax does not discover, police, or compel servers, and a
server that lists itself elsewhere by hand simply forgoes what Pinax provides and is off-policy. The
registry is emitted at build (build-pull), baked in — **not** a live endpoint agents query at runtime
(Principle 1).
 
**Inputs → outputs.** *In:* a server's registration entry in Pinax's config (identity + connect
metadata + its config from roles 1, 4, 5). *Out (at build):* that server present in the
Agno-consumable registry shipped in the artifact; a removed registration drops out.
 
**Executed by.** **Agno**, which reads the emitted registry to know the available servers and attach
them, and composes agents from them — Pinax does not model which agent uses which server (Principles
3–4).
 
**Verification hook.** The deterministic *correct, complete registry for Agno* check: the emitted
registry lists exactly the registered servers — a registered one appears, a removed one drops out,
none are invented — each with correct connect metadata in the form Agno consumes.
 
**Boundary.** Pinax owns *that a server exists and how to reach it*, not *who uses it or why* (agent
composition is Agno's; Principle 3) and not the server's internal capabilities (discovered over the
connection, not held in the registry). Not a runtime discovery service — no live query endpoint
(Principle 1). The detailed per-server config hangs off each registry entry but is *owned* by roles 1
(settings) and 4 (auth); role 2 owns the list and reachability, not those values (no double-ownership).
 
**Open at design session.** The exact registry entry shape (which fields a registration carries) and
how connect metadata is represented, read against Agno's consumable format and the server set; and how
a removed registration propagates to already-built artifacts (ties into build-pull / drift detection).
 
### 3. Agno integration (the Agno-consumable form)
 
**Purpose.** Hand the registry and per-server config to Agno in the exact form Agno consumes, so no
server or agent hand-assembles its Agno MCP wiring.
 
**What Pinax owns.** The *output contract* — the form in which roles 1, 2, and 4 are expressed for
Agno: each server rendered as the inputs Agno needs to construct a single-server `MCPTools` connection
(endpoint/transport, the `header_provider`/auth wiring, the `refresh_connection` policy), never
`MultiMCPTools` (deprecated; see Known Agno constraints). Role 3 owns the *shape*; the *values* it
carries are owned by roles 1/2/4 (no double-ownership) — this role is how they reach Agno.
 
**Authority & ownership model.** Single authoritative form, emitted at build (build-pull) and baked
in. Because Pinax produces the Agno-consumable config and Agno consumes it directly, there is one way
an N1 server is wired into Agno — not per-server improvisation. Conformance is by ease + policy
(Principle 5), not enforcement.
 
**Inputs → outputs.** *In:* the registry + per-server settings/auth from roles 1, 2, 4. *Out (at
build):* that config in Agno's consumable form, baked into the artifact for Agno to construct
connections from.
 
**Executed by.** **Agno** — it reads the config, constructs the `MCPTools` connections, manages their
lifecycle, and **composes agents** from the available servers. Pinax produces the config; Agno does
all the wiring and composition (Principle 3).
 
**Verification hook.** Part of the deterministic *correct, complete registry/config for Agno* check:
each server is emitted as valid single-server `MCPTools` config (never `MultiMCPTools`) carrying the
correct values from roles 1/2/4, in the form the pinned Agno version consumes.
 
**Boundary.** Pinax produces the *config Agno consumes*; it does **not** construct connections, run
sessions, reconnect, or compose agents — all Agno's (Principle 3) — and it does **not** produce
per-agent setups (which servers an agent uses is Agno/agent-side; Principle 4). It is the output form,
not a second Agno.
 
**Open at design session.** The exact Agno-consumable representation (against the pinned Agno
version), and how the `header_provider` token-attachment is expressed given Agno's
fresh-connection-per-context behaviour (see Known Agno constraints).
 
### 4. Auth configuration
 
**Purpose.** Give every server one managed, correct auth setup so each does not reinvent a
security-sensitive OAuth flow — while Pinax never touches a token.
 
**What Pinax owns.** The *configuration* of how a server/agent connection authenticates: the
trusted-services registry endpoint, the scope(s) a server requests (scope conventions), the OAuth
client wiring, the `header_provider` parameters, and the secret-manager **reference** (which key holds
the OAuth client credential) — never the credential or any token itself.
 
**Authority & ownership model.** Single authoritative source for these values, baked in at build
(build-pull). One managed auth config, not N hand-rolled ones — which is also a fleet-wide security
floor (scopes can't quietly broaden per server). Pinax owns the *config*; it owns **no token and no
secret value** (Principle 1).
 
**Inputs → outputs.** *In:* the registry/scope/client/`header_provider` values + the secret-manager
reference in Pinax's config. *Out (at build):* that auth config baked into the artifact, in
Agno-consumable form (role 3).
 
**Executed by.** **Agno** injects the header / establishes the authenticated session (via
`header_provider`), and **each server** validates the token it receives, independently, against the
issuer-established token. The token flows only between the connection and Eyad's registry; **Pinax is
never in that path.**
 
**Verification hook.** The emit reproduces each registered service's auth config exactly as the
managed config holds it (faithful, member-gated — a non-member resolves none); no token or secret
*value* ever appears in an emitted artifact, only the secret-manager reference. (Pinax does not judge
whether a scope is correct — that is authored and reviewed in Pinax's repo; see Security gate.)
 
**Boundary.** Pinax configures *how* auth is set up; it does not issue, hold, broker, validate, or
mint tokens (issuance is Eyad's registry; validation is each server's), and holds no secret values
(Helm/the secret manager delivers those at deploy — see Relationship to Helm). The rejected fleet-wide
token-broker model and the full security posture are in the Security gate.
 
**Open at design session.** The token-attachment mechanism against the pinned Agno version (the
`header_provider` fresh-connection-per-context behaviour) and against the registry's interface
(passthrough vs. token exchange, and the patient-scope claim shape) — shared with the data-fetching
service and confirmed once Eyad's registry interface is available.
 
### 5. External dependency management
 
**Purpose.** Keep every member's build current against the **external** functionality it depends on —
the frameworks, SDKs, and shared libraries that live *outside* the server and **evolve on their own** —
so that as those external things change, each server stays on a current, working version rather than
independently lagging, pinning, or breaking. The concern is currency of a moving external world, not
uniformity for its own sake.
 
**What Pinax owns.** The authoritative *versions* of the **external, shared dependencies** each MCP
server builds against. Initial examples (illustrative, **not** an exhaustive list — the actual set is
determined at the design session, see Development): the Agno framework, the Pinax library (the inverted
pin), shared N1 libraries such as `n1_api_client`, and the MCP SDK. The defining trait is *external*:
functionality the server consumes from outside and does not own. A server's **internal** dependencies —
its own code, and any libraries it chooses for itself that are not in the shared external set — are the
server's own business; Pinax does not touch them.
 
**Authority & ownership model.** Single source: the version of each external dependency a server builds
against is dictated centrally and delivered through the one integration at build (build-pull), not
chosen per server. A bump happens in one place and the fleet picks it up on next build — no per-server
drift. (Conformance is by the path of least resistance, Principle 5, not enforcement.)
 
**Inputs → outputs.** *In:* the authoritative version set in Pinax's config (the external deps + the
Pinax library itself), keyed by server identity. *Out (at build):* a **Pinax-produced lockfile** per
server, which the build resolves against, so each server is built against exactly the dictated set,
baked into its artifact. (This is the inverted pin — see Approach → Repository structure; role 5 is that
mechanism applied across the whole external set.)
 
**Executed by.** The **server's build**, which resolves against the Pinax-produced lockfile. Pinax
authors the lockfile from its config; it does not run anything.
 
**Verification hook.** A bump to a version in Pinax's config produces an updated lockfile, so the
fleet's next build picks it up from that one change; no server resolves a version other than the
dictated one.
 
**Boundary.** This is *external* dependency management only, and it is **not**: any notion of one server
depending on, calling, or being coupled to another (there is none — servers are isolated; agent-side
composition is Agno's, Principle 3); nor management of a server's **internal/own** dependencies (those
are the server's). The line is external-vs-internal: Pinax keeps the shared external set current,
nothing else.
 
**Open at design session.** Exactly which external dependencies are in the shared set Pinax dictates
versus left to each server's own discretion — **identifying that set is an explicit development step**
(see Development) — and the lockfile's exact format and how a build fetches its own. The mechanism (a
Pinax-produced lockfile, the inverted pin) is settled; only the set's membership and the field-level
format are open.
 
The two runtime owners these roles defer to — **Agno** (connection lifecycle, reconnection,
authenticated-session establishment) and **each MCP server** (token validation, data serving) — are
detailed in Approach.
 
## Scope & non-goals
 
### In scope
 
Everything in **Core roles** (the five managed concerns) is in scope, delivered at
configuration/build time, with Pinax out of the runtime path. Pinax is **Agno-exclusive**.
 
Also in scope as a deliverable of **this work** (not of Pinax-the-artifact): **creating the shared base
Helm chart** in the infra/platform layer that MCP servers build their charts on. This effort produces
it so the consistent-deploy path exists from the start rather than being deferred elsewhere — but it is
an infra-layer artifact, **not part of the Pinax library/config/registry and not owned or touched by
Pinax at all** (the Pinax↔Helm boundary in Approach holds). Distinguish throughout: *this setup* builds
the base chart; *Pinax* does not own it.
 
### Non-goals — what Pinax does not touch
 
- **Not in the data call path.** Pinax never routes, proxies, or multiplexes a tool call. Runtime
  multiplexing across servers is **Agno's** (`MCPTools` instances on the agent), not Pinax's.
- **Never holds, brokers, stores, or mints a patient token.** Token issuance is Eyad's registry; token
  validation is each server's.
- **No canonical code, templates, or recommended-best-practice library; no adoption-by-convention.**
  (Principle 2.)
- **Not a custom Agno client and not a framework-agnostic abstraction.** Pinax is Agno-exclusive by
  design; there is no pluggable-framework layer and no non-Agno transport.
- **Not building, scaffolding, or generating MCP servers — and not building agents.** The MCP servers
  and the agents are **consumers** of Pinax, not part of it. Pinax's responsibility ends at what it
  manages and emits (config, the registry, the integration library, the inverted pin); a consumer's
  own code, structure, deployment, and behaviour are entirely its own. This spec builds Pinax only.
- **Not the trusted-services registry.** Eyad's registry (token pre-authorization and issuance) is a
  hard dependency, consumed, not built here. _(The same registry authorizes the data-fetching
  service.)_
- **No runtime observability layer.** Runtime observability is delegated to Agno's OpenTelemetry
  tracing (which already yields the cross-MCP/fleet-wide view via its trace store); Pinax builds no
  runtime telemetry system of its own. See Approach → Observability.
## Approach
 
Pinax is built as the authoritative configuration layer for N1's Agno-based MCP fleet, sitting at
configuration/build time and out of the runtime path. The approach falls out of the five principles
plus what the research established about who owns what at runtime.
 
### Repository structure — split polyrepo, centralized config
 
Code is distributed; configuration and the external dependency versions are centralized. This is
Principles 1–2 expressed as repos.
 
- **The Pinax repo holds two things:** (a) the **single mandatory integration** (the library/CLI a
  server imports — defined in The delivery mechanism); and (b) the **authoritative config + registry**
  — which MCP servers exist and what each offers, each server's settings, the auth configuration
  (registry endpoint, scopes, `header_provider` wiring), and the dictated version set per server (the
  inverted pin, below — the external deps plus the Pinax library). This is data Pinax owns, not code
  servers carry.
- **Each MCP server is its own repo** (preserving the data-fetching spec's "new repo per service" and
  per-team ownership), holding only its own server code. It declares that it uses Pinax and is
  *registered in* Pinax's config; it does **not** hold its own config or a private copy of the
  integration logic.
So the fleet is N+1 repos: one Pinax repo (library + config + registry), N server repos (one per MCP,
each independently deployed).
 
**The inverted version pin (the linchpin).** A server repo must **not** choose its own versions or hold
its own config — that is the ordinary shared-library pattern, and it is exactly the drift Principle 2
forbids (some servers upgrade, some don't, copies diverge → "twelve places" again, wearing version
numbers). Instead the pin is **inverted**: the server self-pins **nothing**; it says *"I use Pinax,"*
and **Pinax** dictates the entire version set it builds against — the Pinax library itself, the Agno
framework, the MCP SDK, the shared N1 libraries: *everything*. The authoritative statement of "server X
builds against this set of versions and this config snapshot" lives in **Pinax's config**, keyed on the
server's identity — not in X's repo. (This is the same mechanism as **role 5, external dependency
management** — role 5 *is* the inverted pin applied across the whole external set; the Pinax library is
simply one more entry in that dictated set. One mechanism, one place, dictating all versions, not two.)
 
Concretely, the dictation is delivered as a **Pinax-produced lockfile**: a normal version lockfile —
except *Pinax* authors it, per server, from its central config, rather than the server writing its own.
The build resolves against that Pinax-produced lockfile, so it ends up on exactly the dictated set. That
the import is mandatory **and** the lockfile is centrally authored is what makes this *management*, not
adoption-by-convention. _(Field-level details — how a build identifies itself to fetch its lockfile, the
exact lockfile format — are design-session; the inversion and the Pinax-produced lockfile are fixed
here.)_
 
### Lifecycle ownership — what Pinax does not start or stop
 
Two different "lifecycles" must not be confused, and **Pinax owns neither**:
 
- **Server process / deployment lifecycle** (starting and stopping an MCP server) is the **standard
  deploy path** — container → ECR → Kubernetes/Helm, exactly as the data-fetching service deploys.
  Pinax does **not** orchestrate, start, or stop server processes; doing so would put it adjacent to
  the runtime path it must stay out of. Pinax's only contribution to a server's startup is the config
  that was **baked in at build** (build-pull, below).
- **MCP connection / session lifecycle** (connect, handshake, bind, refresh, teardown) is **Agno's**
  (`MCPTools`, `mcp_lifespan`, `refresh_connection`), as established in the research. Pinax owns the
  *configuration* of these mechanisms, never their execution.
### Relationship to Helm / deploy — a hard boundary
 
**Pinax never touches infra, deploy, or Helm.** The two are different layers, different times, with
no shared surface:
 
- **Pinax = environment-invariant application/identity config, baked into the image at build.** The
  settings (see Core roles → Settings), auth wiring, registry/identity, and the inverted pin — what
  the server *is*, the same wherever it runs. Baked **into the image** (not a ConfigMap or Helm values
  file) deliberately: it keeps the seam hard and forecloses a live-edit backdoor, so the only way to
  change Pinax-owned config is a rebuild from Pinax.
- **Helm = per-environment infra + the actual secret values, applied at deploy.** Replicas, resources,
  probes, namespace/cluster/environment, image tag; and it mounts the real secret *value* from the
  secret manager into the pod. *How this deployment runs* — different across staging/prod.
- **The one handoff is secrets:** Pinax owns the secret-manager *reference* (which key), baked in;
  Helm/the secret-manager delivers the *value* at deploy. Pinax holds no secret material.
Each MCP keeps **its own Helm chart** — its repo, its responsibility — and Pinax does not generate,
own, or orchestrate deployment. Since every server needs a chart to deploy at all, the path is a shared
**base Helm chart** (infra/platform layer) as the obvious starting point — the common deploy shape
(probes, resource floors, the secret-mount pattern) — that a server builds its chart on and adds only
what's specific to it, rather than hand-rolling the baseline from scratch. **Creating that base chart
is in scope for this work** (so the consistent path exists from the start), but it is an infra-layer
artifact: **Pinax does not own, contain, or touch it** — the boundary holds. This is
the same incentive logic as the inverted pin (Principle 5): the provided base is strictly less work and
the consistent path, so building a chart off it is the natural default; a server *could* hand-roll its
own instead, but that is off-policy and needlessly inconsistent — and, like everything about how a
server builds and runs, nobody prevents it and the server owns the result. The infra layer owns the
base; what a server does with it is the server's. That base chart is a referenced convention here,
**not defined by this spec** (it is infra, not Pinax), and Pinax's only contribution to it is the
values a chart consumes (e.g. the secret-manager reference, above). The model is symmetric: a shared
base keeps *infra* consistent the way Pinax keeps *app config* consistent — same incentive principle,
two domains, clean seam, neither reaching into the server.
 
### Who owns what
 
- **Agno** — connection/session lifecycle, reconnection, authenticated-session establishment, runtime
  multiplexing, and composing agents (the mechanisms in Lifecycle ownership and Known Agno
  constraints). Pinax configures these; Agno executes them.
- **Each server** — serving data and validating its own token, independently against the
  issuer-established token (the data-fetching service's model, unchanged).
- **Pinax** — the configuration that drives the above: the registry, each server's Agno-consumable
  `MCPTools` config, the `header_provider`/scope/registry wiring, the refresh policy, settings, and
  the external dependency versions. Build-time only.
### Known Agno constraints to design against
 
- **Use `MCPTools`, not `MultiMCPTools`.** `MultiMCPTools` is deprecated in favour of multiple
  `MCPTools` instances; the multi-server case is a list of single-server toolkits. _(This is also a
  correction the data-fetching spec needs — see Sibling-spec corrections.)_
- **No mid-run reconnection resilience in Agno.** Agno does not auto-retry failed connections or
  implement backoff mid-run; there is a known issue (~Agno v2.3.24) where a failed reconnection raises
  a `CancelledError` that can cancel the whole agent run. How Pinax's configuration accounts for this
  (refresh policy, failure handling expectations) is a design-session item.
- **`header_provider` header timing.** `header_provider` establishes a fresh connection per context
  rather than passing per-request headers on a shared connection; how patient-scoped tokens attach via
  this mechanism must be confirmed against the pinned Agno version.
### The delivery mechanism — build-pull through one mandatory integration
 
**In plain terms first.** Pinax is a central place that holds each server's config. There are two
common ways a server could get config from such a place: pull it **at runtime** (the server phones home
to a config service when it starts — the more common pattern) or pull it **at build time** (the config
is baked into the server's image when the image is built, and the running server never phones home).
Pinax uses the **build-time** way, on purpose: because this config governs PHI-gating auth, we do not
want a live service the whole fleet depends on at runtime, and we want every config change to go through
normal deploy review. The trade is that changing config means rebuilding and redeploying — which is fine
here, because this config changes occasionally and *should* be reviewed when it does.
 
**"Build-pull"** is the name for that build-time pull: at build, the server fetches its config from
Pinax and bakes it into the image — the same shape as a build fetching its dependencies or pulling a
secret reference. **"The emit"** is the output of that step: the concrete config artifacts the build
produces from Pinax's stored config and writes into the image. (So when Verification says it tests "the
emit," it means it checks that this build step produces the right config for a server — and since that
build step is the only Pinax-related thing that ever runs, it is the only thing there is to test.)
 
Configuration reaches servers and agents through **exactly one mandatory integration**
(Principle 2) — a single "get config / Agno wiring / auth setup from Pinax" path, not re-implemented
per server — and that integration **pulls from Pinax at build/deploy time and bakes the result into
the deployed artifact** ("build-pull").
 
Consequences, which the rest of the spec rests on:
 
- **Pinax is never needed at runtime or at boot.** A deployed server/agent runs entirely on baked-in
  config; Pinax can be down with no effect on the running fleet. This is the strongest form of "never
  in the path" — Pinax is not even on the boot path — and the conservative posture for a layer that
  configures PHI-gating auth.
- **Config changes land through deploy.** A change in Pinax (a scope, a setting, a dependency version)
  takes effect when the affected artifacts are re-emitted and redeployed — not live. This is
  deliberate: security-sensitive config inherits the normal deploy flow's review, diff, versioning, and
  rollback, rather than propagating on an unreviewed restart.
- **A deployment's config is explicit and reproducible** — pinned to what Pinax emitted at build
  time, answerable from the artifact itself.
- **Rollback is ordinary deploy rollback — fleet-wide, heavy but simple.** Because config is baked into
  the image, the previous artifacts already carry the previous config, so **redeploying the prior fleet
  rolls its config back with it** — Pinax is not even involved. To instead roll *forward* to a corrected
  state, revert the change in Pinax's config repo and re-emit + redeploy — fleet-wide, since any Pinax
  change is fleet-wide by nature (above). Either way it is a standard deploy operation, not a bespoke
  Pinax mechanism, and there is no live config to "un-set."
The single integration is **MCP-side** (decided): the server imports the mandatory Pinax library (the
"I use Pinax" declaration), and the **server's build** runs it to pull config from Pinax and produce the
emit baked into the image. Pinax itself runs nothing — it is config/data the build reads, which is what
keeps "Pinax never executes" (Principle 1) a concrete fact rather than just a stance; a Pinax-side
integration would risk becoming a component that runs. What is also fixed: there is exactly one such
integration, it is the sanctioned single path (going around it is hand-rolling — off-policy and
unmanaged, not something Pinax prevents; Principle 5), and it is build-pull.
 
The accepted trade is that config changes require a redeploy to take effect; rejected alternative was
**startup-pull** (servers read Pinax live at boot), which would make Pinax a fleet-wide boot
dependency with its own HA/uptime requirement and would let security-sensitive config changes bypass
the deploy review gate — costs not worth the only prize, no-redeploy config changes, which N1 does
not need for the kind of config Pinax owns.
 
> Agno version pin, the exact registry interface, and the token-attachment mechanism are confirmed at
> a build-time design session against the live Agno version and Eyad's registry, mirroring the
> data-fetching service's design-session model.
 
### Observability — delegated to Agno; build-time provenance to the pipeline
 
Runtime observability is **Agno's**, not Pinax's. Agno's OpenTelemetry tracing captures the agent
execution flow as hierarchical spans (LLM calls, tool executions, delegations) with token usage,
latency, errors, and I/O — stored in your own infrastructure. Because every agent's runs flow through
it, a **cross-MCP / fleet-wide runtime view already exists** as a query over that trace store; it is not
a Pinax feature to build.
 
Two things fall outside Agno's agent-side tracing, and neither makes Pinax a runtime-observability
owner: a **server's internal operations** (its api-backend reads, cache hits, error-mapping) are the
server's **own operational logging**; and **Pinax's own actions** are build-time emit/registration
events whose record is **build/CI logging and artifact provenance** (what config produced which
artifact, when) — a byproduct of build-pull in the deploy pipeline, not a runtime system. So Pinax
builds **no runtime observability layer** (that would breach Principles 1 and 3).
 
## Risks & failure modes
 
- **Mis-configuration blast radius.** Pinax is the single authoritative source of configuration for
  the fleet; a wrong auth-config, scope, or registry entry can mis-configure many servers at once. This
  is the price of centralization. It is bounded *not* by Pinax validating content (Pinax does not judge
  config correctness) but by **where the config is authored and how it ships**: registry entries are
  authored and reviewed in Pinax's repo (ordinary code review on the change), and build-pull means a
  bad entry cannot reach the fleet until it is emitted and redeployed — so it also passes the normal
  deploy review/diff and is rollbackable like any other deploy. Two review gates (authoring + deploy),
  not a Pinax content-check. Residual risk: a wrong-but-well-formed entry that passes both reviews —
  accepted, same as any reviewed config change.
- **Agno coupling.** Agno-exclusivity plus reliance on Agno's native mechanisms means Agno changes
  (the deprecation of `MultiMCPTools`, the reconnection `CancelledError` bug, `header_provider`
  behaviour) propagate to Pinax. Mitigation: pin the Agno version; track these at the design session.
- **Cross-team dependency on the trusted-services registry (Eyad's).** Until it is live and Pinax (and
  each server) is registered, the auth-configuration path is incomplete. Shared with the data-fetching
  service. _(See Open questions.)_
- **Drift in anything Pinax does not manage.** By Principle 2, anything outside Pinax's managed set is
  the server's own; that is an accepted trade-off, but the boundary must be explicit so gaps are
  chosen, not accidental.
- **A server going around the inverted pin.** The split-polyrepo structure (Architecture) keeps
  versions from drifting *for conforming servers*: registration delivers the Pinax-dictated version set
  automatically (the Pinax-produced lockfile), so a conforming server never self-pins. A server *could*
  hand-roll its own versions/config instead — but that is going off the sanctioned path (Principle 5),
  forgoing what Pinax delivers for free, and Pinax neither prevents nor polices it. The residual risk is
  therefore an off-policy server drifting; it is addressed the same way all conformance is — ease and
  policy, plus ordinary review — not by a mechanism Pinax enforces. (Pinax's own emit is still correct
  regardless: it only ever emits the versions it dictates.)
- **Config changes are fleet-wide by nature (build-pull trade).** Pinax is a fleet-wide layer: a change
  to its config means the **whole fleet** is now built against a superseded snapshot, so **all** MCP
  services rebuild and redeploy to pick it up — not a subset. This is not a silent-drift problem needing
  detection (there is no "which servers drifted?" question — the answer is always "all, until the fleet
  redeploys"); it is simply a property of a centralized build-time layer. The redeploy itself is owned by
  **infra / the deploy pipeline** (the same boundary as Helm — Pinax does not orchestrate it). The cost
  is real and deliberate: a one-line Pinax change triggers a fleet-wide redeploy — **heavy, but simple**,
  and it inherits the normal deploy flow's review, diff, and rollback. The only residual is ordinary
  deploy discipline (the fleet redeploy must actually be run after a Pinax change), an operational
  matter, not a Pinax mechanism.
## Verification
 
What is verified is **the emit** — the build-time step that turns Pinax's stored config into the
artifacts a server's build bakes in (defined in Approach → The delivery mechanism). Because it is
build-time, not a running service, verification is largely deterministic and runs in the build/test
pipeline: given a fixture set of registered servers, external dependency versions, and auth config,
assert that the emitted artifacts are exactly correct. There is no live agent to observe here — and
Pinax does not produce per-agent setups (Agno composes agents, Principle 3); Pinax's job ends at
producing the right config and registry. The method is a **loop** — declare expected, emit, verify
output, fix the emit (never the fixture), re-run — built harness-first and run through every
milestone (see Development).
 
Two tiers, checked differently:
 
**Deterministic — must always hold (asserted mechanically; a failure is a hard defect):**
 
- **Correct, complete registry/config for Agno.** The emitted registry lists exactly the registered
  servers with each server's correct config (endpoints, settings, auth wiring, refresh policy) in the
  form Agno consumes, expressed via single-server `MCPTools` (never `MultiMCPTools`).
- **Faithful auth config.** Each registered server's emitted `header_provider`/scope/registry wiring
  reproduces the managed auth config exactly — what the registry holds is what the artifact carries,
  no more and no less. (Whether that managed scope is itself correct is authoring-side, not a Pinax
  emit check.)
- **Single source.** Every emitted value traces to one authoritative source in Pinax; a change at that
  source flows to the whole fleet's next build (fleet-wide by nature — see build-pull).
- **External dependency currency.** A bump to an external dependency's version in Pinax propagates to
  every server's emitted build from the one change, so the fleet stays current with the external world;
  no server resolves a version other than the dictated one. (Servers are isolated — this is each build
  picking up the dictated external version, not any inter-server relationship.)
- **Member-gated, faithful emit.** Config is emitted **only for a registered service**; an
  unregistered service resolves nothing (unprovisioned, never a default). For a registered service, the
  emit faithfully and completely reproduces what Pinax's registry holds for it — no partial artifact, no
  filled-in default. Pinax does **not** judge whether the registry's *contents* are correct or safe
  (that is the maintainer's, authored and reviewed in Pinax's repo); it asserts the emit is a complete,
  member-gated reproduction of the authoritative registry.
- **Fail, don't guess, on an unresolvable reference.** If a registration points at something the emit
  cannot resolve (e.g. an unknown/unresolvable pinned Pinax version), the emit **fails** rather than
  guessing or substituting a default — a mechanical-integrity failure, not a content judgement.
- **No token material.** No patient token, OAuth client secret, or other credential material ever
  appears in an emitted artifact (only configuration that points at where execution obtains them).
- **Out-of-path invariant.** Emitted artifacts contain no runtime/boot-time call back to Pinax — a
  deployed unit depends on Pinax nowhere (the build-pull guarantee, asserted).
**Best-effort — judged, not asserted:** whether a registration is ergonomic — that registering a
server is genuinely "register and done," with no hand-edited per-agent or per-server integration left
over. Reviewed, not gated.
 
**Failure-first scenarios** (the suite is built around these, not the happy path): an **unregistered**
service's build pulls config (must resolve **nothing** — no partial, no default — leaving it
unprovisioned); a registration pointing at an unknown/unresolvable pinned Pinax version (the emit must
**fail**, not guess); a stale registration removed (must drop out of the emitted registry on the next
emit); a change to one managed value (must propagate fleet-wide from the one change). Each must produce
the correct emit result — including correctly serving *nothing* to a
non-member and correctly *failing* on an unresolvable reference — with no manual fix-up. _(These test
the emit's membership gate and mechanical integrity, not the correctness of registry contents, which
Pinax does not judge.)_
 
> The fixture format, the assertion harness, and where it runs in CI are build-time setup, confirmed
> at the design session. What is fixed here is the two tiers and that verification targets the emit.
 
### Development — build and verify in milestones (harness first)
 
Pinax does not exist yet — repo, the one mandatory integration, the config/registry format, and the
verification harness all have to be stood up. As with the data-fetching service, the harness is built
**first** and every later milestone is proven against it before the next begins; nothing is "done" on
its first pass. Because Pinax's behaviour is a deterministic build-time *emit*, the rig is simpler than
the sibling spec's (no live agent, no LLM judge) — it asserts emitted artifacts against expected ones.
 
**The shared rig (built at M1, reused throughout):**
 
- A **fixture set** of registered servers — each a registry entry (identity, settings, auth config,
  pinned version) — plus external dependency versions and (negative) unregistered-server cases. Fixtures
  carry **no PHI and no secret values** (only secret-manager *references*), per the Security gate.
- An **assertion harness** that runs the emit over a fixture set and checks the deterministic tier:
  member-gated faithful reproduction, single-source propagation, external-dependency currency, fail-on-
  unresolvable, no-token-material, and the out-of-path invariant.
- **Golden expected artifacts** per fixture, so "faithful reproduction" is an exact diff, and **negative
  fixtures** (unregistered service, unresolvable pin, malformed entry) that must produce *nothing* or a
  *failed emit* — the failure-first scenarios are first-class, not an afterthought.
- A place it runs: **Pinax's own CI**, on changes to Pinax's config/registry (the authoring gate) and
  on the integration's build path.
**The verification loop (every milestone runs through it).** Development is a loop, not a one-shot
build-then-test. For each milestone:
 
1. **Declare expected.** For the milestone's testable output (below), author the golden for each
   positive fixture and the expected *refusal/empty* outcome for each negative case — up front, because
   we control the fixtures and therefore know exactly what a correct emit must produce.
2. **Run the emit** over the fixture set through the same integration a real build uses (no test-only
   emit path — the thing under test is the real one).
3. **Verify the output** against the expected, using the check-types below, at the milestone's stated
   success bar.
4. **On mismatch, fix the emit or the config/registry logic — never the fixture or the golden to make a
   bad emit pass.** This is the load-bearing discipline, the Pinax analog of the sibling spec's "fix the
   tool, never the agent": a fixture or golden changes only when the *expectation itself* was wrong, not
   to paper over a wrong emit. If a green run depends on having loosened a check or edited a golden to
   match a suspect output, that is a defect hidden, not fixed.
5. **Re-run to green**, then extend the fixture set (more servers, more negatives, the next milestone's
   cases) and repeat. The suite only grows; a scenario once green stays in.
**What the emit produces (the testable outputs).** For each *registered* server, build-pull produces a
baked-in config made of distinct, separately-checkable blocks: **(a)** its Agno-consumable connection
config (endpoint/transport, the auth-header wiring, the refresh policy); **(b)** its operational
settings (the role-1 set — caps, timeouts, cache policy, etc.); **(c)** its auth config (registry
endpoint, scope(s), and a secret-manager *reference* — never a value); **(d)** the resolved external
dependency versions it builds against; and **(e)** its entry in the emitted registry (identity +
connect metadata). For an *unregistered* server the emit produces **nothing**. These blocks — not "the
artifact" in the abstract — are what goldens are written for and what each check below inspects. (Exact
field names per block are design-session detail; the blocks and what each must/must-not contain are
fixed here.)
 
**Output verification — how an emitted output is judged correct.** Five check-types, all mechanical and
all able to fail (a check that cannot fail is not evidence — n1 security litmus); each milestone states
which blocks it emits and which checks at what bar constitute its success:
 
- **Exact golden diff (faithful reproduction).** Each emitted block is compared field-for-field to the
  authored golden for that fixture; any drift — a missing field, an extra default, a changed scope,
  a reordered list — fails. The primary positive check, and the direct assertion of "faithful,
  member-gated reproduction."
- **Structural / schema validity.** Each block is valid in the form its consumer needs — the connection
  config is valid single-server `MCPTools` (never `MultiMCPTools`), parseable by the pinned Agno
  version; the registry entry is well-formed — so a faithful output is also a *usable* one.
- **Determinism / reproducibility.** The same fixture set emits identical blocks every run (build-pull
  bakes these into deployable artifacts, so a nondeterministic emit is a defect).
- **Invariant property-checks across *all* fixtures** (not golden-specific): no token or secret *value*
  appears in any block (only references), and no block contains a runtime/boot-time callback to Pinax
  (the out-of-path invariant). These hold for every emit, positive or negative.
- **Negative outcomes are asserted, not just absent.** An unregistered service must emit *nothing*; an
  unresolvable pin / malformed entry must *fail the emit*. The harness asserts the refusal happened and
  that no partial block leaked — "no output" is a pass only when the check could have wrongly produced
  one.
**Ordered milestones (each built and run through the loop above until green before the next).** Each
states its **testable output** — the concrete thing produced that the harness inspects — and **success**
— the exact pass condition on that output. Where a milestone's output isn't an emit (M0, M1), the
testable output is named accordingly.
 
- **M0 — Identify the external dependency set.** *Build:* enumerate, against the real stack, which
  external dependencies are in the shared set Pinax manages versus left to each server's own discretion
  (the role-5 examples are illustrative, not the final list). *Testable output:* the written set — every
  dependency classified external (Pinax-managed) or internal (server's own), plus the rule that decides
  the class. *Success:* every dependency in the real stack is classified with none left unclassified,
  and the rule is precise enough that a new dependency can be placed without a judgement call. (A
  completeness/unambiguity check on a deliverable, not an emit test.)
- **M1 — Harness first.** *Build:* the fixture format, the assertion harness, golden + negative
  fixtures, and the CI wiring. *Testable output:* the harness's verdict — pass/fail plus *which* check
  failed — on a set of **planted** fixtures whose correct verdict is known in advance. *Success:* every
  planted known-good fixture passes, every planted known-bad fixture fails **on the specific check that
  should catch it** (the harness discriminates *and* localizes). A harness that passes a planted-bad
  fixture, or fails on the wrong check, is itself the defect. (This tests the test before any real emit
  is trusted.)
- **M2 — The emit for one server, end to end.** *Build:* the config/registry format and the one
  mandatory integration far enough to emit one server's config via build-pull. *Testable output:* for
  one registered fixture server, blocks (a)–(e) as baked in; for one unregistered fixture, whatever the
  emit produces. *Success:* the registered server's five blocks each exactly match their authored golden
  (faithful), the connection block is structurally valid/usable, and no block contains a secret value
  (reference only); the unregistered server emits **nothing** — no partial block. Both asserted by the
  harness, not by eye.
- **M3 — The inverted pin (Pinax-produced lockfile) across versions.** *Build:* central version
  dictation keyed on server identity — Pinax produces each server's lockfile (the whole set: external
  deps + the Pinax library), the build resolves against it. *Testable output:* the version set in block
  (d) of each server's emit (sourced from its Pinax-produced lockfile), captured **before and after** a
  single central version change; plus the emit result for a server whose dictated set references an
  unresolvable version. *Success:* before the change every server's lockfile/emit shows the old version;
  after changing it in **one** place and re-emitting, the whole fleet's next build shows the new version
  (fleet-wide from the one change); a server resolves no version other than its dictated one; and the
  unresolvable-version case **fails the emit** rather than guessing or defaulting.
- **M4 — Full deterministic tier + failure-first suite.** *Build:* turn on every check-type and the
  whole negative suite. *Testable output:* the suite's full result matrix over all positive and negative
  fixtures, plus a second identical run. *Success:* all five check-types green on positives; each
  negative fixture yields its correct outcome (unregistered → nothing, unresolvable/malformed → failed
  emit, stale registration → dropped from the registry block, single managed-value change → propagates
  fleet-wide from the one change); the re-run is byte-identical (determinism); and the
  cross-fixture invariants (no secret value, no callback to Pinax) hold on **every** block. "Green"
  explicitly includes the correct refusals.
- **M5 — First real member: the data-fetching service (auth-independent).** *Build:* register the real
  data-fetching server and emit its config through Pinax (applying the Sibling-spec corrections). This
  includes emitting the auth-config block (c) — the registry endpoint, scopes, and secret-manager
  reference — *as config*; it does **not** exercise live auth against Eyad's registry (that is the
  separate Auth milestone). *Testable output:* the data-fetching server's **real** emitted blocks, and
  the deployed server's boot behaviour with Pinax unreachable. *Success:* it is registered and its real
  emit gives it blocks (a)–(e) with **no self-pinned version and no private config**; and the deployed
  unit **boots on baked-in config with Pinax down** — proving the out-of-path invariant on a real
  artifact, not just asserting it on a fixture. (Authenticating and serving real data is the Auth
  milestone, below.)
- **M6 — Base Helm chart + deploy (auth-independent).** *Build:* create the shared base Helm chart (in
  scope, infra-layer, not owned by Pinax) and have the first member build its chart on it. *Testable
  output:* a member actually deployed via a chart built on the base, and the provenance of the secret —
  value vs. reference. *Success:* the member deploys via a chart that inherits the base; the secret
  **value** is delivered at deploy by Helm/the secret-manager while Pinax's emitted block (c) carried
  only the **reference** — the Pinax↔Helm boundary proven in practice, with Pinax holding/emitting no
  secret value. (Deploy mechanics and the boundary only; live auth is the Auth milestone.)
- **Auth — live integration with the trusted-services registry (separate, out-of-band, gated on Eyad).**
  Everything above is built **auth-independent**: Pinax emits auth *config* (the block-(c) shape) as
  ordinary config, but live token obtain/validate against Eyad's registry is walled off here. **No work
  happens on this milestone until Eyad's registry is live and Pinax is registered in it** — it is not a
  fixed position in the M0–M6 sequence but a separate track triggered by that readiness; the rest of the
  build does not wait on it. *Build (when unblocked):* wire the emitted auth config to the live registry
  and exercise it end to end — a real member obtains a patient-scoped token, the server validates it, and
  real data is served. *Testable output:* a deployed real member authenticating via the registry and
  serving. *Success:* end-to-end auth works against the live registry, default-deny on missing/expired/
  over-scoped tokens holds (server-side), and the config Pinax emitted needed no change to light up —
  confirming auth was a clean seam built around, not retrofitted.
**Critical path & external dependencies.** The sequence is built so that nothing core waits on another
team. **M0–M4 is fully self-contained** — fixtures only, no external system (no Eyad, no base chart, not
even live Agno), so Pinax is *fully proven on invented data* before any dependency lands. **M5–M6** add
the first real member and real deploy but are **auth-independent** by construction: they emit real config
(including auth config *as config*) and prove boot/deploy/boundary without live auth. The base Helm chart
M6 needs is in-scope-to-create (infra-layer). Live auth is the **only** thing gated on an external team
(Eyad's registry) and is walled into its own out-of-band milestone, worked only once that registry is
live. So the two external dependencies (Eyad's registry, the base chart) gate only the tail, never the
core.
 
The build-time **design session** (the external dependency set of M0, the Agno version pin, the registry
interface and token-attachment mechanism, the exact config/registry and lockfile schema) feeds M0–M3 and
is normal kickoff, not a spec gate — the architecture, roles, and boundaries above are already settled
here.
 
## Acceptance criteria
 
Pinax is accepted when all of the following hold. Each maps to a Verification check (the emit tiers),
a principle, or a gate.
 
**Function — the five roles work end to end:**
 
- A new MCP server is **registered** with Pinax and, with no hand-written per-server integration code,
  becomes available to Agno: present in the emitted registry; correctly configured (as single-server
  `MCPTools` config — never `MultiMCPTools`); correctly auth-wired; and built against the dictated
  external dependency versions. (How agents are composed from the available servers is Agno's, not
  Pinax's.)
- **Settings and auth config have a single authoritative source** (the Pinax repo); a change to either
  propagates from that one place to the whole fleet on the next build (fleet-wide by nature).
- **External dependency versions are managed centrally**; a version bump propagates from one place so
  the fleet stays current with the evolving external world — servers are isolated, with no dependency on
  one another, and their internal/own dependencies remain their own.
**Structure — split polyrepo + inverted pin:**
 
- Each MCP server is **its own repo** importing the Pinax library; it carries no private config and
  self-pins no versions.
- The entire version set a conforming server builds against — the Pinax library, Agno, the MCP SDK,
  shared N1 libraries — is **dictated by Pinax's central config** (the inverted pin), keyed on server
  identity and delivered automatically by registration as a Pinax-produced lockfile; a conforming server
  self-pins nothing because it does not have to. (Going off the sanctioned path to self-pin is
  off-policy and unmanaged, not a build Pinax fails; Principle 5.) Pinax's emit fails on a registration
  referencing an unknown/unresolvable version rather than guessing.
**Boundaries — out of the path, build-time only:**
 
- Pinax is **not involved in starting or stopping** MCP server processes (that is the K8s/Helm deploy
  path); a deployed server/agent boots and runs on **baked-in config**, and the running fleet depends
  on Pinax **nowhere** (Pinax can be down with no runtime effect).
- Pinax is demonstrably **out of the data call path** and **never holds, brokers, or mints a token**.
- Runtime observability is Agno's; Pinax ships **no runtime telemetry layer** (only build-time emit
  provenance in the pipeline).
**Emit correctness (Verification deterministic tier holds):**
 
- The emit is a **complete, member-gated, faithful reproduction** of Pinax's registry: config is
  produced only for registered services (a non-member resolves nothing — unprovisioned, never a
  default), and a registered service's artifact reproduces exactly what the registry holds, with no
  partial or filled-in default. The emit **fails rather than guessing** on an unresolvable reference
  (e.g. an unknown pinned version). No token or secret *value* appears in any emitted artifact (only
  references). _(Pinax does not judge the correctness or safety of the registry's contents — that is
  the maintainer's, authored and reviewed in Pinax's repo.)_
**Principles and gates:**
 
- **All five principles hold under review:** Pinax owns configuration and never executes in the path
  (1); it manages or doesn't touch — nothing it provides is merely advisory (2); it does not reinvent
  Agno's work (3) or reason about consumer behaviour (4); and it conforms servers by ease and policy,
  never by gating (5).
- The **Security gate** is satisfied: config reaches only registered services (membership gate), no
  token handling, no token/secret value in any artifact, server-side enforcement and default-deny at
  runtime, and blast radius bounded by authoring + deploy review. The **Clinical-accuracy gate** is
  `N/A` as stated.
- **Verification** passes on its own bar: the emit suite (deterministic tier asserted, failure-first
  scenarios producing the correct emit result including correct refusals) is green.
## Clinical-accuracy gate
 
**N/A — Pinax is configuration/build-time infrastructure.** It does not generate, interpret, or alter
any clinical content, returns no data, and is not in the data path; clinical correctness is owned by
the MCP servers and upstream. Pinax *does* configure the auth that gates PHI access — that risk is
owned in the Security gate, not here.
 
## Security gate
 
Pinax touches auth configuration, so this gate is in scope even though Pinax never holds a token.
 
- **Boundary.** Pinax manages auth *configuration* (registry endpoint, scopes, `header_provider`
  wiring); it never holds, brokers, stores, or mints a patient token. The token exists only between a
  server/agent connection and the registry, and is validated by each server independently.
- **The risk Pinax owns** is narrow: that its config reaches only **registered** servers, so a random
  MCP someone stands up cannot inherit the fleet's auth wiring and setup just by pointing at Pinax.
  Control: **registration is service-level acceptance**, and build-pull serves config only to a service
  whose identity is on the register. A service is accepted once (added to Pinax's registry); thereafter
  its builds pull config. An unregistered service's build resolves **no** config — no auth wiring, no
  scopes, no listing — so it is simply unprovisioned, never accidentally set up. ("Visit the office
  first.") This is membership presence, not a credential the build presents.
- **What this control is and isn't.** It is a least-surprise / least-privilege gate against *accidental
  or unsanctioned pickup* of fleet config — not a boundary against a hostile server. The correctness of
  a registered service's config *contents* (scopes, audience, endpoints) is the **registry maintainer's**
  (authored in Pinax, trusted, not re-checked by Pinax); and the real defense against a malicious caller
  is **server-side: each server validates the real token at runtime** (next bullet) regardless of any
  config it holds. Pinax gates *who gets set up*, not *who gets access*.
- **Enforcement lives server-side.** Read-only, patient scoping, and token validation are enforced at
  each MCP server (and in the token's scope), never by Pinax and never client-side. Pinax cannot widen
  a scope at runtime because it is not in the path.
- **No token or secret material in config.** What Pinax serves is configuration that *points at* where
  execution obtains secrets (a secret-manager reference, the registry endpoint) — never a token, OAuth
  client secret, or other credential value. Asserted by the no-token-material check in Verification
  (the litmus "report paths, not values").
- **Fails secure — unprovisioned, not permissively provisioned.** The failure mode is a service that is
  **not registered**: its build resolves no config, so it is **unprovisioned** (no auth wiring at all) —
  it never falls back to a default or broader setup. And a deployed server that ends up with no valid
  auth config must **deny** at runtime, never fall back to a broader credential (server-side, the
  data-fetching model). Both directions fail toward *no access*, never toward a permissive default.
- The fleet-wide-token-broker model was considered and **rejected** on security grounds (single
  high-value PHI-token store; caller-asserted identity / IDOR). _(Principle 1.)_
## Open questions
 
Only two items are genuinely open, both external — no open design decisions remain.
 
1. **Trusted-services registry (Eyad's)** — must be live and Pinax registered in it; hard cross-team
   dependency, tracked separately (shared with the data-fetching service). Gates only the Auth
   milestone, not the core build (see Development → Critical path).
2. **Agno + registry specifics, confirmed at the design session** — the Agno version pin; the
   `header_provider` token-attachment behaviour and the registry's token interface (passthrough vs.
   exchange, patient-scope claim shape); handling of the reconnection `CancelledError` issue. These are
   field-level confirmations against live systems, not open decisions.
_Resolved here, recorded so they are not reopened:_ the **delivery mechanism** (build-pull, MCP-side
integration — Approach → The delivery mechanism); **Agno-config ownership** (yes — Pinax owns each
server's Agno-consumable config; role 3); **observability** (delegated to Agno; Pinax owns only
build-time emit provenance — Approach → Observability); **integration placement** (MCP-side); and the
**inverted-pin mechanism** (a Pinax-produced lockfile dictating the whole version set — Approach →
Repository structure).
 
## Sibling-spec corrections (data-fetching service, apply on its next edit)
 
These are edits to the data-fetching service *spec* — documentation, not a migration or code retrofit
here.
 
- Drop `MultiMCPTools` everywhere; use multiple `MCPTools` instances.
- Soften / correct the "Agno does not auto-reconnect" claim: Agno reconnects at the run boundary
  (`refresh_connection`) and establishes authenticated sessions (`header_provider`); what it lacks is
  mid-run retry/backoff, plus the known `CancelledError` propagation bug.
- Incorporate Pinax adoption: the data-fetching server is registered in Pinax and gets its config,
  Agno wiring, and auth setup through the Pinax integration (build-pull, inverted pin) rather than
  wiring these itself; its repo carries no self-pinned Pinax version or private config. (The server's
  charter, governed-door posture, and per-server repo are unchanged.)
 
