npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

runbios-mcp

v0.6.1

Published

Run BiOS MCP server — train and deploy AI models from MCP-compatible automation clients

Readme

Run BiOS MCP server

The MCP server exposes the authenticated Run BiOS training and model-serving control planes to MCP-compatible automation clients. This build registers 126 tools when every surface is open; get_platform_guide derives its inventory from what is actually registered so its count matches the wire (tools/list).

PRE-LAUNCH: while the coming-soon gates are on (the default — see src/config.ts), the three creation tools (create_training_job, upload_dataset, import_huggingface_dataset) are not registered, and read and lifecycle tools, including dataset mapping/revalidation/source/integration maintenance, remain available. A production organization holding the training beta grant opens both creation gates for its own MCP session. Local API-key mode resolves the bound organization automatically through key introspection, so RUNBIOS_ORG_ID is optional; otherwise set RUNBIOS_TRAINING_COMING_SOON=false / RUNBIOS_DATASETS_COMING_SOON=false at launch and the registrations return.

THE LOOP GATE: the Conscious Loop is offered only where the platform has opened it. This package does not decide that for itself: at start it asks the API it is pointed at, with your key (GET /api/loop/models). Where the API answers 403 LOOP_COMING_SOON, or has no loop backend at all (503 capability_unavailable, or a 404), none of its 59 loop_ tools is registered — reads included — the platform guide does not mention the loop, and introspect_api_key leaves the loop tools and SDK methods out of what a key holding the loop scopes may call (those scopes read "Conscious Loop: not available on this platform yet"). A key without the loop:read scope (403 INSUFFICIENT_SCOPE) gets no loop_ tools either: it could not call one. Give the key loop:read (and loop:write to change anything) and restart the server. Where the API offers the loop to the key, every loop_ tool is registered with no variable set. Any other answer (a server error, no answer within two seconds) registers them too, and each loop call is then answered by the API with its own code. WHERE THE LOOP IS SWITCHED OFF the API still answers the five routes a member needs to stop paying: list and read pipelines, switch one off, delete one, cancel a training. So where the models probe answers 403 LOOP_COMING_SOON, the package asks once more, GET /api/loop/pipelines?limit=1; when that answers 200 the five tools of those routes are registered (loop_list_pipelines, loop_get_pipeline, loop_update_pipeline with enabled: false only, loop_delete_pipeline, loop_cancel_training_run), each description saying the loop is switched off, and the guide names those five and nothing else of the loop; any other answer keeps the family hidden. RUNBIOS_LOOP_COMING_SOON overrides the probe: false registers the tools, any other value hides them, and nothing is asked. The loop gate has this one name: unlike training and datasets it has no legacy BIOS_* spelling, and the training beta grant does not open it. The hosted server reads the gate from its task definition instead of asking; its task definitions open it in every environment.

So the wire count is 126 with everything open, 123 with training and datasets gated, and 64 where all three gates are closed (69 where the API says the loop is switched off: its five stop-paying tools stay).

Set these environment variables in the MCP client configuration:

{
  "command": "npx",
  "args": ["-y", "runbios-mcp"],
  "env": {
    "RUNBIOS_API_KEY": "bios-...",
    "RUNBIOS_BASE_URL": "https://api.runbios.ai",
    "RUNBIOS_WORKSPACE_ID": "workspace-id",
    "RUNBIOS_INFERENCE_KEY": "sk-bios-deployment-key"
  }
}

RUNBIOS_* is the canonical environment prefix. Platform API keys default to bios-; dashboard-issued custom and provider-shaped prefixes work too, and legacy usf- keys remain valid. The legacy BIOS_* variable names are still accepted as fallbacks.

https://api.runbios.ai is the canonical production hostname. Use https://api-dev.runbios.ai explicitly during dev.

For interactive JWT authentication, omit RUNBIOS_API_KEY and set RUNBIOS_ACCESS_TOKEN. The server never guesses credential type from a prefix: API keys use X-API-Key, while access tokens use Authorization: Bearer.

