> ## Documentation Index
> Fetch the complete documentation index at: https://docs.noxus.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Code mode

> Connect to one tool instead of the whole catalog, and drive Noxus from a script

## Why

The Noxus MCP server advertises its full tool list on connect: 113 tools whose
schemas come to roughly **23,000 tokens**. Your client pays that in every
conversation, whether or not it ever calls a Noxus tool. It also makes the
model chain one tool call per step, each result travelling back through the
context.

Code mode is the other way round. Connect to `/mcp/code` and you are offered
**two** tools and about **3,300 tokens**.

Most of that is the catalog, and the catalog is only names: every tool, with
one line saying what it does. Naming all of them is cheaper than hiding any of
them, and it means a tool can never be missed by a search that guessed the
wrong word. What each tool *takes and returns* is the expensive part, so that
stays in the sandbox and `search` hands you the few you ask for.

## Connecting

Same server, same credentials, different path — append `/code` to the URL you
already use:

```json theme={null}
{
  "mcpServers": {
    "noxus": {
      "url": "https://backend.noxus.ai/mcp/code",
      "headers": { "Authorization": "Bearer YOUR_NOXUS_API_KEY" }
    }
  }
}
```

The classic `/mcp` endpoint is unchanged. Use it when your client already has
its own code-execution layer, or when you want the model to see the tools
directly.

## Finding a tool's arguments and types

Pick the names you want out of `execute`'s catalog and name them to `search`,
separated by commas:

```
workflows_list, workflows_list_runs, runs_wait
```

You get back each one's description, its full signature, and the TypedDict
definitions that signature refers to. That last part is the shape of what a
call returns, which is what you need before chaining one result into the next.

When a name is not obviously the right one, pass a word instead and it is read
as a search over names and descriptions:

```
workflow runs
```

For anything those two do not cover, `search` takes Python and `spec()` is the
whole catalog as a dict. It stays in the sandbox, so only what your code
returns comes back:

```python theme={null}
[n for n in spec() if "workflow" in n]
```

`spec()` is a plain call, with no `await`.

One search should be enough: ask for everything the job needs in a single
call, then do the whole job in a single `execute`. `search` cannot call a Noxus
tool, so it has no side effects.

## Running code

Every tool the catalog names is a pre-bound async function. There is no module
to reach through — just the name. The last expression is the result:

```python theme={null}
import asyncio

flows = await workflows_list(page_size=100)
runs = await asyncio.gather(*[workflows_list_runs(workflow_id=f["id"]) for f in flows])
# Return only the answer, not the two lists it came from.
[f["name"] for f, r in zip(flows, runs) if not r]
```

That is one tool call where the classic surface would have taken a hundred and
one, and the intermediate lists never reach the model.

## What the sandbox allows

* **Tools are the only way out.** No filesystem, no network, no environment
  variables. The bound functions are the entire surface.
* **Nothing is pre-imported.** `import asyncio` before you use it. The `json`
  and `re` modules are subsets of the standard library's.
* **Keyword arguments only**: `await workflows_get(workflow_id=...)`.
* **`asyncio.gather` fans out**, but there is no `return_exceptions=`, and one
  raise loses every sibling result. Wrap an uncertain call in `try`/`except`.
* **At most 50 tool calls** per script, and a result over 20,000 characters is
  truncated. Filter and aggregate inside the script.

## Permissions are unchanged

Running code is not a way around authorization. Every call inside a script goes
through the same handler a direct call would, as the same caller, so a script
reaches exactly what your key already allows and nothing more.
