Skip to main content

OriginLab-MCP

An MCP server for OriginLab Origin. It reads and writes worksheets, builds and styles multi-panel graphs, and exports figures — and it is careful about the difference between what Origin accepted and what Origin did.

1.0.0. Every tool here has been run against a real Origin 2024, the Origin App installs and starts the bridge, and examples/five_panel_figure.py builds a five-panel figure end to end.

Known gaps, so they are not a surprise: a legend placed in a corner is checked for being inside its panel, not for sitting on top of the data; a log axis gets no minor ticks unless you ask; and the 213-entry option table records what Origin documents, not what each option was measured to do — sixteen of them have been watched change a picture.

Requirements

  • Origin or OriginPro 2021b or newer (embedded Python 3.9+)
  • Python 3.10+ for the server
  • Windows, either natively or in a VM

Install

pip install originlab-mcp
originlab-mcp --build-app .

That prints the three steps Origin needs, which are worth stating here because the obvious one does nothing: dragging the folder onto the Apps gallery is accepted in silence and adds no button. Copy the generated OriginLab MCP Bridge folder into %LOCALAPPDATA%\OriginLab\Apps, pack it from Origin's Command Window with

mkOPX app:="OriginLab MCP Bridge" opx:="C:\path\to\OriginLab MCP Bridge.opx";

— backslashes, because forward slashes hang mkOPX — and drag the resulting .opx into Origin. A button appears; clicking it brings the Script Window forward, where the bridge reports starting, loaded, serving.

Point your MCP client at originlab-mcp.

originlab-mcp --status says whether a bridge is listening, and exits non-zero when one is not. originlab-mcp --stop ends it.

Stopping is a command rather than a second button because a button must not do the work itself: while the bridge serves it holds Origin's UI thread, so anything the button ran would run from inside the message pump. A button that only spawns an external process is possible -- that is how the upstream project does it -- but the instruction still has to reach the bridge over the socket, and --stop is that instruction without the indirection.

What's different

Origin accepts a great deal that it then ignores, without ever saying so.

  • set <plot> -zzzz 9 — an option Origin has never heard of — returns true, reads back as 9.0, and leaves the graph pixel-for-pixel identical.
  • plot:=2003 is not a plot type. Origin makes the window, draws the axes, writes the legend, and plots nothing.
  • A style written to a plot inside a group reads back exactly as requested, while Origin goes on drawing the group's style.

None of these is catchable from the reply, so the checking happens before the write and after the figure:

Before. Options are checked against Origin's own documented list, and an invented one is refused with the options it was probably meant to be. This matters because the real names are unguessable — line width is -w, bar fill pattern is -pfp — so a plausible guess is the likely failure, not a typo. Writing to a grouped plot member is refused outright. Plot types come from oPlotIDs.h in the Origin installation rather than from documentation, and every name in the table was drawn and looked at.

After. A per-call check cannot reach the question that matters, which is whether the figure is right. So the operations that build one report the thing that could contradict them:

operation what it reports back
origin_plot the layer used, and how many plots Origin says are in it
origin_layers_arrange every layer's real geometry, and the box they all occupy
origin_legend_set where the legend is, and whether that is inside its layer
origin_axis_set which side of the frame the title landed on

That list exists because of a measured failure: a five-panel figure where all twenty-three steps returned OK and the result was unusable. One legend had been placed at left = 24953 on a page 6432 wide — legend.x is in data coordinates, not the percentages it was being given — and Origin's export grew the canvas to contain it, squeezing the figure into a corner. Nothing in any reply said anything was wrong.

A read-back is reported as a read-back, never as proof:

{
  "requested": 60,
  "readback": {"readable": true, "value": 60.0, "matches_request": true},
  "readback_means": "Origin stored this value where 'get' can find it. It is not
                     proof that the graph changed: Origin also stores options it
                     does not recognise."
}

Exporting the graph is the only thing that settles it, which is why origin_graph_export is a first-class tool rather than a way to save pictures.

Arguments this server does not read are refused, with the nearest name it does. The same failure it guards against in Origin turned up here first: worksheet_read takes max_rows, and a call passing rows=3 used to get every row in the sheet and no indication its argument had been dropped.

The tool surface is small on purpose. One plot tool with a plot_type parameter rather than one per chart type; one plot_option_get/set pair rather than a wrapper per property.

Tools