The inference tools use RUNBIOS_INFERENCE_KEY for a dedicated deployment, or a workspace RUNBIOS_API_KEY whose scopes allow serverless or dedicated invocation through the unified /v1 gateway; no serving credential is accepted as a tool argument or returned in model-visible text. chat_with_inference and message_with_inference work on models that serve the respective OpenAI-chat or Anthropic-Messages dialect. complete_with_inference, embed_with_inference, and rerank_with_inference require a dedicated deployment that advertises the matching task: the serverless pool has no completions/embeddings/rerank routes. Choose by the server's declared model task, not a guess from the name.

Set RUNBIOS_INFERENCE_BASE_URL=https://api-dev.runbios.ai explicitly in dev. The chat tool validates function schemas and matching tool responses. Chat streaming assembles deltas; completions and Messages streaming preserve ordered SSE events in one MCP result (up to 2 MB/4096 events; use an SDK for longer streams). MCP cancellation propagates to HTTP, an error or response echoing the configured key is suppressed, and a dispatched inference POST is never retried automatically. RUNBIOS_INFERENCE_TIMEOUT_MS defaults to 900000 (15 minutes). Caller-provided idempotency headers are forwarded without promising server-side replay/deduplication.

Conscious Loop

What it is

The Conscious Loop keeps improving a model from an app's conversations and the user's feedback. A pipeline is one use case. The app's conversations are saved to it as samples, the user says how each answer did, and when enough samples have feedback a training starts: the model learns from them. Every training is tested before it can go live: on questions from the pipeline's own samples that the model never trained on (the automatic test), and on the user's benchmarks if they add any. A training that does better, or that a member approves, becomes the next version: v1, v2, v3 and on, with no limit. The live version is the version the app gets answers from right now; it answers to the model name loop-<pipeline ID>, and each new version takes that name over. For 30 days after a new version goes live a member can go back to the one before.

The pipeline ID (e.g. support-replies) is made from the pipeline's name when it is created and never changes; the pipeline's Connect page shows it. The sample ID comes back in the reply's X-Loop-Sample-Id header, and feedback names it; it is missing only when the platform is not recording calls just then, and then nothing was saved. A sample ID does not prove the pipeline ID is right: if no pipeline has that ID (misspelt, or the pipeline was deleted), the conversation is not saved under it. If recording is switched on for the model that answered, the call is still recorded the way that model records every call, and feedback on it is then accepted; when nothing records it, feedback on it is refused (first "not recorded yet", then "not found"). loop_stats counts such calls under capture (reason no_pipeline), and loop_list_pipelines shows each pipeline's ID. The pipeline ID is read in lowercase.

The three steps, from an assistant

  1. Send the app's conversations. loop_chat asks a model with the pipeline ID in the X-Loop-Pipeline header and saves the conversation as a sample: it returns answer and sample_id. It is a normal, billed model call. Before the pipeline's first version pass model (the model the app uses now); left out, it asks loop-<pipeline ID>, and while no version is live it answers with a plain sentence saying so.
  2. Say how each answer did. loop_add_signal on the sample_id: good (learned as it is), bad (not learned), or corrected with the right answer in correction (the right answer is learned instead). Feedback sent the instant the answer arrives can reach the platform before the conversation is saved (409 SAMPLE_NOT_YET_RECORDED): loop_add_signal waits 2 seconds and sends it again by itself, up to 6 tries, as the SDKs do. Without feedback, if automatic scoring is on, the judge scores it: the judge is an AI that compares each answer with the right answer, and where nobody gave one, as here, it scores the answer on its instructions alone. 0.8 or more is learned like good.
  3. Use the improved model. Leave model out of loop_chat once a version is live, or call loop-<pipeline ID> from any OpenAI-compatible client: it always answers with the live version.

loop_get_pipeline and loop_list_pipeline_attempts say how each training went and what each version learned; get_platform_guide lists every loop tool in the order a user takes them.

Workspace serverless observability

A platform API key or hosted OAuth grant with analytics:read may use get_serverless_limits, get_serverless_usage_overview, get_serverless_usage_by_model, list_serverless_requests, get_serverless_usage_timeseries, get_serverless_usage_daily and get_serverless_savings. The gateway resolves current workspace access from the credential and stamps it on the request: no tool takes an organization or workspace override, serving key, or per-key usage selector. serverless scope alone authorizes inference, not analytics. The saved RPM/spend settings are read-only; key creation/listing, key-level usage, org-wide totals, and all limit writes stay in the JWT-authenticated console.

