Skip to main content
Glama
juanqui

joulescope-mcp

by juanqui

Record JLS

record_jls
Destructive

Record raw JS220 samples to a JLS v2 file for later waveform analysis. Specify output path and duration to capture current, voltage, and power signals.

Instructions

Record raw JS220 samples to a JLS v2 file for later waveform analysis.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
output_pathYes
duration_sYes
device_pathNo
frequency_hzNo
signalsNocurrent,voltage,power
noteNo
overwriteNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The core implementation of the record_jls tool. Opens a driver session, selects a device, configures auto range, creates a Record writer, writes raw JS220 samples to a JLS v2 file for the specified duration, then returns metadata about the recording.
    def record_jls(
        self,
        output_path: str,
        duration_s: float,
        device_path: str | None = None,
        frequency_hz: int | None = None,
        signals: str = "current,voltage,power",
        note: str | None = None,
        overwrite: bool = False,
    ) -> dict[str, Any]:
        if duration_s <= 0:
            raise JoulescopeMcpError("duration_s must be greater than 0")
        if duration_s > self._limits.max_duration_s:
            raise JoulescopeMcpError(f"duration_s must be <= {self._limits.max_duration_s}")
        path = Path(output_path).expanduser().resolve()
        path.parent.mkdir(parents=True, exist_ok=True)
        if path.exists() and not overwrite:
            raise JoulescopeMcpError(f"Output path already exists. Set overwrite=true to replace: {path}")
    
        with self._driver_session() as driver:
            device = self._select_device(driver, device_path=device_path)
            driver.open(device, mode="defaults")
            writer = None
            try:
                if frequency_hz is not None:
                    driver.publish(f"{device}/h/fs", int(frequency_hz))
                driver.publish(f"{device}/s/i/range/mode", "auto")
                driver.publish(f"{device}/s/v/range/mode", "auto")
                writer = self._record_factory(driver, [device], signals)
                user_data = [] if note is None else [[0, note]]
                writer.open(str(path), user_data=user_data)
                stop_at = time.monotonic() + float(duration_s)
                while time.monotonic() < stop_at:
                    time.sleep(min(0.05, stop_at - time.monotonic()))
            finally:
                if writer is not None:
                    writer.close()
                driver.close(device)
        return {
            "device_path": device,
            "output_path": str(path),
            "duration_s": float(duration_s),
            "signals": signals,
            "frequency_hz": frequency_hz,
            "overwrite": overwrite,
        }
  • The MCP tool registration with FastMCP, defining input parameters/output schema via type annotations: output_path (str), duration_s (float), device_path (str|None), frequency_hz (int|None), signals (str), note (str|None), overwrite (bool). Decorated with @mcp.tool annotations including file_write_tool for destructive hint.
            raise _tool_error(exc) from exc
    
    @mcp.tool(
  • The delegate function registered as an MCP tool. It calls service.record_jls(...) and wraps errors in ToolError.
    def record_jls(
        output_path: str,
        duration_s: float,
        device_path: str | None = None,
        frequency_hz: int | None = None,
        signals: str = "current,voltage,power",
        note: str | None = None,
        overwrite: bool = False,
    ) -> dict[str, Any]:
        try:
            return service.record_jls(
                output_path=output_path,
                duration_s=duration_s,
                device_path=device_path,
                frequency_hz=frequency_hz,
                signals=signals,
                note=note,
                overwrite=overwrite,
            )
        except JoulescopeMcpError as exc:
  • The _default_record_factory helper that creates a pyjoulescope_driver.Record object used inside record_jls to write JLS v2 files.
    def _default_record_factory(driver: Any, devices: list[str], signals: str) -> Any:
        if Record is None:
            raise JoulescopeMcpError("pyjoulescope_driver.Record is not available")
        return Record(driver, devices, signals)
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Description adds context beyond annotations by specifying the data type (raw JS220 samples) and file format (JLS v2). However, it does not disclose behavioral traits like file creation side effects, potential data loss, or permission requirements. Annotations already indicate destructiveHint=true, so description partially complements but lacks depth.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded with the action and purpose. No redundant or irrelevant information. Every word adds value, achieving high efficiency.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 7 parameters, no schema descriptions, and an output schema (not described), the description is insufficient for an agent to correctly invoke the tool. It lacks detail on parameter roles, defaults, and expected behavior, making the tool cryptic without additional context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, yet the description provides no information about any of the 7 parameters (e.g., output_path, duration_s, signals, overwrite). The agent cannot infer parameter meaning or usage from the description alone, leaving the schema's bare types as the only clue.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the action (record), the resource (raw JS220 samples), the output format (JLS v2 file), and the purpose (for later waveform analysis). It effectively distinguishes from sibling tools which deal with statistics, configuration, device info, etc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives. No mention of prerequisites, context, or exclusions. The description merely states what the tool does, not when or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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