๐ JouleScope JS220 MCP Server
joulescope-mcp is a Model Context Protocol (MCP) server for the JouleScope JS220 precision energy analyzer. It exposes agent-friendly tools for measuring current, voltage, power, charge, and energy, plus lower-level access to the JouleScope driver PubSub topic tree.
๐ก Primary tool
measure_energy โ provide a duration and accumulation interval, and it returns total charge and energy plus one sample per interval. For example, duration_s=15 and interval_s=0.5 returns 30 interval samples along with totals such as total_charge_mAh.
๐ Quick Start
Install directly from GitHub with uvx:
{
"mcpServers": {
"joulescope-js220": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
}
}
If you prefer SSH, use the same Git install shape with the SSH URL:
{
"mcpServers": {
"joulescope-js220": {
"command": "uvx",
"args": [
"--from",
"git+ssh://git@github.com/juanqui/joulescope-mcp.git",
"joulescope-mcp"
]
}
}
}
Then ask your MCP client:
Measure JouleScope power for 15 seconds with 500 ms intervals. Include voltage.
Expected result shape, with compact sample arrays shortened for display:
{
"total_charge_mAh": 0.0051,
"total_energy_mWh": 0.019,
"average_current_mA": 1.23,
"average_voltage_v": 3.70,
"interval_count": 30,
"sample_charge_mAh": [0.00015, 0.00015, 0.00015]
}
๐ฆ Requirements
- Python 3.11 or newer
- JouleScope JS220 connected over USB
uv for the recommended uvx install path
- An MCP client that can run stdio servers
โ ๏ธ Platform note
The Python package installs pyjoulescope_driver>=2.1.0 and pyjls>=0.17. On Linux, configure JouleScope udev rules as documented by JouleScope before running the server.
๐ก About uvx
uvx is an alias for uv tool run; it runs Python command-line tools in an isolated environment without a permanent install.
๐ฅ Install Options
Option 1: GitHub with uvx
uvx --from git+https://github.com/juanqui/joulescope-mcp joulescope-mcp
MCP JSON:
{
"mcpServers": {
"joulescope-js220": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
}
}
Use this for normal installs.
Option 2: GitHub over SSH with uvx
Use this if you prefer SSH or need GitHub SSH authentication:
uvx --from git+ssh://git@github.com/juanqui/joulescope-mcp.git joulescope-mcp
Option 3: Local Checkout
Use this while developing or when you want to pin the MCP server to a local clone:
git clone git@github.com:juanqui/joulescope-mcp.git
cd joulescope-mcp
uv sync --extra dev
uv run joulescope-mcp
Verify that the driver can see the JS220:
uv run python -m pyjoulescope_driver scan
uv run python -m pyjoulescope_driver statistics --frequency 2 --duration 1
Local checkout MCP JSON:
{
"mcpServers": {
"joulescope-js220": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/joulescope-mcp",
"run",
"joulescope-mcp"
]
}
}
}
โ ๏ธ Absolute path required
Use an absolute path. Several MCP clients launch servers with a limited PATH; if uv or uvx is not found, replace "command": "uvx" or "command": "uv" with the full executable path from which uvx or which uv.
๐งฉ Client Configuration
Most MCP clients use one of two JSON shapes:
mcpServers: Claude Desktop, Claude Code project config, Cursor, Windsurf, Cline, and many other clients
servers: VS Code / GitHub Copilot MCP config
Choose one install command:
| Current situation |
Use this command in client configs |
| Normal GitHub install |
uvx --from git+https://github.com/juanqui/joulescope-mcp joulescope-mcp |
| GitHub over SSH |
uvx --from git+ssh://git@github.com/juanqui/joulescope-mcp.git joulescope-mcp |
| Local development checkout |
uv --directory /absolute/path/to/joulescope-mcp run joulescope-mcp |
The snippets below show the normal GitHub install path.
GitHub replacement:
{
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
Local checkout replacement:
{
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/joulescope-mcp",
"run",
"joulescope-mcp"
]
}
โ ๏ธ One server per device
Configure only one always-on client for a physical JS220. Many desktop clients auto-start configured MCP servers, and the JS220 should not be shared between multiple MCP server processes.
โฑ๏ธ Timeout Configuration
measure_energy is a blocking hardware measurement. A 15 second measurement takes at least 15 seconds, plus JS220 startup and cleanup time. Configure MCP clients for a 5 minute tool timeout when they expose a timeout setting.
Recommended values:
| Setting |
Recommended value |
| Tool call timeout |
300 seconds / 300,000 ms |
| Server startup timeout |
60 seconds / 60,000 ms |
If a client does not document a timeout setting, keep synchronous measurements short enough for that client or use a client with configurable MCP tool timeouts. A future async measurement API can avoid long single tool calls, but the current measure_energy call is synchronous by design.
๐ค Claude Code
Recommended global install:
claude mcp add joulescope-js220 -- uvx --from git+https://github.com/juanqui/joulescope-mcp joulescope-mcp
claude mcp list
Launch Claude Code with 5 minute MCP tool calls and a 60 second server startup timeout:
MCP_TIMEOUT=60000 MCP_TOOL_TIMEOUT=300000 claude
Project .mcp.json:
{
"mcpServers": {
"joulescope-js220": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
}
}
Inside Claude Code, run /mcp to inspect server status. MCP_TIMEOUT and MCP_TOOL_TIMEOUT are Claude Code process environment variables, not per-server env values.
๐ฅ๏ธ Claude Desktop
Edit:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"joulescope-js220": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
}
}
Restart Claude Desktop after editing the file. Claude Desktop does not document a portable per-server timeout field in claude_desktop_config.json; if your launch environment supports MCP timeout environment variables, set MCP_TOOL_TIMEOUT=300000 before starting Claude Desktop.
๐งโ๐ป Codex
Recommended global install:
codex mcp add joulescope-js220 -- uvx --from git+https://github.com/juanqui/joulescope-mcp joulescope-mcp
codex mcp list
Direct ~/.codex/config.toml entry:
[mcp_servers.joulescope-js220]
command = "uvx"
args = ["--from", "git+https://github.com/juanqui/joulescope-mcp", "joulescope-mcp"]
startup_timeout_sec = 60
tool_timeout_sec = 300
The codex mcp add command creates the server entry. Edit ~/.codex/config.toml afterward to add startup_timeout_sec and tool_timeout_sec.
๐ฏ Cursor
Global config:
- macOS/Linux:
~/.cursor/mcp.json
- Windows:
%USERPROFILE%\.cursor\mcp.json
Project config:
{
"mcpServers": {
"joulescope-js220": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
}
}
Cursor also supports adding MCP servers from Settings. After changing the config, restart Cursor or refresh MCP tools from the MCP settings panel. Cursor does not currently document a portable mcp.json timeout field; if your Cursor build exposes a request/tool timeout in Settings, set it to 300 seconds.
๐งฉ VS Code / GitHub Copilot Agent Mode
Workspace config:
User config:
- Run
MCP: Open User Configuration from the Command Palette.
{
"servers": {
"joulescope-js220": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
}
}
Command-line install:
code --add-mcp '{"name":"joulescope-js220","type":"stdio","command":"uvx","args":["--from","git+https://github.com/juanqui/joulescope-mcp","joulescope-mcp"]}'
VS Code's MCP configuration reference does not document a per-server tool timeout field. Do not add unsupported timeout keys to .vscode/mcp.json; use shorter synchronous measurements if your Copilot host times out long calls.
๐ Windsurf
Edit:
- macOS/Linux:
~/.codeium/windsurf/mcp_config.json
- Windows:
%USERPROFILE%\.codeium\windsurf\mcp_config.json
{
"mcpServers": {
"joulescope-js220": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
]
}
}
}
Windsurf Cascade has a total enabled-tool limit. If you use many MCP servers, disable tools you do not need. Windsurf's public MCP docs do not document a portable timeout field in mcp_config.json; if your Windsurf build exposes a request/tool timeout setting, set it to 300 seconds.
๐งโ๐ง Cline
CLI install:
cline mcp add joulescope-js220 -- uvx --from git+https://github.com/juanqui/joulescope-mcp joulescope-mcp
Manual config:
- CLI default:
~/.cline/data/settings/cline_mcp_settings.json
- VS Code extension: open the MCP Servers panel, then choose Configure MCP Servers
{
"mcpServers": {
"joulescope-js220": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/juanqui/joulescope-mcp",
"joulescope-mcp"
],
"timeout": 300,
"disabled": false,
"alwaysAllow": []
}
}
}
๐ Run as HTTP
Most local MCP clients should use stdio. If you need streamable HTTP:
uvx --from git+https://github.com/juanqui/joulescope-mcp joulescope-mcp --transport streamable-http --mount-path /mcp
๐ ๏ธ Troubleshooting
| Issue |
Resolution |
Client cannot find uvx |
Use the absolute path from which uvx. |
| No JouleScope found |
Run your configured server command directly in a terminal to check startup errors, then run uvx --from pyjoulescope-driver pyjoulescope_driver scan to verify the official driver can see the JS220. |
| Permission denied on Linux |
Install JouleScope udev rules and reconnect the JS220. |
| Multiple clients fight over the device |
Run only one MCP client/server process against a JS220 at a time. |
| GitHub install fails |
Verify git clone https://github.com/juanqui/joulescope-mcp works first. |
| Tools changed but client still shows old tools |
Restart the client or reset/reload MCP tools. |
Quick local health check:
uv run python scripts/hardware_smoke.py --duration-s 2 --interval-s 0.5
๐งช Agent Workflow
For firmware or application power optimization, keep the measurement setup stable:
- Run a baseline measurement with
measure_energy.
- Apply one firmware or software change.
- Run the same
measure_energy duration and interval again.
- Compare
total_charge_mAh, total_energy_mWh, average_current_mA, and the interval samples.
- Repeat the measurement when differences are close to normal run-to-run variance.
Example request:
{
"duration_s":