Raw request metrics and the per-request log have about seven days of retained detail; get_serverless_usage_daily reads the workspace's full-history daily counters over up to 92 UTC days, counting admitted failures as well as success. The saved workspace RPM cap is not a claim about effective org-tier RPM or remaining headroom. Incomplete responses error rather than presenting zero usage or an unset limit.

What the platform derives (never a tool input)

An MCP client acts on the schema it is given, so the schema must not offer a choice the control plane will reject. These serving settings are SERVER-DERIVED and immutable, and are therefore absent from create_inference / preflight_inference:

  • serving_mode (full / adapter / merged) — from the verified checkpoint's lineage; a catalog base model is served whole.
  • model_task — from the resolved model: chat for an instruct or vision-language model, completion for a base model with no chat template, embedding/rerank for those architectures. Every model in the current catalog resolves to chat, so there is nothing to select.
  • supports_images — from the model's own config, never a caller claim.

They are reported back on the preflight/create/status responses, which is where a caller reads them. Copying canonical_request from preflight into create still works: the echoed derived fields are dropped rather than rejected.

context_length is the one window a caller may narrow. The policy the server enforces is: default min(native max, 262144), falling back to 32768 when the native window is unknown (a model with a smaller native window keeps its own), and the hard ceiling is always the model's OWN native max. No static JSON Schema can express a per-model ceiling, so the tool advertises a 1024-1048576 sanity range and its description names the real authority — model.native_max_context from preflight_inference. An out-of-range value is rejected with the whole policy in the message, not a bare bounds error.

max_seq_length (training) follows the same rule: the platform default is 2048, the hard ceiling is the base model's OWN window, and the authoritative field bounds live in get_training_capabilities (max_length), so the tool advertises the contract's 128 floor and the same 1048576 sanity ceiling instead of the meaningless 10000000 it used to. chat_with_inference's max_tokens is bounded the same way — the real ceiling is the served window minus the prompt.

Spend consent is bounded by what the platform can charge

max_price_hour_cents is the one field that authorizes money: the maximum accepted TOTAL hourly price for the complete GPU count. The control plane has no ceiling of its own — it only refuses a cap BELOW the primary placement's verified price — so z.number().int() alone advertised 9007199254740991, i.e. told an agent that consenting to nine quadrillion cents an hour is a legal request. All five money-bearing tools (preflight_inference, create_inference, update_inference_policy, preflight_training_job, create_training_job) now cap it at 100000 cents ($1,000/hour): the dearest configuration the GPU catalog can book is 8 x B300 at 8280 cents/hour, and the beta serving cap (models up to ~130B total parameters) keeps a deployment inside that ladder, so the bound has an order of magnitude of headroom and still reads as a limit rather than a blank cheque. It is a sanity bound on consent, never a price quote: get_gpu_pricing and the preflight response carry the real numbers, and the rejection message says all of this.

Error text an agent can act on

  • A capacity rejection stays the structured compact JSON below.
  • A model id outside the Run BiOS catalog answers MODEL_NOT_HOSTED and names every route to a valid id (list_models, search_models, ids already returned by list_inferences/list_training_jobs, the console Models page) plus what to do when none of them answer — recovery advice never dead-ends on one tool.
  • A model-resolution failure answers MODEL_NOT_RESOLVED / MODEL_REVISION_UNRESOLVED in the platform's own terms. The upstream mirror's transport error is never forwarded: an agent cannot act on a vendor's 404, and the vendor is not the answer to "why can this not be sized".
  • A workspace-scoped read with no workspace context answers WORKSPACE_CONTEXT_REQUIRED and says the fix is configuration (RUNBIOS_WORKSPACE_ID or a workspace-bound API key), not a retry.
  • An unknown id answers a structured <THING>_NOT_FOUND (INFERENCE_NOT_FOUND, TRAINING_JOB_NOT_FOUND, CHECKPOINT_NOT_FOUND, DATASET_NOT_FOUND, INTEGRATION_NOT_FOUND, BOOKING_NOT_FOUND, or RESOURCE_NOT_FOUND for a path with no id) carrying the id, the resource, the upstream code, and the read that hands out valid ids — never the bare sentence ("Deployment not found") an agent would have to string-match. A 404 on a static endpoint under the same prefix (/api/inference/gpu-options) is never reported as an id that does not exist.
  • FastAPI-shaped bodies ({"detail": ...}) are read as well as {"error":{"message"}}, and a response with no message at all reports the status, the path, and what to do — never a bare BIOS API error 400.
  • No tool result is ever a bare null.
  • get_inference_status adds a derived status_summary (phase, count x SKU GPU, endpoint_usable, queue/GPU state) built only from fields in the same response, so a field that is null before the pod reports is not read as "no GPU" or "no phase".
  • list_supported_architectures labels its rows as manifest provenance. Which build published a row is registry provenance, never the image the platform is running, and the control plane no longer publishes it at all: the public projection drops image_tag, bios_version and manifest_sha256 at the boundary. Internal build references are additionally removed by content from every string of every scope, not by field name: dropping the image_tag key alone left the identical <registry>/<engine>@sha256:<digest> in the free-text notes of 194 training-scope rows, and a rule that matches only a key is defeated the moment the value moves. manifest_provenance reports how many references were redacted and how many rows came from a published manifest — counted from source, the one provenance field that survives the projection. It publishes no build-version or digest counts, because after the projection those could only ever report 0, and a standing 0 reads as "the registry records no build" rather than "this response cannot see one".

