SerenWorkbench
The tool surface an LLM reaches through.
One process on port 7425 serving an MCP endpoint, an operator dashboard and a small HTTP API. Builtin tools cover memory, web search, time, cluster control and the scheduler. On top of those, you can add your own tools as YAML files — no Python, no restart.
Part of the Seren stack, but it doesn't require the rest of it. Point it at whichever services you actually run.
Install
pip install seren-workbench
python -m seren_workbench
That's a working server with the builtin tools and an empty tool
directory. Configuration is optional — copy seren-workbench.yaml.sample
to seren-workbench.yaml when you want to change ports, service URLs or
which tools start enabled.
python -m seren_workbench --config /etc/seren/workbench.yaml --port 7425
Connect a client
The MCP endpoint is at /mcp/ (trailing slash — a bare /mcp gets a 307).
{
"mcpServers": {
"seren-workbench": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://127.0.0.1:7425/mcp/",
"--transport", "http-only"]
}
}
}
Set a bearer token in the config (or SEREN_WORKBENCH_BEARER_TOKEN) before
this leaves localhost - a bind beyond loopback with no token refuses to start
and prints the ways out.
If Memory or Lodestar were installed with a token, tell the builtins what to present:
services:
bearer_token_env: SEREN_CLUSTER_TOKEN # one token for memory / lodestar / scheduler
# memory_bearer_token_env: SEREN_MEMORY_TOKEN # or per service
Adding your own tools
Drop a YAML file in tools_dir (default ~/seren-workbench/tools):
schema_version: 1
tools:
- name: disk_free
description: >
Report free space on the Seren data volume. Use when someone asks
whether there's room for another model.
invoke:
kind: process
argv: ["df", "-h", "--", "{mount_point}"]
parameters:
- name: mount_point
type: string
required: true
pattern: "/[A-Za-z0-9._/-]*"
Then reload — the tool is live immediately, no restart:
curl -X POST localhost:7425/tools/manifests/reload
Tools can run a process or make a web call. Parameters are typed,
defaulted, range-checked and — for strings — matched against a pattern
or an enum, with the rules published into the JSON schema so the model
reads them rather than discovering them by being corrected.
→ docs/TOOL-MANIFESTS.md is the full reference. examples/tools/example-tool.yaml is an annotated file you can copy; the test suite loads it, so it can't quietly stop being true.
Tools the model asks for
A model can propose a tool for itself with propose_tool. The manifest lands
in a staging directory that nothing loads — it's inert text until you read
it and approve, at which point it moves into tools/ and goes live.
Open /viewer → Proposals; the tab shows a count when something's waiting.
Or from the shell:
curl -s localhost:7425/proposals # what's waiting
curl -s localhost:7425/proposals/prop_a1b2c3d4e5 # the manifest + what it would run
curl -X POST localhost:7425/proposals/prop_a1b2c3d4e5/approve
curl -X POST localhost:7425/proposals/prop_a1b2c3d4e5/reject \
-d '{"critique":"argv shells out to a script I cannot read"}'
Approving installs it switched off. The tool appears in your list, disabled; you turn it on separately from the Tool State tab. Two decisions — "this isn't malicious" and "I want it live now" — kept apart on purpose.
The model can propose and read its proposals. It cannot approve — there's no MCP tool behind any approval route, and a test asserts there never is. Reject requires a critique, which the proposer reads and can revise against; same loop as the memory consolidator's draft gate.
Turn it off with dashboard.proposals_enabled: false, which removes the tools
entirely rather than leaving them to fail.
→ docs/TOOL-PROPOSALS.md — what to look at when reviewing one.
What reload won't do
It reads files that are already on disk. It cannot author a tool, it refuses a manifest that would shadow a builtin, it won't re-enable something you switched off, and it treats a missing tools directory as "something's wrong" rather than "delete everything." A tool exists because a person put it somewhere.
Neither does a restart re-enable anything: toggles are remembered in
<tools_dir>/.tool-state.json. A remote from: import may only hand you
kind: web tools, and no tool may point back at the Workbench itself.
Endpoints
GET / |
service info, tool counts and update status |
GET /health |
liveness |
GET /tools |
every tool with its schema |
GET/POST /tools/state |
enable and disable, per tool or per action |
GET /tools/manifests |
what loaded, what was skipped, and why |
POST /tools/manifests/reload |
re-read the directory, apply it live |
GET /proposals |
tools the model has asked for |
GET /proposals/{id} |
one, with the full manifest and what it would run |
POST /proposals/{id}/approve |
install it, switched off |
POST /proposals/{id}/reject |
refuse it, with a critique |
GET /config |
resolved config, secrets masked |
GET /logs |
recent server logs |
/mcp/ |
the MCP streamable-HTTP transport |
/viewer |
the operator dashboard |
Update checking
GET / reports whether a newer seren-workbench has been published, alongside
the tool counts:
{
"service": "SerenWorkbench",
"version": "1.2.0",
"tools_count": 26,
"updates": {
"status": "ok",
"installed": "1.2.0",
"latest": "1.3.0",
"update_available": true
}
}
Opt-in, because a box that never leaves the LAN has no business calling PyPI:
pip install 'seren-workbench[updates]'
updates:
enabled: true
check_interval_hours: 6 # cached; never checked per-request
allow_prerelease: false
The result is cached and the check never happens in the request path, so /
stays fast. updates.status is always one of ok, disabled, unavailable
(the extra isn't installed) or error — never absent, and never a silent
"you're fine" when it couldn't actually check.
SEREN_WORKBENCH_UPDATES_ENABLED=false turns it off without editing config.
The Workbench never upgrades itself. Applying an update is pip install -U seren-workbench and a restart — your service supervisor's job, not this
process's. A running process can't reliably swap its own code out from under
itself, so it doesn't pretend to.
Development
pip install -e ".[dev]"
pytest -q
License
GPL-3.0-or-later.
Release files for seren-workbench 2.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| seren_workbench-2.0.1.tar.gz | 147.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| seren_workbench-2.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 275.5 kB
Release files / seren_workbench-2.0.1.tar.gz
| Download URL | seren_workbench-2.0.1.tar.gz |
|---|---|
| Size | 147.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2f39ea67de02d8a23d44f39e9d3206e6a2d3dbb2456354240b47128d424190e2
|
|
BLAKE2b-256 checksum How to use checksums |
dafdb25816550bed370aeb337bce6b631e27999b5240cd726d0d7b23b6adc5fd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / seren_workbench-2.0.1-py3-none-any.whl
| Download URL | seren_workbench-2.0.1-py3-none-any.whl |
|---|---|
| Size | 127.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eb41a01ad514f182deefb696e2e5533106f6c677a74789ff1da0ec929ecb35c7
|
|
BLAKE2b-256 checksum How to use checksums |
124e438916f82d795be15fb09a3ac168d682c3f9fe79075811b51eb98cca87fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency log