Skip to main content
Glama

Nanites

Two tools in one repo. Use either, both, or neither.

What it is

Needs a coding harness?

nanites

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.

nanites-router

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 rolling avg_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 node:sqlite module, which does not exist on Node 20.

LM Studio

local models only

Talks to LM Studio's local HTTP server (http://localhost:1234 by default). Not needed by the router — a cloud-only gateway never touches it.

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 + cactus-needle, laya

local helper models

Optional, and every helper feature defaults off. Without them the router is unaffected.

cloudflared

the quick tunnel only

Only for POST /v1/tunnel. A missing binary is a 501, not a failure.

No lms CLI is required. Nanites will try lms server start as a recovery step if LM Studio is unreachable, but it is best-effort and non-blocking.

Install

git clone https://github.com/ADn-001/NANITES_MCP.git
cd NANITES_MCP
npm install
npm run build

Point Claude Code at the plugin directory for this session:

claude --plugin-dir ./plugin/nanites

To install it permanently as a marketplace plugin:

claude plugin marketplace add ADn-001/NANITES_MCP
claude plugin install nanites@nanites

npm 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/jobs runs 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/tunnel to 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 status

nanites-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:4800

Set 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

GET

/v1/health

bind, port, key presence, provider/key counts, helper status

GET

/v1/models

the advertised catalog. Anthropic-shaped when anthropic-version is sent, OpenAI-shaped otherwise

GET

/v1/keys

key inventory per provider

POST

/v1/messages

Anthropic Messages, non-streaming or SSE

POST

/v1/chat/completions

OpenAI Chat Completions, non-streaming or SSE

POST

/v1/jobs

start an async generation; returns a job id

GET

/v1/jobs/:id

job status, phase, and artifact

GET

/v1/jobs/:id/events

SSE progress

DELETE

/v1/jobs/:id

cancel

GET/PATCH

/v1/config

read and change writable feature flags

POST

/v1/helpers/{extract,classify,embed,score}

direct helper calls, when enabled

POST

/v1/tunnel

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

tool_repair

Needle 3

reconstructs a mangled tool call after the deterministic repair ladder fails

7/7 exact, 1/1 correct abstention

structured_output

Needle 3

extracts a response_format schema from free text

4/4 exact

laya_preflight

Laya

batched routing / moderation questions

weak — 40% on a 20-case set

laya_postflight

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 workstation with 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_models Load the small coding model. → load_model Summarize 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 units

  • get_pending_judgments — pull back the units that need your call

  • submit_test_judgment — record your score and approve it

  • write_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 written

  • nanites.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:4700

Views: 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

NANITES_HOME

Storage root

~/.nanites

NANITES_UI_PORT

Dashboard port

4700

NANITES_LMS_API_TOKEN

LM Studio auth token (used when the profile has none)

—

NANITES_LMSTUDIO_MODELS_DIR

Where to measure free disk for downloads

~/.lmstudio/models

NANITES_VISION_ROOTS

Allowed roots for image paths (;-separated)

current directory

NANITES_AUTOSTART_UI

Set 0 to disable dashboard orchestration

1

NANITES_HF_FETCH

Set 1 to allow Hugging Face network lookups

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 --noEmit

The 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-feature

Known 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 .env loader. If you rely on a .env file 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_file requires explicit opt-in, but it is a real capability, not a simulation.

  • command-runner integration carries a shell grant. Keep tools.enabled: false unless a profile genuinely needs it.

  • Provider API keys are stored in plaintext in nanites.db. The file is created with 0600 permissions 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-smoke timing 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 init does, 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_repair and structured_output are 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 tools
chatChatA

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.

share_test_resultsShare Test ResultsA

Copy approved test results from source_profile into profile when both point at the SAME LM Studio instance (endpoint fingerprint: normalized URL + auth presence). Opt-in sharing to avoid redundant regimen runs; different endpoints are refused and stay isolated. Nothing is auto-finalized — a later regimen/finalize aggregates the copied results without re-running the model.

Inputs: profile (required), source_profile (required), model_id.

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

    B3.2/5.0

    Scored across 53 tools

    Disambiguation4/5

    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 Consistency3/5

    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.

    Tool Count2/5

    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.

    Completeness4/5

    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

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables 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.
      -
    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables 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.
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables 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