Safe inference workflow

  1. get_inference_gpu_options returns inference-fit configurations joined to authoritative deployment prices and stock. Prefer the MODEL-ADDRESSED form (model=<catalog_model_id> — an id from list_models/search_models, optionally revision): the server resolves the model facts (vision-aware) and answers with computed min_gpus, valid_counts, and bookable_counts — the exact minimums the create gate enforces, so client-supplied facts can never understate a minimum. unknown is not treated as available; never offer a count below min_gpus or outside bookable_counts.
  2. preflight_inference validates the exact source, model, GPU, queue, price cap, and wallet-hold terms without creating a deployment or mutating funds.
  3. create_inference uses the same request contract, self-validates the selection against the model-addressed minimums before submitting, and follows BOOK-BEFORE-REVEAL: a non-queued create answers 202 with a booking handle while the GPU is secured on real capacity (30-40 s typical); the tool polls the handle and returns the deployment payload only after the GPU is confirmed. The API's one-time inference_key is deliberately withheld from MCP tool content because that text is model-visible; MCP inference uses the workspace key plus deployment name/id. Create through the console or a direct SDK/API call when an external standalone key is required. A definitive miss returns the standard CAPACITY_UNAVAILABLE stock-miss error with fresh alternatives and NO deployment exists (nothing charged). A selection that can never run at all is refused up front with a permanent code instead (see below). Queueing is opt-in, a maximum total hourly price is explicit, and a GPU alternative is never selected without approval. gpu_priorities backups (1-5 ranked choices) may be supplied on ANY create — they form the after-start replacement ladder; the queue itself stays opt-in.
  4. get_inference_booking polls a booking handle from a long-running create_inference (pending → revealed payload → or the standard 409).
  5. get_inference_status reports durable queue state, provisioning/loading, endpoint readiness, price cap, notification summary, and wallet authorization. An endpoint is live only when the returned status is running. queued_capacity means waiting for stock at zero charge — after a deployment has ever been booked, GPU loss never ends in a capacity failure; it waits and auto-resumes.
  6. get_inference_notifications reports durable lifecycle-email delivery, bounded retries, and operator-visible dead letters.
  7. update_inference_policy, stop_inference, resume_inference, restart_inference, and delete_inference manage the lifecycle.

Standard GPU rejection contract

Training and inference speak ONE GPU rejection shape, with a code that says whether waiting can ever help. The MCP transport serializes every code in the family as compact JSON in the tool-error text, even when zero alternatives exist, so an agent can act on it directly.

| reason | code | HTTP | queue_offered | | --- | --- | --- | --- | | insufficient_stock | CAPACITY_UNAVAILABLE | 409 | true | | model_too_large | GPU_TYPE_TOO_SMALL | 400 | false | | below_model_minimum | GPU_COUNT_BELOW_MINIMUM | 400 | false | | invalid_gpu_count | GPU_COUNT_INVALID | 400 | false | | gpu_unsupported | GPU_TYPE_UNSUPPORTED | 400 | false |

