joulescope-mcp

joulescope-mcp

MCP server for the JouleScope JS220 precision energy analyzer, enabling agents to measure current, voltage, power, charge, and energy via tools like measure_energy.

Category
Visit Server

README

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]
}

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

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-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"
      ]
    }
  }
}

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"
  ]
}

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 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:

  • .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 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

  • 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:

  1. Run a baseline measurement with measure_energy.
  2. Apply one firmware or software change.
  3. Run the same measure_energy duration and interval again.
  4. Compare total_charge_mAh, total_energy_mWh, average_current_mA, and the interval samples.
  5. 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 window
  • total_energy_mWh: total energy over the measurement window
  • average_current_mA: average current over the actual captured duration
  • average_power_mW: average power over the actual captured duration
  • actual_interval_s: average actual interval captured by the JS220
  • sample_charge_mAh: compact per-interval charge list when compact=true
  • sample_energy_mWh: compact per-interval energy list when compact=true
  • sample_voltage_avg_v, sample_voltage_min_v, sample_voltage_max_v: compact per-interval voltage lists when compact=true and include_voltage=true
  • samples: full per-interval statistics when compact=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 seconds
  • interval_s: accumulation interval in seconds
  • device_path: optional explicit device path, such as u/js220/005920
  • configure_auto_range: defaults to true; configures current and voltage range modes to auto
  • compact: returns compact charge and energy arrays and omits full samples
  • include_voltage: when used with compact, 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 it
  • on_mode: auto by default, or manual
  • settle_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 milliseconds
  • on_mode: auto by default, or manual
  • settle_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 list
  • joulescope://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 dev

Run tests:

uv run python -m pytest

Run linting:

uv run python -m ruff check .

Build the package:

uv run python -m build

Hardware 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"]])
PY

Repeatable hardware smoke script:

uv run python scripts/hardware_smoke.py --duration-s 2 --interval-s 0.5

Design

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

Client configuration references used for the examples above:

Client References
Claude Code Claude Code MCP docs, Claude Code support FAQ
Claude Desktop MCP local server quickstart, Anthropic custom connectors note
Codex OpenAI Docs MCP Codex quickstart, Codex MCP interface notes, plus local verification with codex mcp add --help and codex mcp list
Cursor Cursor MCP configuration docs, Cursor CLI MCP docs
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 Cline CLI configuration, Cline MCP overview

Popular MCP setup examples reviewed:

License

Apache License 2.0. See LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured