Nanites
Summary: Nanites is an MCP server that lets a coding harness delegate bounded work to local LM Studio (or cheap cloud) models, and manage the model registry, profiles, tests, cloud provider keys, and cost tracking behind it.
Model lifecycle (LM Studio): list loaded/available models, load/unload instances, chat, and download models (optionally waiting or auto-testing).
Delegation: run bounded sub-agent tasks synchronously (
run_sub_agent) or as async jobs (start_sub_agent_job), and open side-chats via/nanites-btw(start_btw_chat).Profiles: create, switch, update, and list machine profiles (VRAM specs, endpoint, pricing, inference effort, guardrails).
Registry & role pins: read/write registry entries, diff untested models, filter by guardrail tier, and pin roles to provider/model pairs.
Testing & scoring: register/validate test units, run test regimens, fetch pending judgments, and submit orchestrator judgments with user approval.
Cloud providers: add/remove/list/toggle provider keys, discover and register provider models, manage provider enablement and preference order, and view provider errors.
Cost reporting: audit tokens and estimated USD saved by local delegation over day/week/month/all.
Health & notifications: check LM Studio/disk/loaded-model health and send ntfy push notifications.
Allows using Cloudflare Workers AI as a cloud model provider for delegated inference tasks, including provider key management for Cloudflare-backed models.
Enables Hugging Face network lookups for model information when enabled, supporting model discovery in the registry.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Nanites Use a local model to summarize this repo's README"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Nanites
Two tools in one repo. Use either, both, or neither.
What it is | Needs a coding harness? | |
| An MCP server that lets Claude Code / Claude Desktop delegate bounded, disposable work to your own local models — so you stop paying frontier tokens for grunt work. | Yes, to be driven. |
| An OpenAI- and Anthropic-compatible HTTP gateway that fronts your cloud provider keys behind one virtual key. | No. It stands alone. |
Nanites is the delegation layer, not the orchestrator. Claude Code/Desktop stays your orchestrator on a paid frontier model and handles anything requiring real judgment. Nanites hands the cheap, bounded, throwaway work — scanning a codebase, summarizing a file, drafting a test, answering a side question — to a local LM Studio model or a cheap cloud model, and returns the result.
The router is a separate program with a separate job: it puts your Cloudflare / OpenRouter / OmniRoute / NVIDIA keys behind one endpoint, adds a virtual key, model aliasing, key failover, async jobs, and an OpenAI/Anthropic-compatible API. Any client that speaks those APIs can use it — including things that are not a coding harness at all. It does not import the MCP server and does not need LM Studio.
Both ship from one repo and share one database, so a key you add once is visible to both.
Table of contents
Related MCP server: Houtini LM
Why it exists
Delegating work to a small local model is a good idea. Delegating it blindly — without knowing which model is good at what — is how you end up with worse results and a bigger bill. Nanites builds the part that is tedious:
A model registry. Each model gets a
performance_score(1-100), plus rollingavg_load_ms/avg_response_ms, recomputed from your real logged runs. The score is a speed/stability signal, not an oracle — the skill teaches Claude to weigh it alongside the test-regimen results and your own approvals.A test regimen. A built-in suite of modular test units runs against a model. Deterministic ones (valid JSON, exact label) are scored automatically; the rest come back to you for judgment — never auto-filed as passing.
Guardrail tiers keyed to your VRAM. A 4 GB card and a 24 GB card get different concurrency advice, and the advice comes with a stated reason so Claude can explain it.
A cost-saved report. Every delegation is logged with token counts and a computed saving, so the claim is auditable rather than vibes.
Requirements
Requirement | Needed for | Notes |
Node.js 22.5+ | everything | Hard requirement. Nanites uses the built-in |
LM Studio | local models only | Talks to LM Studio's local HTTP server ( |
Claude Code or Claude Desktop | the plugin experience | Any MCP-capable client works for the raw server. Not needed by the router. |
A cloud provider key | cloud routing | Cloudflare / OpenRouter / OmniRoute / NVIDIA / any OpenAI-compatible endpoint. |
Python + | local helper models | Optional, and every helper feature defaults off. Without them the router is unaffected. |
| the quick tunnel only | Only for |
No
lmsCLI is required. Nanites will trylms server startas a recovery step if LM Studio is unreachable, but it is best-effort and non-blocking.
Install
As a Claude Code plugin (recommended)
git clone https://github.com/ADn-001/NANITES_MCP.git
cd NANITES_MCP
npm install
npm run buildPoint Claude Code at the plugin directory for this session:
claude --plugin-dir ./plugin/nanitesTo install it permanently as a marketplace plugin:
claude plugin marketplace add ADn-001/NANITES_MCP
claude plugin install nanites@nanitesnpm run build also installs the plugin's own runtime dependencies into
plugin/nanites/node_modules (the plugin resolves its imports relative to the
plugin root, so it needs its own copy). The two commands above are therefore all
that a fresh clone needs — no separate npm install inside the plugin
directory, and no manually copied dist.
Build output is not tracked in git. plugin/nanites/dist is generated by
npm run build, which copies the compiled server there because Claude Code
refuses a plugin path that escapes the plugin directory.
As a plain MCP server
Register it with any MCP client. For Claude Code, add to your project .mcp.json:
{
"mcpServers": {
"nanites": {
"command": "node",
"args": ["/absolute/path/to/NANITES_MCP/dist/index.js"]
}
}
}Run npm run build first — dist/index.js does not exist until you do.
The router
nanites-router is a standalone HTTP gateway. It presents an OpenAI Chat Completions
and an Anthropic Messages API, and forwards to whichever provider serves the model
you asked for. It is the piece to use if your consumer is not Claude Code — a
script, a library, another agent framework, a spreadsheet macro, anything that can
POST JSON.
It does not import the MCP server, does not construct an MCP server, does not touch the LM Studio lifecycle, and never asks a harness what to do. On a machine that has never seen Claude Code it runs exactly the same.
What it adds over calling a provider directly
One key instead of yours in every client. The router generates a virtual API key, stored scrypt-hashed with a per-install salt. Clients authenticate to the router; the router authenticates to the provider.
Model aliasing. Publish a model under a name a harness will accept (
nanites-flash) and map it to whatever the provider actually calls it. Clients never see a slash-and-colon id.Ordered failover chains. An alias can list candidates; the router tries them in order and remembers the winner. It absorbs "unavailable right now" and propagates real errors — a provider that 500s on everything is not walked past four times just to return the same error.
Key failover, scoped to the provider. Round-robin, random, most-used, or sticky-last-best across your keys. A different provider is never silently substituted — that is a different model at a different price.
Async jobs.
POST /v1/jobsruns a slow generation (an image, a video, TTS) and gives you a job id, an SSE progress stream, and cancellation. Retry with backoff on transient upstream failures; a shape rejection is never retried.Rate limiting and a quick tunnel. Token-bucket limiting per virtual key, and
POST /v1/tunnelto expose it through a cloudflared quick tunnel for testing.
Standalone setup (no harness)
git clone https://github.com/ADn-001/NANITES_MCP.git
cd NANITES_MCP
npm install
npm run build
# 1. Create a profile and make it active. This is the ACTIVE profile the
# router reads, and it is the same profile the Providers tab writes.
nanites-cli init
# 2. Add a key. Read it from the environment so the secret never lands in
# shell history or in another process's argv.
export NANITES_API_KEY_CLOUDFLARE=...
nanites-cli add-key cloudflare --account-id <your-account-id> --nickname work
# 3. List the provider's catalog.
nanites-cli discover cloudflare
# 4. Check what is configured before starting anything.
nanites-cli statusnanites-cli never prompts — a blocking prompt cannot be scripted, and an EOF on a
pipe looks like an empty key. Missing input is an error naming the flag that fixes it.
It is idempotent, and it never prints a secret.
Discovery stores candidates. Registering one is a separate, deliberate act, and
status reports both counts, because "65 discovered, 0 registered" is a normal
starting state and not a failure.
Then start it:
NANITES_ROUTER_KEY=choose-your-own-virtual-key nanites-router
# nanites-router listening on http://127.0.0.1:4800Set NANITES_ROUTER_KEY and the router uses your key. Leave it unset and the router
generates one and prints it once — stdout is not a secret store, so it is never
re-printed.
curl http://127.0.0.1:4800/v1/chat/completions \
-H "Authorization: Bearer $NANITES_ROUTER_KEY" \
-H 'content-type: application/json' \
-d '{"model":"cloudflare:@cf/meta/llama-4-scout-17b-16e-instruct",
"messages":[{"role":"user","content":"Reply with exactly: PONG"}]}'Both dialects work. An Anthropic client sets anthropic-version: 2023-06-01 and
uses /v1/messages.
The router and the Providers tab share one key store. Add a key in the Providers tab, or with
nanites-cli add-key, and the router can use it on its next request — no restart, and no second place to enter it. Switching your active profile changes which keys the router uses.
Using it with a harness
Nothing changes. The router reads the same database, so keys added through the MCP
Providers tab or the dashboard are already there. To let a client reach the router
over a network rather than loopback, POST /v1/tunnel:
curl -X POST http://127.0.0.1:4800/v1/tunnel -H "Authorization: Bearer $NANITES_ROUTER_KEY"It prints a trycloudflare.com URL. That is a public endpoint with real provider
spend behind it and the virtual key as the only thing in between — the router says so
at startup when it is not bound to loopback, and it says so again here.
Router endpoints
Method | Path | Purpose |
|
| bind, port, key presence, provider/key counts, helper status |
|
| the advertised catalog. Anthropic-shaped when |
|
| key inventory per provider |
|
| Anthropic Messages, non-streaming or SSE |
|
| OpenAI Chat Completions, non-streaming or SSE |
|
| start an async generation; returns a job id |
|
| job status, phase, and artifact |
|
| SSE progress |
|
| cancel |
|
| read and change writable feature flags |
|
| direct helper calls, when enabled |
|
| start a cloudflared quick tunnel |
All of them require Authorization: Bearer <virtual key>. Rate limits answer 429
with retry-after.
Modality. Cloudflare models outside the text-generation category are routed to
Workers AI's /ai/run endpoint rather than the chat shim, so image generation, TTS,
and vision models work through the same /v1/chat/completions call. An image reply
comes back as data[0].b64_json, the shape an image client expects.
Local helper models (optional)
Two on-device models can sit inside the request path. They are free, run locally, and send nothing anywhere — but they load a model into memory, so every one of them defaults to off.
Feature | Model | What it does | Measured |
| Needle 3 | reconstructs a mangled tool call after the deterministic repair ladder fails | 7/7 exact, 1/1 correct abstention |
| Needle 3 | extracts a | 4/4 exact |
| Laya | batched routing / moderation questions | weak — 40% on a 20-case set |
| Laya | judges whether a reply refused or hedged | weak — 35% zero-shot |
The numbers come from a labeled eval run against the real packages, and the two
laya_* rows are why they default off: a classifier that fires on 12 of 20 benign
requests teaches you to ignore it.
curl -X PATCH http://127.0.0.1:4800/v1/config \
-H "Authorization: Bearer $NANITES_ROUTER_KEY" \
-H 'content-type: application/json' \
-d '{"enable_helpers":true,"feature_tool_repair":true}'Turning enable_helpers false stops any request from using them and kills the
resident workers, so the model is released rather than merely unused. You can also do
this from the dashboard's Router tab, the /nanites-helpers command, or the
nanites_toggleHelpers MCP tool — all four write the same row.
The helpers need Python with the cactus-needle and laya packages. Without them
the router is unaffected; they report as unavailable with a reason.
Getting started
With a coding harness
Everything below assumes Claude Code (or another MCP client) is driving.
1. Create a profile
A profile describes your machine — its VRAM, the LM Studio endpoint, pricing, and what you want to delegate. This is what makes the guardrail and scoring advice specific.
In Claude Code, say something like:
Create a Nanites profile called
workstationwith 24 GB VRAM and 32 GB RAM, pointing at my LM Studio at http://localhost:1234.
Or call the tool directly: create_profile with a name, optional machine_specs, and an
optional endpoint. If you omit machine_specs, a conservative baseline is used
(4 GB VRAM — the safe default that keeps you sequential).
2. Point it at your endpoint
If your LM Studio requires an API token, set it on the profile (endpoint.auth_token),
or export NANITES_LMS_API_TOKEN to cover profiles that leave it null. If LM Studio is
down when you start, run system_health_check — it attempts a one-shot lms server start
and rechecks before reporting down.
3. Load a model and delegate something small
What models do I have? →
list_modelsLoad the small coding model. →load_modelSummarize what this repo's build script does. →run_sub_agent
The first run_sub_agent is where the machinery engages: the model is hot-loaded if
needed, the inference gate serializes access for your profile's tier, the reply passes
through the cleaner (strips reasoning tags, catches degeneration loops), and the run is
logged so the score can be recomputed next time.
4. Build up the registry
Once you have a few models:
run_test_regimen— score a model against the built-in unitsget_pending_judgments— pull back the units that need your callsubmit_test_judgment— record your score and approve itwrite_registry_entry— persist a model and its parameters
After that, run_sub_agent picks better models automatically because the registry knows
what each one is actually good at.
5. Check what you saved
How much have I saved? →
get_cost_saved_report
Reads real logged token counts and computes the not-spent cost at your profile's rates.
How it works
Transport. stdio. The MCP server is a child process; Claude Code owns the pipe.
Storage. Everything lives under NANITES_HOME (default ~/.nanites):
profiles/*.json— small, human-editable, rarely writtennanites.db— SQLite (WAL mode) for the registry, call logs, events, test results
Concurrency. Your profile's VRAM determines a guardrail tier, which determines a
(max_parallel_models × num_parallel) pair. Forced-sequential tiers (< 12 GB) also route
through a per-profile inference gate — one in-flight inference at a time — so
overlapping sub-agents queue instead of fighting over a single model slot.
Providers. Local LM Studio, or cloud (Cloudflare Workers AI / OpenRouter / OmniRoute / any OpenAI-compatible endpoint). Cloud runs get a sandboxed filesystem tool loop that Nanites executes in-process, confined to a configured root.
Sanitization. Anything returned to the orchestrator is scrubbed: no reasoning-tag leakage, no absolute filesystem paths, no usernames, no raw upstream error bodies. Loop detection in generated text cuts the degenerate tail and flags it rather than silently shipping it.
The dashboard
A local web dashboard runs as a separate process sharing the same database.
npm run ui # http://127.0.0.1:4700Views: Live Execution, Registry & Leaderboards, Hardware State, Cost & Ledger, System Health, Providers, Router, Settings, Errors. Live sub-agent output streams in over SSE by polling the events table — no cross-process IPC.
The Providers tab is where you add and enable provider keys. The Router tab shows what the gateway is configured with (bind, port, key presence, per-provider key counts, job totals) and holds the helper-model toggles. Both read the same database, so they cannot disagree — and a key you add in Providers is usable by the router on its next request. The dashboard never shows the virtual key or a provider key, only whether one is set.
Themes
Three switchable profiles, set in Settings and stored on the active profile:
Theme | Character |
Retro Instrument (default) | E-ink paper-and-ink with a single orange signal, hard 1px borders, corner brackets, a faint dither texture, and a day/night toggle. System monospace only. |
Phosphor Terminal | Green CRT, angular and gritty, with the cursor-evading skull in the header. |
Modern Minimal | Clean dark, quiet typography, sans headings. |
The dashboard binds 127.0.0.1 by default. A Broadcast setting can expose it on the LAN
for a phone or tablet; that mode is read-only unless the caller presents the
per-boot LAN token (sent as X-Nanites-Lan-Token), and Broadcast warns before enabling
because it exposes local data to the network.
Configuration
Everything is environment variables — there is no .env loader. Export them into your
shell (or your MCP server's env block) before starting.
Variable | Purpose | Default |
| Storage root |
|
| Dashboard port |
|
| LM Studio auth token (used when the profile has none) | — |
| Where to measure free disk for downloads |
|
| Allowed roots for image paths ( | current directory |
| Set |
|
| Set | off |
Tool reference
Nanites exposes the real 55-tool surface, grouped by what you would use it for:
Models and inference — list_models, get_loaded_model, load_model, unload_model,
chat, download_model, get_download_status, download_and_wait, download_and_test
Delegation — run_sub_agent, start_sub_agent_job, get_sub_agent_job_status,
start_btw_chat, share_test_results, get_cost_saved_report
Registry — read_registry, write_registry_entry, diff_untested,
run_untested_sweep, filter_by_guardrail, seed_provider_models, set_role_pin,
list_role_pins, delete_role_pin
Profiles — create_profile, switch_profile, update_profile, list_profiles,
get_active_profile, get_first_run_status
Testing and scoring — list_test_units, validate_test_unit, register_test_unit,
run_test_regimen, get_pending_judgments, submit_test_judgment, check_adaptation,
register_adapted_units
Cloud providers — nanites_addProviderKey, nanites_removeProviderKey,
nanites_listProviderKeys, nanites_toggleProviderKey, nanites_discoverProviderModels,
nanites_listProviderModels, nanites_registerProviderModel,
nanites_deregisterProviderModel, nanites_showProviderErrors,
nanites_setProviderEnabled, nanites_getProviderConfig,
nanites_setProviderPreferenceOrder
Health and notifications — system_health_check, send_ntfy
Every tool takes schema-validated input and returns a structured envelope —
{code, message, retryable, details?} — never a raw throw or stack trace.
Slash commands
Available once the plugin is loaded:
/nanites-new-profile, /nanites-switch-profile, /nanites-profiles,
/nanites-models, /nanites-registry, /nanites-untested, /nanites-cost-saved,
/nanites-effort, /nanites-dynamic-model, /nanites-pin, /nanites-vision,
/nanites-seed-agents, /nanites-health, /nanites-btw,
/nanites-helpers
/nanites-btw opens a side-conversation with a model mid-task — useful when you want to
ask "wait, what does that function do?" without derailing the main thread.
Development
npm install
npm run build # tsc + copy frontend to dist/ui, skill, and plugin server bundle
npm test # full suite, mocked — no LM Studio or network required
npm run typecheck # tsc --noEmitThe test suite is fully self-contained: 162 test files run against a mock LM Studio
server and a scratch NANITES_HOME, so nothing touches your real data or the network.
CI runs typecheck + tests on every push.
Optional live checks (require a running LM Studio with a model loaded):
npm run live-smoke
npm run live-featureKnown limitations
Node 22.5+ is required. This is a hard floor imposed by
node:sqlite, not a preference. Node 20 will not run it.There is no
.envloader. If you rely on a.envfile in your current workflow, you will need to export variables into the environment instead.The cloud filesystem grant executes real writes when a profile enables it. It is confined to a configured root and
write_filerequires explicit opt-in, but it is a real capability, not a simulation.command-runnerintegration carries a shell grant. Keeptools.enabled: falseunless a profile genuinely needs it.Provider API keys are stored in plaintext in
nanites.db. The file is created with0600permissions where the OS supports it, but this is not encrypted at rest.The dashboard's Broadcast mode exposes local data to the LAN. It is read-only without a token, but the token is printed to the console at startup.
live-smoketiming is sensitive to LM Studio contention. A loaded machine can exceed the script's budget even when everything is working.The router reads the ACTIVE profile's provider keys. This is what makes one key store work across the CLI, the Providers tab, and the gateway — but it also means switching your active profile changes which keys the router uses. The "router config is global" property holds for the router's own tables (config, key metrics, aliases, the advertised catalog, jobs) and deliberately not for provider keys.
The router does not create a profile for you.
nanites-cli initdoes, but a router started on a home with no active profile refuses every request rather than guessing which provider you meant. That refusal is deliberate.The two
laya_*helper features are not reliable. Measured zero-shot on a 20-case labeled set: 40% on cache-poisoning, 35% on refusal detection, and 90% on modality intent against a deterministic heuristic that is already 100%. They are exposed for inspection and would need fine-tuning and calibration on your own labelled router traffic before they should gate anything. That is why they default off;tool_repairandstructured_outputare measured strong and are the ones worth enabling.Cloudflare's own quotas still apply. A key whose daily free allocation is spent is retired until the next UTC midnight. The router rotates the rest of the pool and tells you which key failed and why — it cannot create neurons.
License
MIT © 2026 Adnan Shelim. Use it, fork it, ship it commercially.
Acknowledgements
Built against the LM Studio REST API and the Model Context Protocol TypeScript SDK.
Available Tools
53 toolschatChatA
Send a multi-message chat to a loaded model instance. System messages become the system prompt; output passes through the reply validator/cleaner and includes a validation field describing anything stripped.
Inputs: messages (required), instance_id (required), params, timeout_s.
check_adaptationCheck AdaptationA
Check whether a profile's use case diverges from nanites-default. When it does, returns a user prompt asking whether to draft custom test units, plus the default-plan notice that reusing the default plan may not be well-calibrated.
Inputs: profile (required).
create_profileCreate ProfileC
Create a named profile. Machine specs, endpoint, pricing, test_plan_ref and ntfy are optional and resolve to documented defaults; concurrency is derived from machine specs via the guardrail tiers.
Inputs: name (required), ntfy, tools, pricing, +8 more.
delete_role_pinDelete Role PinB
Remove a role pin so that role falls back to dynamic model selection.
Inputs: role (required), profile.
diff_untestedDiff Untested ModelsA
List downloaded LLM models on the profile's endpoint that have no registry entry yet (the Workflow #3 discovery step). Returns a trimmed per-model shape.
Inputs: profile (required), verbose.
download_and_testDownload And TestB
Workflow #4 end to end: download_and_wait, then on completion trigger Workflow #1 (run_test_regimen) on the newly downloaded model automatically. A failed/paused/gave-up download returns without testing.
Inputs: source (required), profile (required), quantization.
download_and_waitDownload And WaitB
Workflow #4 download half: ask LM Studio to download a model by HF source id, then poll download status with exponential backoff until completed/failed/paused (or a poll ceiling).
Inputs: source (required), profile (required), quantization.
download_modelDownload ModelC
Ask the active profile's LM Studio endpoint to download a model by HF source id, optionally pinned to a quantization.
Inputs: source (required), quantization.
filter_by_guardrailFilter By GuardrailA
Shortlist candidate models (e.g. Hugging Face search results the host gathered via its HF connector) against the profile's machine-spec guardrail tier. Excludes models far outside the tier's recommended size range with an explicit reason; never silently suggests.
Inputs: profile (required), candidates (required).
get_active_profileGet Active ProfileA
Return the currently active profile, or null if none has been switched to yet.
Inputs: no named parameters.
get_cost_saved_reportGet Cost Saved ReportA
Report tokens and estimated USD saved by delegating work to local models, from real logged sub-agent usage over a period (all/day/week/month) at the profile's input/output rates. Local delegation costs ~$0, so saved_usd is the orchestrator-equivalent cost not spent.
Inputs: profile (required), period.
get_download_statusGet Download StatusA
Poll the download progress for a job_id returned by download_model.
Inputs: job_id (required).
get_first_run_statusGet First Run StatusA
Report whether Nanites needs first-run initialization: true exactly when zero profiles exist. The orchestrator calls this once at session start; when true, it runs the /nanites-new-profile flow.
Inputs: no named parameters.
get_loaded_modelGet Loaded ModelA
Return the models currently loaded into GPU/CPU on the active profile's LM Studio endpoint (loaded_instances non-empty).
Inputs: verbose.
get_pending_judgmentsGet Pending JudgmentsB
Fetch cleaned raw output plus rubric and prompt context for pending orchestrator-judged units (all, or a requested subset) for the orchestrator to read and judge in the same turn.
Inputs: profile (required), model_id (required), unit_ids.
get_sub_agent_job_statusGet Sub-Agent Job StatusA
Poll a sub-agent job started with start_sub_agent_job. Returns { job_id, status: queued|running|done|error, result? }; result is present for done (shaped like run_sub_agent's response) and error (structured { code, message, retryable }).
Inputs: job_id (required).
list_modelsList ModelsA
List the models known to the active profile's LM Studio endpoint. Returns a trimmed shape by default; pass verbose for the full model objects.
Inputs: verbose.
list_profilesList ProfilesA
List profile names. Pass verbose for full profile objects.
Inputs: verbose.
list_role_pinsList Role PinsB
List the role->model pins for a profile (default active).
Inputs: profile.
list_test_unitsList Test UnitsA
List the registered test units for a profile (the default regimen is registered automatically on first use).
Inputs: profile (required).
load_modelLoad ModelA
Load a model into the active profile's LM Studio endpoint. model_id is the model key (the identifier shown by list_models); optional load params (context_length, flash_attention, ...) may be passed.
Inputs: model_id (required), params.
nanites_addProviderKeyAdd Provider KeyC
Add an API key for a cloud provider (Cloudflare, OpenRouter, OmniRoute, Generic).
Inputs: api_key (required), provider (required), account_id, gateway_url.
nanites_deregisterProviderModelDeregister Provider ModelB
Deregister a registered model from a cloud provider.
Inputs: model_id (required), provider (required).
nanites_discoverProviderModelsDiscover Provider ModelsC
Auto-discover available models from a cloud provider.
Inputs: provider (required).
nanites_getProviderConfigGet Provider ConfigA
Get provider preference order and per-provider settings.
Inputs: no named parameters.
nanites_listProviderKeysList Provider KeysA
List all API keys for a cloud provider.
Inputs: provider (required).
nanites_listProviderModelsList Provider ModelsC
List cached models from a cloud provider.
Inputs: provider (required), registered_only.
nanites_pingNanites PingA
Liveness probe for the Nanites MCP server. Returns server identity and transport health.
Inputs: no named parameters.
nanites_registerProviderModelRegister Provider ModelC
Register a discovered model for use with a cloud provider.
Inputs: model_id (required), provider (required).
nanites_removeProviderKeyRemove Provider KeyC
Remove an API key from a cloud provider.
Inputs: key_id (required), provider (required).
nanites_setProviderEnabledSet Provider EnabledB
Enable or disable a cloud provider globally.
Inputs: enabled (required), provider (required).
nanites_setProviderPreferenceOrderSet Provider Preference OrderC
Set the global provider preference order for cloud routing.
Inputs: order (required).
nanites_showProviderErrorsShow Provider ErrorsC
Show recent errors from cloud provider calls.
Inputs: filter.
nanites_toggleProviderKeyToggle Provider KeyC
Enable or disable an API key for a cloud provider.
Inputs: key_id (required), enabled (required), provider (required).
read_registryRead RegistryA
Read model-registry entries (roles, scores, best params, last tested) for a profile, optionally filtered to one model_id. Trimmed by default; verbose includes timestamps.
Inputs: profile (required), verbose, model_id.
register_adapted_unitsRegister Adapted UnitsA
Validate a batch of authored test units through the Phase 4 validator and register the ones that pass; each rejected unit is returned with its validation issues surfaced, never silently dropped or force-registered.
Inputs: units (required), profile (required).
register_test_unitRegister Test UnitB
Validate and persist a test unit for a profile. Rejects invalid units with the issues listed; duplicate ids are refused.
Inputs: unit (required), profile (required).
run_sub_agentRun Sub-AgentA
Delegate one bounded task to a local model. Resolves the model from the profile's registry by roles (or an explicit model_id), acquires a model respecting the profile's concurrency tier (reuse already-loaded, evict on sequential tiers, refuse at parallel capacity), runs the brief once, cleans the reply, unloads exactly once if it loaded the model, and logs exactly one token-usage entry for cost tracking.
Inputs: brief (required), profile (required), task, roles, +8 more.
run_test_regimenRun Test RegimenA
Test one model against the profile's registered test units (the default regimen is auto-registered on first use). Loads the model, runs deterministic units inline with a logged param search, runs orchestrator_judged units to pending, unloads exactly once, and writes the registry entry when nothing is pending. Returns only pending_unit_ids, never raw output.
Inputs: profile (required), model_id (required), provider.
run_untested_sweepRun Untested SweepB
Workflow #3 end to end: diff downloaded LLM models against the registry and run Workflow #1 (run_test_regimen) on each unregistered model, sequentially.
Inputs: profile (required).
seed_provider_modelsSeed Provider ModelsA
Bulk-register the canonical Cloudflare agentic models (canonical manifest), role-tag them in the registry, and write the default role pins. Idempotent; unknown model ids are refused before anything is written.
Inputs: profile, provider, model_ids.
send_ntfySend NotificationA
Fire-and-forget push notification to the profile's ntfy topic (public-server default resolution per profile config). A failed push never fails the underlying operation; it is logged server-side only.
Inputs: message (required), profile (required), tags.
set_role_pinSet Role PinA
Pin a role to a preferred (provider, model). Auto-route by pin on later sub-agent runs; falls back to dynamic when the pinned target is unusable.
Inputs: role (required), model_id (required), provider (required), profile.
start_btw_chatStart /nanites-btw ChatA
Start a /nanites-btw working-memory chat for a profile: replaces the active chat row and wipes its old transcript (the compaction caches persist), enqueues compaction of the given host-session transcript as an async job (returns immediately — it can never stall or eject a running job), pins and holds a context_qa model when the job completes, and answers initial_question inline if it finishes inside the ~5s grace window. Returns the dashboard deep link (open it in the preview) plus the job handle and status.
Inputs: profile, messages, initial_question.
start_sub_agent_jobStart Sub-Agent JobA
Queue a sub-agent job on the profile's async job FIFO and return its job_id immediately (non-blocking — for long-horizon work on slow/big models instead of a tool call that blocks for minutes). Same validated inputs as run_sub_agent; when the profile's concurrency tier is at capacity the job waits queued rather than erroring. Poll with get_sub_agent_job_status.
Inputs: brief (required), profile (required), task, roles, +5 more.
submit_test_judgmentSubmit Test JudgmentA
Record an orchestrator judgment for one pending unit. Nothing becomes final in the registry until user_approved is true; a submission with user_approved false records the judgment without finalizing that score.
Inputs: score (required), profile (required), unit_id (required), model_id (required), +3 more.
switch_profileSwitch ProfileA
Make a named profile the active one. All subsequent model tools use its endpoint until switched again.
Inputs: name (required).
system_health_checkSystem Health CheckA
Check LM Studio health for a profile: endpoint reachability (with a one-shot lms server start autostart recovery and recheck), free disk space for downloads, and stuck-loaded-model detection. Returns an overall status (healthy/degraded/down) plus per-check sub-fields.
Inputs: profile (required).
unload_modelUnload ModelC
Unload a loaded model instance by its instance_id from the active profile's LM Studio endpoint.
Inputs: instance_id (required).
update_profileUpdate ProfileA
Partially update a named profile (machine specs, endpoint, pricing, ntfy, inference effort/ceiling, theme, tool grant). Omitted fields keep their current values. Used by /nanites-effort to set the active profile's effort.
Inputs: profile (required), ntfy, tools, pricing, +8 more.
validate_test_unitValidate Test UnitA
Validate a test-unit object against the schema/validator rules without persisting it. Returns { ok, issues }.
Inputs: unit (required).
write_registry_entryWrite Registry EntryA
Insert or update one registry entry for a profile/model_id. Omitted entry fields keep their existing values.
Inputs: entry (required), profile (required), model_id (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 53 tools
Most tools are clearly distinct (e.g., list_models vs get_loaded_model, run_sub_agent vs start_sub_agent_job), but a few pairs could be confused: nanites_deregisterProviderModel vs nanites_removeProviderKey (deregister vs remove), and get_download_status vs download_and_wait overlap in polling behavior. Overall, the core model/test workflows are well separated.
Naming is mixed: some tools use snake_case with domain prefix (nanites_*), others use plain verbs (chat, load_model, create_profile), and a few use different conventions (get_cost_saved_report, seed_provider_models). The pattern is not uniform, making it harder to predict tool names, though each individual name is readable.
With 53 tools, the surface is both wide and deep, covering profiles, providers, models, testing, jobs, workflows, and notifications. While each domain has its own cluster, the sheer number exceeds what an agent can easily navigate, and some tools (e.g., send_ntfy, get_cost_saved_report) feel peripheral. A more focused set of ~25-35 would be more manageable.
The set covers the full lifecycle for models (list/load/unload/download/test), profiles (create/update/switch/list), providers (add/remove/list/toggle keys, set preference), and test management (validate/register/run/judge). Minor gaps exist: no explicit tool to delete a profile or a test unit, and no tool to list provider errors beyond 'show' (which is read-only). Overall, core workflows are well-covered.
Maintenance
Related MCP Connectors
AI routing, memory, guardrails, and governance. Routes across Claude, GPT, Gemini.
LLM cost optimization gateway, repo token-waste auditor & model arbitrage MCP server.
Enterprise AI Control Plane: governance, guardrails, spend tracking, compliance & smart routing.
BYOK AI router & FinOps control plane: audit token waste, check tool safety, and rank models.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables Claude Code to hand off bulk, mechanical, read-heavy tasks to a local model, including agentic loops that can read, write, and run commands sandboxed at zero cloud token cost.MIT
- FlicenseNot gradedqualityAmaintenanceEnables MCP clients such as Claude Code to hand bounded work — code reviews, boilerplate, commit messages, format conversion, embeddings — to a local or cloud OpenAI-compatible LLM instead of the main model, cutting token spend by keeping large files out of the orchestrator's context. It also provides a cheap second model for reviewing code and verifying results.-
- FlicenseNot gradedqualityAmaintenanceEnables Claude Code and other MCP clients to offload bounded work—code review, test stubs, boilerplate, commit messages, format conversion, embeddings—to a local GPU model or a cheaper cloud, OpenAI-compatible endpoint. Source files are read by the server rather than the main model, cutting token spend while the orchestrating model keeps planning and verifying.-
- AlicenseNot gradedqualityBmaintenanceEnables Claude Code and other MCP clients to offload bounded tasks such as code review, test stubs, commit messages, and format conversion to local or cheaper cloud LLMs, cutting token usage while the primary model remains the orchestrator.MIT