CAPACITY_UNAVAILABLE is the ONLY transient one: the GPU is not free right now, so retrying later or joining the queue can succeed (training also echoes the deprecated SELECTED_GPU_UNAVAILABLE as legacy_code for one release). The four 400 codes are permanent facts about the request itself, so the queue is never offered for them and resending the same gpu_type/gpu_count can never succeed. Branch on retryable_as_submitted (or queue_offered) rather than on the message text.

{
  "code": "GPU_TYPE_TOO_SMALL",
  "status": 400,
  "reason": "model_too_large",
  "message": "This model does not fit on L40_48GB, at any GPU count.",
  "recoverable": true,
  "retryable_as_submitted": false,
  "instruction": "This GPU cannot run the request as submitted, and free capacity will never change that. Retry the same call with gpu_type and gpu_count set to one of available_gpus, never below that entry's min_gpus. Do not set allow_capacity_queue, and do not send the same gpu_type and gpu_count again: neither waiting nor the queue can make this request fit.",
  "available_gpus": [
    { "gpu_type": "H100_80GB", "gpu_count": 2, "min_gpus": 2, "valid_counts": [2, 4, 8],
      "tier": "secure", "price_hour_cents": 598, "available_count": 6 }
  ],
  "minimum_requirement": {
    "selected_gpu_min": 2, "selected_valid_counts": [2, 4, 8],
    "per_type": [{ "gpu_type": "H100_80GB", "min_gpus": 2, "valid_counts": [2, 4, 8] }]
  },
  "selected": { "gpu_type": "L40_48GB", "gpu_count": 2, "availability_status": "available" },
  "queue_offered": false,
  "queue_eligible": false,
  "gpu_priorities_entry": 1,
  "checked_at": "2026-07-19T00:00:00Z"
}

available_alternatives is the deprecated alias of available_gpus, and gpu_priorities_entry is the 1-based rank of the refused gpu_priorities entry when the rejection belongs to one. A stock miss carries the same shape with code: "CAPACITY_UNAVAILABLE", queue_offered: true, retryable_as_submitted: true, and an instruction that does offer allow_capacity_queue=true.

A 503 ADMISSION_UNAVAILABLE is a transient market outage, never a capacity verdict. Retry shortly, and never conclude out-of-stock from it. See get_platform_guide topic capacity_errors for the recovery playbook.

Models are selectable only from the platform's own catalog: list_models and search_models read the hosted registry, and create_training_job, preflight_training_job, create_inference, and preflight_inference validate the model id against it, answering MODEL_NOT_HOSTED — never a live Hugging Face lookup. Catalog models are pre-mirrored, so raw access tokens are intentionally excluded from MCP tool inputs and no integration is needed for models; Hugging Face integrations remain for dataset imports via import_huggingface_dataset.

list_inference_models is a different read: it uses /v1/models and the connection's selected inference credential to list the serverless pool and workspace deployments it can actually invoke. get_inference_model retrieves one exact id through the same scope and workspace boundary, including author/name model ids. A partially readable list names usf_unreachable_sources; never infer an unreadable source has no models. The registry's list_models / search_models tools remain the source for trainable/deployable base models, not the invocable roster. Neither new tool accepts a credential argument or emits credential fields in its result.

create_training_job and resume_training_job accept an optional idempotency_key. Reuse the same value after a timeout so the API replays the original acknowledgement instead of creating another job, wallet hold, queue entry, or GPU request. The MCP server generates a fresh key when it is omitted.

Training lifecycle (book-before-reveal)

dataset_ids is the ordered optimization set; eval_dataset_ids is a separate held-out set and cannot be combined with eval_split_ratio. Dataset sampling, row caps, source order, mixing weights, and the fixed seed must be identical in preflight and create. They are frozen when the job is created—an active job does not accept another dataset; launch a new job to change its data contract.

Like inference, create_training_job books a GPU before it reveals a job. The call blocks while the ranked ladder is booked (~40s typical); a job id and the "training started" email exist only once a real pod is secured. Read status on the response and from get_training_status:

  • booked — a GPU is secured (booked == secured); the job then provisions, downloads, and runs on its own. Money is captured only after this point.
  • securing — still booking at the deadline; the async tail continues. Poll get_training_status until booked/running (or a terminal state). Nothing is charged while securing.
  • queued — returned only with explicit queue consent; waits for stock at zero charge and books via the same path.
  • A booking-time stock miss returns the standard CAPACITY_UNAVAILABLE (409) with fresh available_gpus and no job exists (nothing charged); a selection that can never run returns one of the permanent 400 codes above instead, and no queue is offered for it. A transient 503 ADMISSION_UNAVAILABLE is a retry, never out-of-stock, and the platform never auto-substitutes a GPU.