origin_ping Is the bridge alive — answers even when originpro is broken
origin_bridge_status Where the bridge is, and whether it is answering
origin_worksheet_info Size, column names, formats
origin_worksheet_read Columns as lists, refusing rather than truncating
origin_worksheet_write Columns in, with the format stated not guessed
origin_plot Plot columns into a new page or a new layer of an existing one
origin_graph_info Layers, plots, addresses, group membership
origin_graph_export PNG out — and the only witness that a style took
origin_layer_add Add a panel, and say what its index is
origin_layers_arrange Grid the panels, and report where they really went
origin_legend_set Rebuild a legend, place it, check it is inside its panel
origin_axis_set Scale, range and title, with the title's side reported
origin_axis_get Read an axis back
origin_plot_option_get Read one LabTalk set option
origin_plot_option_set Write one, and report what that established
origin_set_options Search Origin's 213 documented set options
origin_labtalk The escape hatch, with Origin's output captured

examples/five_panel_figure.py builds a five-panel figure end to end and prints, at every step, the number that could contradict it.

Setups

Windows, everything local — the usual case. Server and Origin on the same machine, talking over loopback TCP.

Origin in a Windows VM, working from macOS or Linux — also supported. The server runs inside the VM over ssh; only the MCP client is on the host. This works because the server reaches Origin through a loopback socket rather than COM, which cannot cross a Windows session boundary.

MCP client  ──ssh──▶  server (Windows)  ──TCP 127.0.0.1──▶  Origin

docs/remote-origin.md walks through that one: the ssh server, the key (Windows puts an administrator's in a different file and ignores the usual one without saying so), and pointing an MCP client at it.

Notes on Origin's behaviour

Things measured here that no documentation mentions:

  • originpro is single-threaded, absolutely. Called from any thread but Origin's UI thread it blocks while holding the GIL and deadlocks the whole embedded interpreter. Origin's window stays responsive; its Python is gone. The bridge therefore serves on that thread and pumps Origin's message queue between requests.
  • A modal dialog stops the bridge, because the dialog holds the thread the bridge serves on — while the handshake file goes on saying it is up. Exporting into a directory that does not exist opens one, so that is checked before the export is sent.
  • A legend has two pairs of coordinates in different spaces. legend.x/legend.y are the layer's data coordinates; legend.left/.top are page units, the same ones page.width reports.
  • plotxy ogl:=<new> makes a new layer, not a new page, and does not make it active. [<new>] is the new page.
  • Origin exchanges the axes for bar charts and reports it through no layer property. It moves the title objects to match and keeps their rotation, so the value-axis title ends up under the frame reading bottom to top.
  • -w is points × 500; -wp takes points. Passing a point value to -w gives a hairline rather than an error.
  • A fill pattern set with -pfp alone is invisible: Origin draws it in the fill colour, so -pfc is needed too, and neither changes anything on its own.
  • LabTalk stops at the first statement it rejects, so a script that reports failure has run an unknown prefix of itself.
  • Origin refuses to start Python while a command is in flight, and every bridge request is one. Scripts containing run -pyf or py.exec are refused up front rather than failing without explanation.

References

Origin and OriginPro are products of OriginLab Corporation. This project is not affiliated with OriginLab.

Licence

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

originlab_mcp-1.0.0.tar.gz (337.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

originlab_mcp-1.0.0-py3-none-any.whl (76.2 kB view details)

Uploaded Python 3

File details

Details for the file originlab_mcp-1.0.0.tar.gz.

File metadata

  • Download URL: originlab_mcp-1.0.0.tar.gz
  • Upload date:
  • Size: 337.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for originlab_mcp-1.0.0.tar.gz
Algorithm Hash digest
SHA256 1243fe77b6e6f86569006ff2773472425ca61bcdf18dd8768ba1b5e197438e15
MD5 2ac386dc85d93e7179856a1553e8948f
BLAKE2b-256 ac68918fd918fd9e04ca7bccd41f280cf09bc7a22fa82ed058a339a3dfd53627

See more details on using hashes here.

Provenance

The following attestation bundles were made for originlab_mcp-1.0.0.tar.gz:

Publisher: release.yml on Yike-Ye/OriginLab-MCP

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file originlab_mcp-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: originlab_mcp-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 76.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for originlab_mcp-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a4b866df7f95f936bd74ea8181b2bd07a5d25b7da867bc13670d8a790f6fcc2e
MD5 38abf7c0d26762f0658d2d8ac7c3b7cd
BLAKE2b-256 74f031964539f3443b1385303e3d5ec7516526998b466315f916dc849f38bfb4

See more details on using hashes here.

Provenance

The following attestation bundles were made for originlab_mcp-1.0.0-py3-none-any.whl:

Publisher: release.yml on Yike-Ye/OriginLab-MCP

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page