envbert-mcp
MCP server for envbert environmental due diligence (EDD) text classification — supports both stdio (Claude Code, VS Code) and streamable HTTP (Claude.ai, any remote MCP client) transports.
Classifies EDD text — site assessment reports, groundwater monitoring logs,
geological surveys — into categories like Geology, Contaminants, and
Remediation Standards using a local DistilBERT model
(d4data/environmental-due-diligence-model).
No LLM fallback, sub-second inference, and your data never leaves your machine.
Features
- Two transports, one codebase — the same tool logic is exposed over stdio and streamable HTTP; the model loads once per process and is shared across all connections.
- Three MCP tools:
check_envbert_status— check whether the model is loaded and readyclassify_environmental_text— classify a single passageclassify_environmental_document— classify every paragraph of a document concurrently, with a category breakdown and low-confidence flags
- Fast — sub-second inference after warmup, no LLM round-trip
- Local-only — the model runs on your machine; HTTP mode only binds to
localhostby default
Installation
pip install envbert envbert-mcp
Verify:
python -c "from EnvBert.due_diligence import envbert_predict; print('OK')"
envbert-mcp --help
Note: the importable module is
EnvBert(capital E and B), notenvbert.
Usage
stdio (Claude Code / VS Code)
Default mode — no flags needed. Claude Code and the Claude Code VS Code extension spawn this as a subprocess automatically once configured (see below).
envbert-mcp
Streamable HTTP (Claude.ai / remote clients)
envbert-mcp --http
Runs on http://127.0.0.1:8000 by default. First call after startup takes
10–40 seconds while the model warms up; subsequent calls are sub-second.
# custom host/port
envbert-mcp --http --host 127.0.0.1 --port 8765
# check it's alive
curl http://127.0.0.1:8000/health
# {"status": "ready", "model_ready": true, "load_error": null}
Full setup walkthrough, including auto-start scripts and login-time
launchers for macOS/Windows, is in LOCAL_SETUP.md.
Connecting a client
Claude.ai (browser)
- Start the server:
envbert-mcp --http - In Claude.ai: Settings → Integrations (or Settings → MCP Servers)
- Add server URL:
http://127.0.0.1:8000/mcp - Name it
envbertand save
Claude.ai must be running on the same machine as the server — this is a localhost URL and isn't reachable from another computer.
Claude Code
~/.claude/mcp_config.json:
{
"mcpServers": {
"envbert": {
"url": "http://127.0.0.1:8000/mcp"
}
}
}
VS Code (Continue.dev)
.continue/config.json:
{
"mcpServers": [
{
"name": "envbert",
"transport": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp"
}
}
]
}
GitHub Copilot (agent mode)
settings.json:
{
"github.copilot.chat.mcp.servers": {
"envbert": {
"url": "http://127.0.0.1:8000/mcp"
}
}
}
Auto-start
Scripts to start the server without remembering the command each time, and
optional login-time launchers, are in scripts/:
| File | Platform | Purpose |
|---|---|---|
start-unix.sh |
macOS / Linux | Start server in background, wait for health check |
start-windows.bat |
Windows | Start server minimized, wait for health check |
com.envbert.mcp.plist |
macOS | launchd agent — auto-start at login |
envbert-mcp-task.xml |
Windows | Task Scheduler task — auto-start at login |
See LOCAL_SETUP.md for install/uninstall steps for each.
Architecture
Claude Code / VS Code Claude.ai / remote clients
│ stdio │ HTTP POST /mcp
▼ ▼
envbert_mcp/server.py ←── FastMCP (single instance, both transports)
│
│ asyncio.to_thread() (keeps event loop free during ~1s inference)
▼
EnvBert.due_diligence.envbert_predict()
│
▼
DistilBERT (d4data/environmental-due-diligence-model)
Tools reference
check_envbert_status
No arguments. Returns:
{
"envbert_installed": true,
"model_ready": true,
"loading": false,
"load_error": null,
"load_time_s": 12.3,
"last_inference_ms": 850.0
}
classify_environmental_text
| Arg | Type | Description |
|---|---|---|
text |
str |
A sentence or paragraph of EDD text |
Returns label, confidence (0–1), and inference time. Confidence is the raw model estimate — below ~0.6, treat it as a best guess.
classify_environmental_document
| Arg | Type | Description |
|---|---|---|
paragraphs |
list[str] |
Paragraphs/sections, in document order |
low_confidence_threshold |
float |
Default 0.6 — paragraphs below this are flagged |
Returns per-paragraph results, a category distribution summary, and a list of low-confidence items worth a closer look.
Note on
confidence: this is a cosine similarity between the input text and a reference embedding for the predicted category — not a calibrated probability. It's a useful relative signal (higher = closer match) but shouldn't be read as "X% likely correct." Scores at or below 0.3 are already relabeledNot Relevantinternally before they reach you. Every response also includes ascore_basisfield as a reminder.
Why low-confidence flagging matters here
Without an LLM fallback, a low envbert confidence score (e.g. 0.42) is the
final answer — there's no second opinion baked in. classify_environmental_document
surfaces a low_confidence_items list explicitly so Claude can apply its
own judgement to exactly those paragraphs, rather than treating every
result as equally reliable.
Troubleshooting
Claude.ai says it can't connect:
- Confirm the server is running:
curl http://127.0.0.1:8000/health - Confirm Claude.ai is running on the same machine (not a remote browser session)
- Check your firewall isn't blocking localhost connections
Server starts but tools don't appear:
- Wait for warmup to finish —
check_envbert_statusreturns"model_ready": falseuntil it completes - Try disconnecting and reconnecting the MCP server in Claude.ai settings
envbert-mcp: command not found:
- Activate your venv first, or use the full path to the executable
More detail in LOCAL_SETUP.md.
envbert-mcp vs envbert-agent which to use
| This package (raw envbert) | envbert-agent | |
|---|---|---|
| Used by | Claude / MCP clients | CLI, pipelines, non-LLM consumers |
| LLM fallback | None | Yes — Ollama (local) or Azure |
| Typical latency | <1s always | <1s confident, ~10s on fallback |
| External dependencies | None beyond envbert | Ollama or Azure OpenAI |
| Confidence on ambiguous text | Raw model score only | LLM-resolved final label |
| Why this shape | Claude can reason over raw scores itself — a second hidden LLM call is redundant | No reasoning layer downstream; the agent must resolve ambiguity itself |
Both are legitimate — they're solving for different consumers of the classification, not competing implementations of the same thing.
License
MIT
Metadata
Release files for envbert-mcp 4.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| envbert_mcp-4.1.0.tar.gz | 12.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| envbert_mcp-4.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.0 kB
Release files / envbert_mcp-4.1.0.tar.gz
| Download URL | envbert_mcp-4.1.0.tar.gz |
|---|---|
| Size | 12.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9b2dbd233010d054ea57afb749820babfebdf99e0710c652ca75129e8d1c048f
|
|
BLAKE2b-256 checksum How to use checksums |
d969f5f1c609d033fff8778f53fde16a34dfe2b4796167e10eaf52b87299a23b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / envbert_mcp-4.1.0-py3-none-any.whl
| Download URL | envbert_mcp-4.1.0-py3-none-any.whl |
|---|---|
| Size | 9.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5a45ae279d4f49b2ae38fca1d33ba5928aa54f38de1a6927c767a77c2cf6dd2e
|
|
BLAKE2b-256 checksum How to use checksums |
cd6dab36d212c6760925f1c6dcd48b4005aace9408b0cde427b09435adc26dc7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|