If a started job loses its pod, it rests at interrupted — a self-heal state distinct from failed in which billing is already stopped. Call resume_training_job to continue from the last checkpoint; resume re-books on secured capacity before reporting resumed, so the same guarantees apply.

Training and deployment share one authoritative GPU-capacity broker. Server priority is evaluated first. Within an equal-priority class, the broker rotates across users and preserves FIFO order within each user's own requests. This anti-starvation policy prevents one user's large backlog from monopolizing GPU capacity; consequently, a newer request from another user can run before an older request in a busy user's backlog.

For each eligible request, the broker selects the lowest-ranked approved GPU choice that is live, has enough cards, and remains within the accepted total hourly price cap. Thus an older request's third choice can receive capacity before a newer request's first choice. Unknown/stale provider inventory issues no grant. Every vendor mutation requires the broker's short-lived fenced grant, and atomic reservations prevent training and deployment replicas from booking the same cards.

If capacity disappears before the vendor mutation, a queued request releases the grant and returns to its original global position. Expired worker leases are fenced and recovered with a new grant identity. Ambiguous provider results retain the same immutable provisioning request and grant fence until reconciliation proves success or definitive failure, so MCP clients should retry with the same idempotency key rather than submit a replacement request.

What never leaves the platform

An MCP client is a program the customer runs, so every tool result is a customer-facing response. Two facts never appear in one:

  • Container build identity — any image name, version, tag, digest or path. list_supported_architectures used to ship the engine image reference that published each registry row (image_tag, bios_version, manifest_sha256, and the same tag again inside the free-text notes), and get_training_capabilities shipped image_compatibility, the engine image VERSION range the contract was written against. Both are removed at the tool boundary (src/redaction.ts), by CONTENT as well as by key — a key-only rule is defeated the moment the same value moves one field over, which is exactly what notes did. Architecture support is unchanged and still authoritative: the deployment and training gates read those same rows, and the response says so. Engine text that reaches an agent as an error (upstream bodies, serving exceptions, training log lines) goes through the same content rule.
  • Which supplier backs a placement — the control plane already answers the neutral bios-cloud / global placement labels, and the tools echo those unchanged. Tool text describes what was bought ("the GPU is secured on real capacity"), never who sold it.

Hosted (remote) connector — implemented, not planned

Besides the stdio entry (dist/index.js), this package ships the hosted Streamable HTTP connector used by clients that only accept remote MCP servers (dist/http/main.js, ECS service bios-mcp, default port 7152). It is built and deployed, not a roadmap item:

  • POST {PUBLIC_BASE_URL}/mcp — stateless Streamable HTTP endpoint. GET and DELETE answer 405; an unauthenticated call answers 401 with the RFC 9728 WWW-Authenticate: Bearer resource_metadata=... challenge.
  • OAuth 2.1 authorization server with dynamic client registration and PKCE, advertised at /.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server, and /.well-known/openid-configuration (each also under /mcp).
  • Consent is granted in the console (CONSOLE_BASE_URL); every request re-validates the bearer token and re-checks scopes and workspace membership through the internal api-gateway. tools/list is filtered to that grant and the organization’s active release entitlements, so unavailable capabilities are absent rather than advertised and rejected later.
  • chat_with_inference is available when the OAuth grant carries serverless for a pool model or deployments:read/deployments:write for a workspace deployment. The gateway resolves the grant, checks the current workspace membership and scopes, and forwards through an internally attested serving route. The deployment's one-time serving key is never retrieved or returned to the model. upload_dataset remains unavailable on hosted MCP because the hosted process cannot read a file from the client's machine; use the console for local uploads.
  • complete_with_inference, embed_with_inference, rerank_with_inference and message_with_inference are withheld from hosted tools/list until OAuth-bound routes for those tasks are implemented and tested; stdio may use the configured inference credential now.

Any documentation still describing the hosted connector as "planned" is stale.

Verification

npm test
npm run typecheck
npm run build