Skip to content

Latest commit

 

History

History
170 lines (139 loc) · 7.3 KB

File metadata and controls

170 lines (139 loc) · 7.3 KB

Control Suite MCP APS 2-ID-D

This project exposes APS 2-ID-D MIC controls through FastMCP over HTTP and executes beamline actions through Bluesky QueueServer.

Architecture

MCP client -> FastMCP HTTP server -> REManagerAPI -> Bluesky QueueServer

The MCP service is a thin allowlisted control layer over QueueServer. It does not run a local RunEngine and it does not expose arbitrary QueueServer plans or functions.

Setup

Install the package into the target environment:

pip install -e .

The environment needs:

  • fastmcp
  • bluesky-queueserver-api

It does not require the old local worker/ZMQ stack.

Configuration

A repo-level config.toml provides the default MCP server configuration, including:

  • host/port/path
  • allowable x, y, and z ranges
  • QueueServer addresses
  • approved QueueServer plan names for acquisition and motion

CLI flags still override TOML values when needed.

Run

Start the MCP server with the repo config:

control-suite-aps-2idd-mcp --config config.toml

If QueueServer is running on the same host as the MCP server, keep the default 127.0.0.1 QueueServer addresses in config.toml. Otherwise, update the [qserver] section.

You can still override specific values from the command line, for example:

control-suite-aps-2idd-mcp   --config config.toml   --qserver-control-addr tcp://[hostname]:60615   --qserver-info-addr tcp://[hostname]:60625   --allowable-x-range 0,50   --allowable-y-range 0,50

MCP URL

Clients should connect to:

http://127.0.0.1:8050/mcp

Tools

  • aps2idd_control.health()
  • aps2idd_control.get_state()
  • aps2idd_control.get_current_mda_file()
  • aps2idd_control.get_save_data_path()
  • aps2idd_control.get_global_health_snapshot()
  • aps2idd_control.recover_detector(device_name, retries=1)
  • aps2idd_control.acquire_image(width, height, x_center, y_center, stepsize_x, stepsize_y, dwell_ms=None)
  • aps2idd_control.process_image(current_mda_file, save_data_path=None, plot_in_log_scale=None, show_colorbar=None, channels=None)
  • aps2idd_control.dump_array(buffer_name)
  • aps2idd_control.acquire_line_scan(positioner_name, length, stepsize, center=0, sample_x=None, sample_y=None, sample_z=None, energy=None, dwell_ms=None)
  • aps2idd_control.move_sample(axis, position)
  • aps2idd_control.move_zp_z(position)
  • aps2idd_control.set_parameters(parameters)
  • aps2idd_control.get_attribute_payload(name)

After aps2idd_control.acquire_line_scan() succeeds, the service keeps image_0, image_km1, and image_k buffers plus matching psize_0, psize_km1, and psize_k values inferred from the line-scan step size. aps2idd_control.dump_array() returns those image buffers as base64-encoded NumPy payloads.

MCP Client Configuration

For an HTTP MCP client:

{
  "mcpServers": {
    "control-suite-aps-2idd": {
      "url": "http://127.0.0.1:8050/mcp",
      "transport": "http"
    }
  }
}

Tool Contract Notes

  • Scan dimensions, positions, and step sizes are in microns unless noted otherwise.
  • aps2idd_control.move_zp_z(position) drives the zone-plate z positioner, validated against allowable_zp_range (distinct from the sample z motor's allowable_z_range). aps2idd_control.set_parameters(parameters) is equivalent, using parameters[0] as the zp-z target (also validated against allowable_zp_range).
  • Motion and acquisition tools are QueueServer plans, submitted with item_execute. Plans return an item_uid (not a task_uid); the service waits for the RE manager to return to idle and reads the outcome from QueueServer history. task_uid is only produced by QueueServer functions (e.g. get_save_data_path).
  • aps2idd_control.get_global_health_snapshot() returns a beamline + scan device snapshot ({"timestamp": ..., "devices": {name: {"pvs": {...}}}}) covering ring, sample, scanrecord, the area detectors, and fly_dwell. It is the observable for beamline/scan health monitoring and is safe to poll while a scan runs (executed as a background QueueServer function). The device set is driven by the beamline monitor manifest (qserver.beamline_monitor_manifest).
  • aps2idd_control.recover_detector(device_name, retries=1) attempts to unhang a stalled area detector (e.g. xmap, xp3, eiger). If a plan is running it pauses the RE (immediate), resets the detector through the allowlisted QueueServer recover_detector function, then resumes; an already-paused RE is left paused. The result includes device, success, and a progress step list.
  • aps2idd_control.acquire_image and aps2idd_control.acquire_line_scan stream live scan progress as MCP progress notifications, sourced from the QueueServer console (ZMQ info) output. Their results report item_uid, run_uids, scan_ids, save_data_path, and current_mda_file. current_mda_file is captured before the plan runs (the savedata next_file_name auto-increments once the scan starts), so it names the MDA file that scan actually wrote.
  • After the scan, acquisition tools process the MDA/HDF5 output and write file artifacts. acquire_image returns absolute img_path and raw_data_path fields for the rendered PNG and 2D .npy array. acquire_line_scan returns absolute img_path and raw_data_path fields for the plotted line profile and .npy profile data, plus gaussian_fit_params with fwhm, a, mu, sigma, c, normalized_residual, x_min, and x_max. Successful line scans also update the in-process image_0, image_km1, image_k, psize_0, psize_km1, and psize_k attributes.
  • aps2idd_control.process_image runs the same postprocessing as aps2idd_control.acquire_image on an existing MDA file, so already-acquired data can be (re)visualized without a new scan — no beamline motion and no QueueServer plan. save_data_path defaults to the current QueueServer save path, and plot_in_log_scale, show_colorbar, and channels default to the service configuration. It returns img_path, raw_data_path, channel, h5_path, mda_path, save_data_path, and current_mda_file.
  • aps2idd_control.acquire_line_scan drives the axis named by positioner_name (x, y, z, or energy); length, center, and stepsize are in that positioner's units (microns for x/y/z, keV for energy). center is a relative offset from the positioner's position at scan time (e.g. center=0 scans symmetrically around the current position). The step1d_scanrecord plan moves the sample/energy to the optional sample_x/sample_y/sample_z/ energy positions (current position is kept for any left unset) before scanning.
  • Dwell time per point: pass dwell_ms to override per call; when omitted the acquisition uses the configured dwell_imaging (images) or dwell_line_scan (line scans) value.
  • Range validation: any explicitly provided absolute position (sample_x/sample_y/sample_z/energy) is validated against its axis range (allowable_x/y/z_range in microns, allowable_energy_range in keV). The relative scan extent (target + center ± length/2) is only validated when the driven axis's absolute target is supplied; with no target the current position is unknown, so the absolute extent cannot be checked.