# Integrate Model Management Microservice into your application **Audience:** application developers and coding agents integrating a shared model catalog into an existing application's model-management directory. This guide does not require a particular UI framework or redesign of your application. **Desired onboarding:** generate a Model Management API token → configure it securely in the new app as `MMM_Token` → give your coding agent this guide and the SDK link → integrate with the existing model-management layer → verify behavior before enabling rollout. ## 1. Read the release boundary first This guide is implementation-aligned preparation, **not a claim that onboarding is already available in production**. The inspected API/SDK contract is the source at commit `c9f051355feb8648c5107d0058142bd02bdbb6c9`; documentation examples are tested separately with synthetic data. Recheck the release you actually install. | Capability | Current evidence / gate | | --- | --- | | Catalog read API and TypeScript SDK | Implemented and locally tested; full acceptance/hosting remain open. | | Developer token generation, scopes, expiry, rotation and revocation | **Token issuance and server-side token validation are not implemented** in the inspected read API. No token page or mint endpoint is documented as working. | | Token-enabled client transport | The executable example attaches `Authorization: Bearer` using `MMM_Token`, with origin/method/redirect restrictions. This does not add authentication to the server. | | Hosted API | Intended origin is `https://market-context.org`; a live deployment is not verified by this guide. Confirm the approved environment before sending credentials. | | SDK distribution | **No published npm SDK package is verified**. The repository package is private; do not guess an npm package name or install command. | | End-to-end consumer integration | Pending the completed app, token feature, approved SDK distribution and live integration rehearsal. | The current read API is anonymous. A 200 response with a Bearer header does **not** prove that the token was checked. An invalid token must fail protected/token-specific routes in a future token-enabled release before that onboarding path can pass its authentication gate. Do not use a Supabase service key or invent a token to work around unfinished issuance. ### Recommended access policy (proposal, not a new server feature) Use anonymous access for public catalog metadata, with rate limits, ETags, bounded signed snapshots and caching. Mandatory credentials add integration/rotation burden without making already-public data confidential. Optional per-app tokens can later provide attribution or differentiated quotas if those features are approved and built. They are not implemented benefits today, nor a requirement for current public reads. Always authenticate privileged maintenance/role operations, enforce MFA for privileged users, and preserve exact-digest human approval for publication. A consumer token must not double as a portal administrator credential. If a future hybrid API has both public and token-specific routes, test them separately: rejection on protected routes does not mean a caller is forbidden from reading the independently public catalog. The guide retains the requested **token-enabled onboarding** below as a release-gated option. To exercise current anonymous reads, skip token generation and use the explicit `createAnonymousMmmClient` example in section 5. Selecting the token factory with a missing token fails—it never silently downgrades to anonymous access. No server access policy is changed by these documentation examples. ## 2. What Model Management does—and does not—own Model Management Microservice supplies reviewed catalog metadata: providers, models, hosted offerings, provider identifiers, capabilities, parameter rules, limits, pricing and lifecycle. The SDK verifies signed snapshots and supports persistent cache and app fallback. Your application still owns: - Provider inference calls, API credentials and authentication to each model host. - Account entitlement, actual regional availability, routing and adapter support. - User settings, presets, local/private model discovery and application policy. - Billing, markup, budgets and enforcement; catalog prices are not an invoice. Model Management API tokens are **catalog access credentials**, not provider inference keys, Supabase Auth sessions/service keys, database passwords or signing private keys. This integration must not publish catalog changes or grant portal administrator roles. ## 3. Generate and store the API token (release-gated) When the token-enabled product is released: 1. Sign in to the approved Model Management environment and use its documented token-generation flow. A working UI path/endpoint will be linked by that release; it does not exist in this inspected implementation. Do not assume a button name or mint URL. 2. Generate a separate application credential for each app/environment. Request only the read permissions needed for the catalog. Do not request publication or admin authority for an ordinary consumer integration. 3. Capture the token through the product's secure issuance flow and immediately place it in your application's server-side secret store. Do not paste it into an agent prompt, repository issue, screenshot, log or committed file. 4. Use expiry and rotation according to the released token policy. Treat the secure lifecycle (one-time display, least-privilege scopes, expiry, next-request revocation and rate limits) as acceptance requirements—not already delivered behavior. Use exactly this case-sensitive environment variable: ```dotenv MMM_Token=[api-token-from-model-mgt-microservice] ``` Replace the entire bracketed placeholder with the issued token through your secret manager. Do not commit the resulting file. Do not rename it to a client-exposed `VITE_`, `NEXT_PUBLIC_` or similar variable. Frontend applications should call their own backend, which holds the token and exposes only the metadata the UI needs. CORS does not make a browser-embedded credential safe. Optional **application-side** configuration used by the example: ```dotenv # Intended origin only; confirm the approved live environment first. MMM_ORIGIN=https://market-context.org # Use a durable, app-owned file outside tracked source in the real environment. MMM_CACHE_PATH=./.cache/model-management/catalog.json ``` These two names are example app settings, not automatically read SDK options. The adapter passes them to the SDK. Ensure your runtime/secret manager actually injects the variables: Node does not load a `.env` file just because it exists. Never log the environment or include a credential in a URL, query string, model ID or cache file. ## 4. Give your coding agent the SDK and integration brief ### Canonical links - [SDK source](https://github.com/Savagecode100/model-mgt-microservice/blob/main/src/sdk.ts) — `ModelCatalogClient`, `MemoryCache`, `ClientOptions`, `CatalogView`, cache interfaces. - [Persistent cache source](https://github.com/Savagecode100/model-mgt-microservice/blob/main/src/file-cache.ts) — `FileCache`. - [Schema/contracts](https://github.com/Savagecode100/model-mgt-microservice/blob/main/src/contracts.ts) and [validation](https://github.com/Savagecode100/model-mgt-microservice/blob/main/src/validate.ts). - [API description source](https://github.com/Savagecode100/model-mgt-microservice/blob/main/src/openapi.ts). A running API exposes `GET /openapi.json`; do not assume the intended host is live. - [Executable integration example](examples/mmm-client.ts) and [local integration-example tests](../tests/developer-integration.test.ts). Repository access may be required. These are source links, **not a standalone CDN bundle or proof of public package availability**. Pin an approved release/commit and verify its license/distribution permission. `sdk.ts` imports other modules; copying that file alone is not an installation. Do not run an invented `npm install` command. Until a supported SDK package is published, use an authorized source checkout for inspection and local testing, or an explicitly approved vendored/workspace build. Update imports to that distribution and verify its public exports. The example's relative imports are intentionally for testing inside this repository. ### Agent handoff (copy without secrets) > Integrate Model Management Microservice into this application's existing model-management directory. > Read this guide, the SDK source and contracts linked above. Inspect the current > model catalog, provider adapters, presets, lifecycle and pricing paths first. > Use an approved pinned SDK distribution; report if none is available. Keep the > secret server-side as `MMM_Token`; do not request or print its value. Add an > origin-restricted token fetcher through the SDK's existing `fetcher` option—there > is no current `apiToken` constructor option. Preserve provider credentials, > inference adapters, user overrides, current model selections and app-owned fallback. > Add signed-snapshot verification, persistent cache, explicit metadata mapping, > lifecycle handling and tests. Never bypass signature validation or fabricate > support/pricing. Keep rollout disabled until token enforcement and end-to-end > acceptance pass. Report actual test evidence and remaining gates. ## 5. Integrate inside your model-management directory Keep your current directory names. For example only: ```text src/model-management/ mmm-client.ts # token transport + one long-lived SDK client per worker trusted-catalog.ts # approved public verification keys/source-host allowlist catalog-mapper.ts # Model Management metadata -> existing application's types fallback.ts # app-owned validated fallback, not downloaded unchecked JSON model-service.ts # app-facing reads/selection, independent of provider inference ``` The [tested `mmm-client.ts` example](examples/mmm-client.ts) constructs the actual `ModelCatalogClient` with `FileCache`, validates the fallback and requires trusted public keys. For the current anonymous path, call `createAnonymousMmmClient` with the same origin/cache/trust/fallback options shown below, omit `environment`, and do not configure a token-bearing fetcher. That factory never reads `MMM_Token` or creates an Authorization header. It still verifies signatures and preserves fallback/cache safety. For future token-enabled access, `createMmmClient` adds the token through a custom `fetcher`. Its transport: - Allows only GET/HEAD under `/api/v1/` on the configured bare HTTPS origin. - Rejects URL user-info (username/password), non-bare origins and paths that escape the catalog API. - Sets `Authorization: Bearer ${MMM_Token}` and `Accept: application/json` without putting the token in the URL, catalog or persistent cache. - Preserves request signals and conditional headers; rejects redirects and omits browser cookies. A snapshot pointing at a different origin is also rejected by the SDK. - Rejects a missing token, the literal placeholder and whitespace/control characters. The proposed Bearer transport follows the intended token onboarding convention. It **does not validate the token**, implement issuance or replace the server's future scope/expiry/revocation checks. The tests use a non-credential synthetic token. Construct the client in a **server-side composition module** after loading your app's approved keys, fallback and source-host allowlist. This wiring outline uses the example adapter; the imported app configuration must be supplied by your application: ```ts import { createMmmClient } from './mmm-client.js'; import { approvedPublicKeys, allowedSourceHosts, fallbackCatalog } from './trusted-catalog.js'; export const modelCatalog = createMmmClient({ origin: process.env.MMM_ORIGIN ?? 'https://market-context.org', cachePath: process.env.MMM_CACHE_PATH ?? './.cache/model-management/catalog.json', environment: process.env, // reads MMM_Token; never log this object trustedKeys: approvedPublicKeys, validation: { allowedSourceHosts }, fallback: fallbackCatalog, }); ``` `approvedPublicKeys` is a `Map` containing approved **public** Ed25519 keys (for example, constructed with Node `createPublicKey`). Obtain keys through a separately trusted release/configuration channel, not from an unverified manifest. Key IDs must match the signed release. `allowedSourceHosts` contains approved documentation-source hosts, not simply the API origin. No private signing key belongs in a consuming app. The persistent file must survive a restart and be writable by the app. Keep it out of source control. Confirm your platform's filesystem/locking semantics; this is not a distributed network-filesystem cache guarantee. A browser requires a separate backend/service boundary, not `FileCache` or Node cryptography bundled into the UI. ## 6. Read, map and use the catalog safely The current SDK API is: ```ts const view = await modelCatalog.get(); // view: catalog, source, release_id, age_ms, warnings // Read-only input to your mapper; do not mutate the shared catalog in place. ``` `get()` tries verification/refresh on first use, then uses the SDK's cache/scheduling. `refresh()` forces a refresh and returns a boolean, not a catalog or detailed HTTP error; do not call it on every inference request. A download has one shared 1.5s default timeout across manifest/snapshot requests (`timeoutMs` overrides it). On success the next refresh is due after `min(900, refresh_after_seconds)` seconds with 0.9–1.0 jitter; failure schedules 30s before the next get-triggered attempt. There is no autonomous background timer. Routine stale grace defaults to 7 days; pricing grace is 1 day via `get({ pricing: true })` and `quote()`. Configure `routineStaleMs` and `pricingStaleMs` explicitly if your application needs different bounds. Sources are `remote`, `last_known_good` or `app_fallback`. **`remote` can mean verified content restored from disk, not necessarily a successful network request just now.** Use `age_ms`, `warnings` and separately checked service health rather than displaying a misleading “online” badge. The current SDK's age calculation uses the older of verification time and snapshot creation time; re-fetching an old unchanged release is not a guarantee that it remains within the 7-day grace window. App fallback has null `release_id`; `age_ms` can be null or the age of an expired cached release. Monitor `source` and warnings, not just age. The SDK returns the catalog without filtering retired offerings: call `lifecycle(offeringKey)` and enforce the app's routing/selection policy. There is no `include_retired` SDK option. `ClientOptions` has no `channel` option; the SDK reads the current stable manifest. ### Mapping checklist - `model_key` identifies a model; `offering_key` identifies its hosted offering. Provider-call identifiers live in `identifiers[].api_id`; neither catalog key is automatically a callable provider model name. - Preserve alias/pinned semantics. Do not replace a user's pinned choice with a new alias target without the application's normal selection policy. - Keep provider adapter support and account entitlement separate from catalog presence. `integration_level: catalog_only` is not proof that your SDK supports the offering. - Apply capability support states and `parameter_rules` conditions explicitly. Conditional defaults, required beta headers and invalid-behavior rules are not universal instructions. Keep user overrides and preset policy app-owned. - Unknown/null limits are unknown—not zero or unlimited. Preserve units and conditions. - Honor lifecycle events and retirement. The SDK retains a ledger and exposes `lifecycle(offeringKey)`; it does not filter `get()` or block `quote()` automatically. Your app must enforce routing, selection and history/preset policy. Independent recovery of retirement/high-water state remains a wider SDK acceptance gate. - Keep app fallback validated and versioned. Never replace it with unverified API JSON. Test lifecycle behavior during outage and cache loss; fallback is not permission to resurrect retired offerings or silently switch provider credentials. ### Pricing Use `modelCatalog.quote(offeringKey, usage, context)` for catalog estimates. Usage values are decimal strings keyed by metric, such as `uncached_input_tokens`. The quote returns `status` (`known`, `incomplete` or `ambiguous`), `total_usd`, `known_subtotal_usd`, `lines` and `reasons`. A catalog's partial/unknown coverage yields an incomplete estimate; `total_usd` stays null even when a known subtotal exists. Never relabel the subtotal as a full quote or convert null/unknown pricing to zero. Condition-dependent rules need caller context; overlapping matches can be ambiguous. Catalog pricing does not include your app's markup, credits or provider account terms. ## 7. HTTP reference and troubleshooting Base origin and API prefix are separate: give the SDK the **bare HTTPS origin**; it appends `/api/v1/...`. Do not pass an origin ending in `/api/v1`. | Implemented GET route | Purpose | | --- | --- | | `/health/live` | Process liveness; not a token-validity check. | | `/health/ready`, `/health` | Readiness; verifies current manifest/artifact. `/health` is a readiness alias. | | `/api/v1/manifest` | Current stable manifest; conditional ETag supported. No channel query option. | | `/api/v1/releases/{release_id}/snapshot` | Immutable verified snapshot bytes; UUID release ID. | | `/api/v1/models`, `/api/v1/models/{model_key}` | Model listing/detail with related offering metadata. | | `/api/v1/offerings/{offering_key}` | Offering detail; there is no offerings-list route. | | `/api/v1/changes?from_release={uuid}&to_release={uuid}` | Directional release diff; supply both UUIDs, not `since`. Current API does not reject reversed order. | | `/api/v1/releases` | Paginated release history. No separate release-detail route. | | `/openapi.json` | Runtime API description (not under `/api/v1`). | Inspect OpenAPI and the API source for exact query/envelope schemas. Models and release history use `limit` (1–100, default 50) and `next_cursor`; **there is no `has_more` field**. Continue while next_cursor is non-null. Follow the opaque cursor unchanged, keeping filters/limit fixed; the server binds the relevant filters and anchors model listing to a release. Do not synthesize cursors. Responses identify `release_id`/`sequence_no` so the app can notice mixed-version reads. Model listing and model/offering detail accept `release_id` to pin reads; unknown pins return 404. The frontend pins listing and details to the same manifest release. Immutable signed snapshots remain the SDK's atomic/verified integration path. Model listing filters: `q`, `lab`, `input`, `output`, `capability`, `maturity` (default stable) and `lifecycle` (default active), plus `release_id`, `cursor` and `limit`. There is no `include_catalog_only` or `include_retired` query flag. Model/detail/list query schemas reject unknown keys; the manifest handler currently does not validate query parameters, so an ignored parameter is not evidence of supported behavior. Current API outcomes include 200/304, 400 (bad query/cursor), 404 (missing resource), 413 (URL longer than the 4096-character guard), 429 (rate limit with Retry-After) and 503 (not ready, artifact unavailable/corrupt or other service failure). There is no current 422 reversed-diff response or explicit oversized-snapshot 413 response. Keep client-side signed-size limits; do not assume a server rejection that is not implemented. Token-specific 401/403 semantics and enforcement are **future acceptance gates**, not current API behavior. Don't equate an SDK false refresh result with a particular HTTP error; use a bounded diagnostic request that reports status only, never credentials or full request objects. | Symptom | Check / safe response | | --- | --- | | Missing token/config error | Verify case-sensitive server-side `MMM_Token`, injection and placeholder replacement. Never print the value. | | Token-like header gets 200 even when invalid | Current anonymous API, not successful authentication. Block token-enabled acceptance. | | 404 on every SDK call | Verify bare origin and deployed routing; don't double `/api/v1`. | | 429 | Honor Retry-After/backoff; avoid per-request forced refresh loops. | | Failed signature or unknown key | Check approved public-key ID/version; reject the candidate. Never disable verification. | | Digest/size/schema/source-host mismatch | Keep verified cache/fallback and investigate; don't loosen the trust policy to pass a test. | | Lost cache after restart | Check durable path, permissions, mount and filesystem support. | | New model missing or not callable | Check approved release/lifecycle and app adapter/entitlement, not just catalog presence. | ## 8. Verification and rollout checklist ### Local evidence supplied with this guide `tests/developer-integration.test.ts` imports and typechecks the executable adapter. It tests anonymous reads without a token/header, opt-in header injection, missing/ placeholder rejection, no cross-origin/write forwarding, redirect/cookie policy, signed snapshot verification through the real SDK, persistent recovery, pricing and fallback on simulated failures/tampering. In-process tests also exercise the actual API's documented routes/envelopes and demonstrate its current anonymous behavior. No live deployment, token issuance, consumer app or provider inference is involved. Synthetic 401/403 responses test client failure handling, **not server authentication**. Repository commands: `npm run typecheck`, `npm test -- tests/developer-integration.test.ts`, and `npm run verify`. Build with `npm run build`. Running the consumer's own tests is still required after adapting imports/mapping; passing repository examples alone is not an end-to-end integration certificate. ### Run against the completed product before enabling integration Record whether the approved integration uses public anonymous reads or a released token-specific capability. For anonymous reads, mark token-issuance/enforcement items not applicable with that reason; do not use anonymous success to complete the separate token feature. All trust, fallback, mapping and consumer acceptance gates still apply. - [ ] Confirm an approved live origin, actual release/commit and SDK distribution/license. - [ ] Generate a real app token through the released flow without retaining it in evidence. - [ ] Valid, scoped token succeeds; missing/invalid/expired/revoked token fails; insufficient scope is denied. Verify rotation and old-token rejection on the next request. - [ ] Token stays server-side and is absent from browser bundles, logs, URLs and cache files. - [ ] Verify real signed release, trusted-key rotation and rejection of untrusted keys/tampering. - [ ] Map models/offerings/identifiers/parameters/limits without losing existing user choices. - [ ] Test cold start, last-known-good use, timeout, 429, offline restart, corrupt/lost cache and fallback; record lifecycle/retirement outcomes, not merely “app still loads”. - [ ] Verify pricing unknown/partial outcomes and keep routing/billing/entitlement app-owned. - [ ] Exercise staging rollout with the application's actual model-management directory; run its unit/integration/security checks and review any UI changes. - [ ] Verify rollback to the app's existing model source without erasing settings or secrets. - [ ] Record sanitized target, commit/package version, date, commands and results. No token, private key, user PII or provider credentials in the report. Enable only after approval. ## 9. Turn the integration into a skill After the first integration passes, turn its repeatable process into a reusable agent skill (for example, a `SKILL.md` adapted to your agent's supported format). Include: when to use it; this guide and pinned SDK links; discovery of the app's model-management directory; required `MMM_Token` **name, never value**; secret/trust boundaries; approved distribution/import steps; mapping/cache/fallback/lifecycle checks; rollout/rollback gates; and evidence to report. The skill should inspect before editing, preserve existing app conventions and refuse to invent missing endpoints, SDK packages, provider capabilities or passing tests. Keep release-specific commands versioned and revalidate them when the SDK or token contract changes. A skill is an integration runbook, not permission to bypass human approval, expose secrets or auto-enable an unverified deployment.