joulescope-mcp
The joulescope-mcp server enables AI agents to interact with a JouleScope JS220 precision energy analyzer over USB, providing tools for measurement, device configuration, power management, and low-level hardware access.
Device Discovery & Inspection
list_devices: Enumerate connected JouleScope devices with serial numbers and firmware versionsdevice_info: Retrieve retained driver topic values and metadata for a specific deviceread_gpi: Read general-purpose input pin state as a 32-bit value
Measurements
measure_energy: Run timed measurements and return total charge (mAh), energy (mWh), average current/power, and per-interval sample arrayscapture_statistics: Frequency-based wrapper aroundmeasure_energy— specifyfrequency_hzinstead ofinterval_srecord_jls: Save raw current, voltage, and power samples to a JLS v2 file for offline analysis
Device Configuration & Power Control
configure_frontend: Set current/voltage range modes (auto,manual,off) and specific range selectionstarget_power_status: Report DUT power path stateset_target_power: Connect or disconnect power to the device under testcycle_target_power: Power-cycle the DUT with configurable hold-off and settle times
Low-Level Driver Access
list_topics: Browse the full JouleScope driver PubSub topic tree with values and metadataquery_topic: Read the value of any specific driver topicpublish_topic: Write a value to any driver topic for advanced control (destructive-capable; use with care)
Typical Agent Workflows
Firmware power optimization loops: baseline → apply change → re-measure → compare results
Automated power cycling under agent control
Waveform capture to JLS files for visual analysis
Safety guardrails enforce minimum intervals, maximum durations, and maximum interval counts on measurements.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@joulescope-mcpMeasure energy for 15 seconds with 0.5 second intervals"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.
The primary tool is 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]
}Related MCP server: Enapter MCP Server
Requirements
Python 3.11 or newer
JouleScope JS220 connected over USB
uvfor the recommendeduvxinstall pathAn MCP client that can run stdio servers
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.
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-mcpMCP 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-mcpOption 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-mcpVerify that the driver can see the JS220:
uv run python -m pyjoulescope_driver scan
uv run python -m pyjoulescope_driver statistics --frequency 2 --duration 1Local checkout MCP JSON:
{
"mcpServers": {
"joulescope-js220": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/joulescope-mcp",
"run",
"joulescope-mcp"
]
}
}
}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 clientsservers: VS Code / GitHub Copilot MCP config
Choose one install command:
Current situation | Use this command in client configs |
Normal GitHub install |
|
GitHub over SSH |
|
Local development checkout |
|
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"
]
}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:
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 listLaunch Claude Code with 5 minute MCP tool calls and a 60 second server startup timeout:
MCP_TIMEOUT=60000 MCP_TOOL_TIMEOUT=300000 claudeProject .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.jsonWindows:
%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 listDirect ~/.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 = 300The 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.jsonWindows:
%USERPROFILE%\.cursor\mcp.json
Project config:
.cursor/mcp.json
{
"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:
.vscode/mcp.json
User config:
Run
MCP: Open User Configurationfrom 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.jsonWindows:
%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-mcpManual config:
CLI default:
~/.cline/data/settings/cline_mcp_settings.jsonVS 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 /mcpTroubleshooting
Client cannot find
uvx: use the absolute path fromwhich 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 scanto 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-mcpworks 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.5Agent 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_energyduration 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": 15,
"interval_s": 0.5,
"compact": true
}The response includes:
total_charge_mAh: total charge over the measurement windowtotal_energy_mWh: total energy over the measurement windowaverage_current_mA: average current over the actual captured durationaverage_power_mW: average power over the actual captured durationactual_interval_s: average actual interval captured by the JS220sample_charge_mAh: compact per-interval charge list whencompact=truesample_energy_mWh: compact per-interval energy list whencompact=truesample_voltage_avg_v,sample_voltage_min_v,sample_voltage_max_v: compact per-interval voltage lists whencompact=trueandinclude_voltage=truesamples: full per-interval statistics whencompact=false
If duration_s is not an exact multiple of interval_s, the server rounds up to the next full interval and reports both requested_duration_s and actual_duration_s.
Tools
list_devices
Lists connected JouleScope devices. For JS220 devices, it attempts to include hardware, firmware, and FPGA versions.
device_info
Returns retained driver topic values for a selected device. Set include_metadata=true to include topic metadata returned by the driver.
measure_energy
Measures charge and energy using JS220 sensor-side statistics.
Parameters:
duration_s: requested measurement duration in secondsinterval_s: accumulation interval in secondsdevice_path: optional explicit device path, such asu/js220/005920configure_auto_range: defaults to true; configures current and voltage range modes toautocompact: returns compact charge and energy arrays and omits full samplesinclude_voltage: when used withcompact, also returns per-interval voltage arrays
Implementation detail: the JS220 publishes per-interval current.integral in coulombs and power.integral in joules. The server sums those integrals, then also converts charge to mAh and energy to mWh.
capture_statistics
Frequency-based wrapper around measure_energy. Use when you want frequency_hz instead of interval_s.
configure_frontend
Sets current and voltage range modes and optional range selections. Use auto for normal measurements.
target_power_status
Reports whether the JS220 target/DUT power path is connected. For JS220, DUT power is controlled through s/i/range/mode: off disconnects Current+ from Current-, while auto or manual connects the target path for measurement.
set_target_power
Connects or disconnects power to the DUT through the JS220 current path.
Parameters:
power_on: true to connect target power, false to disconnect iton_mode:autoby default, ormanualsettle_ms: optional wait after changing state
cycle_target_power
Power-cycles the DUT by setting target power off, waiting, then restoring target power.
Parameters:
off_ms: hold-off time in millisecondson_mode:autoby default, ormanualsettle_ms: optional wait after restoring power
record_jls
Records raw samples to a JLS v2 file using the JouleScope driver's Record API. This is useful for later waveform analysis in the JouleScope UI or JLS tooling. Existing files are rejected unless overwrite=true.
read_gpi
Reads JS220 general-purpose input state and returns a 32-bit value plus decoded pins.
list_topics
Lists retained driver topics, values, and optional metadata. This is the discovery tool for advanced JS220 capabilities.
query_topic
Queries one driver topic. Relative topics are resolved under the selected device, so c/fw/version becomes u/js220/<serial>/c/fw/version.
publish_topic
Publishes a value to a driver topic. This exposes advanced JS220 features and can change device behavior. Prefer typed tools when available.
Resources and Prompts
Resources:
joulescope://devices: JSON device listjoulescope://driver: server and driver version information
Prompt:
power_optimization_session: template for measurement-driven power optimization loops
Safety and Limits
The server opens a short-lived JouleScope driver connection per tool call and serializes device access inside one server process. Blocking measurements have guardrails:
Minimum interval: 0.5 ms
Maximum duration: 3600 seconds
Maximum returned intervals: 10,000
Statistics collection times out if the JS220 does not publish the expected samples
set_target_power, cycle_target_power, record_jls, and publish_topic are marked as write/destructive-capable MCP tools. cycle_target_power intentionally interrupts the DUT. Agents should use it only when an interruption is part of the requested test.
Development
Set up a local checkout:
uv sync --extra devRun tests:
uv run python -m pytestRun linting:
uv run python -m ruff check .Build the package:
uv run python -m buildHardware smoke test:
uv run python -m pyjoulescope_driver scan
uv run python -m pyjoulescope_driver statistics --frequency 2 --duration 1
uv run python - <<'PY'
from joulescope_mcp.service import Js220Service
r = Js220Service().measure_energy(duration_s=2, interval_s=0.5)
print(r["total_charge_mAh"], r["average_current_mA"], [s["charge_mAh"] for s in r["samples"]])
PYRepeatable hardware smoke script:
uv run python scripts/hardware_smoke.py --duration-s 2 --interval-s 0.5Design
See docs/design.md for the MCP design, measurement semantics, tool rationale, and verification strategy. See docs/testing.md for repeatable software, MCP, and hardware checks. See docs/adversarial-reviews.md for the implementation and README review logs.
References
JouleScope downloads and documentation: https://www.joulescope.com/pages/downloads
JouleScope driver documentation: https://joulescope-driver.readthedocs.io/
JouleScope driver source: https://github.com/jetperch/joulescope_driver
JouleScope
dut_power.pyexample: https://github.com/jetperch/pyjoulescope_examples/blob/main/bin/dut_power.pyMCP Python SDK: https://github.com/modelcontextprotocol/python-sdk
uvxtool execution: https://docs.astral.sh/uv/concepts/tools/
Client configuration references used for the examples above:
Client | References |
Claude Code | |
Claude Desktop | MCP local server quickstart, Anthropic custom connectors note |
Codex | OpenAI Docs MCP Codex quickstart, Codex MCP interface notes, plus local verification with |
Cursor | |
VS Code / GitHub Copilot | Add and manage MCP servers in VS Code, VS Code MCP configuration reference |
Windsurf | Windsurf MCP integration docs, Windsurf MCP client guide from Grafana |
Cline |
Popular MCP setup examples reviewed:
GitHub MCP Server installation guides: https://github.com/github/github-mcp-server/tree/main/docs/installation-guides
Context7 MCP installation guide: https://context7.mintlify.dev/docs/installation
MCP local server quickstart: https://modelcontextprotocol.io/docs/develop/connect-local-servers
OpenAI Docs MCP client examples: https://developers.openai.com/learn/docs-mcp
License
Apache License 2.0. See LICENSE.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/juanqui/joulescope-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server