Install
$ agentstack add mcp-techmanual-ai-lablink-mcp ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
LabLink
Unified & extensible MCP server enabling connectivity to all types of lab equipment
Install · Quick Start · Tools · Configuration · CLI · Contributing
What is LabLink?
LabLink gives an AI agent direct, structured access to lab hardware and services — without a human in the loop. Connect by alias, send commands, read results, and iterate across any combination of devices in a single session.
- 5 protocol drivers out of the box: VISA/SCPI, SSH, REST, serial, and a Python subprocess shell
- Per-protocol tool names (
visa_query,ssh_exec,rest_get) — no leaky one-size-fits-all interface - Install only what you need — drivers are optional extras; the server runs with zero installed
diagnose()surfaces exactly what is missing or unreachable before the agent tries to use it- Extensible — add a driver with no changes to the core server or CLI
Supported Protocols
Each device is addressed by an alias whose config type field selects the driver. Per-driver tools register only when that driver's dependencies are installed.
| Protocol | type | Transport | Operation tools | Extra | Hardware-validated | |----------|--------|-----------|-----------------|-------|:------------------:| | VISA / SCPI | visa | PyVISA (USB-TMC, TCPIP, GPIB, Serial) | visa_query, visa_write | [visa] | ✅ | | SSH | ssh | Paramiko | ssh_exec, ssh_shell_session, ssh_start_stream, ssh_read_stream, ssh_stop_stream | [ssh] | ✅ | | REST | rest | httpx | rest_get, rest_post, rest_put, rest_patch, rest_delete | [rest] | ✅ | | Serial | serial | pyserial (RS232/RS422/RS485) | serial_query, serial_write, serial_read, serial_flush | [serial] | ⚪ | | Python shell | python_shell | subprocess REPL | python_shell_exec, python_shell_eval | [python_shell] | ✅ |
An external routing stub also lets a device be handled by a vendor-supplied MCP server, surfacing routing hints to the agent on connect().
> Legend — ✅ exercised end-to-end on real hardware · ⚪ covered by unit tests with the > driver library mocked (real use needs real hardware).
📦 Install
pip install lablink-mcp # core only (no drivers)
pip install lablink-mcp[visa] # + PyVISA
pip install lablink-mcp[ssh] # + Paramiko
pip install lablink-mcp[all] # all drivers
🚀 Quick Start
1. Create a device config
One TOML file per device at ~/.lablink/devices/.toml. The type field selects the driver.
VISA instrument:
# ~/.lablink/devices/tek_mso44.toml
type = "visa"
alias = "tek_mso44"
resource_string = "USB0::0x0699::0x0527::C012345::INSTR"
manufacturer = "Tektronix"
model_number = "MSO44"
timeout_ms = 5000
description = "4-channel mixed signal oscilloscope"
Find your resource string:
python -c "import pyvisa; print(pyvisa.ResourceManager('@py').list_resources())"
SSH host:
# ~/.lablink/devices/rpi_dev.toml
type = "ssh"
alias = "rpi_dev"
host = "192.168.1.42"
port = 22
username = "pi"
auth_type = "ssh_key"
auth_ssh_key_path = "~/.ssh/id_rsa"
timeout_ms = 10000
See [examples/configs/](examples/configs/) for templates for all drivers.
2. Verify with the CLI
lablink list # show all configured devices
lablink connect tek_mso44 # open session, print identity
lablink visa query tek_mso44 "*IDN?" # send SCPI query
3. Add to your MCP client
Claude Code — add to ~/.claude.json (global) or .mcp.json in your project root:
{
"mcpServers": {
"lablink-mcp": {
"command": "lablink-mcp"
}
}
}
Claude Desktop — add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"lablink-mcp": {
"command": "lablink-mcp"
}
}
}
MCP Tools
Shared lifecycle (all drivers)
| Tool | Description | |------|-------------| | connect(alias) | Open session, return identity, device memory, and topology slice | | disconnect(alias) | Close session | | list_devices() | List all configured aliases with status | | diagnose(alias?) | Reachability and dependency check; system audit (with topology warnings) when no alias given | | system_topology(alias?) | Return the bench wiring map; or a single device's slice |
Per-driver operation tools
| Driver | Tools | |--------|-------| | visa | visa_query, visa_write | | ssh | ssh_exec, ssh_shell_session, ssh_start_stream, ssh_read_stream, ssh_stop_stream | | rest | rest_get, rest_post, rest_put, rest_patch, rest_delete | | serial | serial_query, serial_write, serial_read, serial_flush | | python_shell | python_shell_exec, python_shell_eval |
Per-driver tools are only registered when that driver's dependencies are installed. All tools return structured dicts. On failure:
{"success": false, "error": "VISA timeout", "hint": "Check that the instrument is powered on."}
Device Configuration
One TOML file per device at ~/.lablink/devices/.toml. Override the directory:
export LABLINK_CONFIG_DIR=/path/to/devices/
Base fields (all drivers)
| Field | Required | Description | |-------|----------|-------------| | type | yes | Driver: visa, ssh, rest, serial, python_shell | | alias | yes | Must match the filename (e.g. tek_mso44.toml → alias = "tek_mso44") | | timeout_ms | yes | Default communication timeout in milliseconds | | description | no | Shown in lablink list output |
Per-driver extras
See [examples/configs/](examples/configs/) for complete templates.
VISA — adds resource_string, manufacturer, model_number, read_termination, write_termination, techmanual_document_ids
SSH — adds host, port, username, auth fields (auth_type, auth_ssh_key_path, auth_token_env, etc.)
REST — adds base_url, auth fields
Serial — adds serial_port, baud_rate, data_bits, parity, stop_bits, read_termination, write_termination
python_shell — adds python_path (path to interpreter), working_dir
Credentials are always referenced by environment variable name — never stored in config files directly.
CLI Reference
The CLI mirrors the MCP tool surface for development and debugging.
lablink list # list all configured devices
lablink diagnose # system dep check (all drivers)
lablink diagnose tek_mso44 # device-specific reachability check
lablink connect tek_mso44 # open session, print identity
lablink disconnect tek_mso44 # close session
lablink visa query tek_mso44 "*IDN?" # SCPI query
lablink visa write tek_mso44 "CH1:SCALE 0.5" # SCPI write
lablink ssh exec rpi_dev "uname -a" # run SSH command
lablink rest get my_api /status # HTTP GET
lablink rest post my_api /jobs --body '{"n":1}' # HTTP POST
lablink serial query my_device "MEAS?" # serial write + read
Per-protocol commands appear only when that driver's deps are installed.
VISA Troubleshooting
list_resources() returns an empty tuple ()
- Confirm the instrument is powered on and the cable is connected.
- For USB instruments on macOS, check System Settings → Privacy & Security → USB.
- For USB instruments on Windows, pyvisa-py requires
libusb. Install viapip install libusb-package. - For GPIB instruments, pyvisa-py has limited GPIB support — consider NI-VISA.
VISA timeout on connect or query
- Increase
timeout_msin your instrument config. - Confirm no other software (e.g. NI MAX, Keysight Connection Expert) has the port locked.
VISA Backend
LabLink uses pyvisa-py by default — a pure-Python implementation with no additional software required.
To use NI-VISA instead (e.g. for GPIB or if you already have it installed):
export LABLINK_VISA_BACKEND=@ni
Using with techmanual.ai (optional)
techmanual.ai is a searchable index of technical manuals for T&M equipment. When both MCP servers are loaded, your agent can look up SCPI commands and execute them without human intervention.
Add techmanual_document_ids to your VISA config to enable targeted lookups:
techmanual_document_ids = [1291, 1323] # user manual, programming guide
When this field is set, connect() returns the IDs so the agent can fetch relevant pages without a search query.
Control your home (Home Assistant)
Home Assistant is a local-first, open-source smart-home hub. It unifies thousands of devices across ecosystems — Apple Home, Alexa, Google, Zigbee, Z-Wave, Matter — behind one local REST API. That means LabLink's existing rest driver drives your whole home through a single alias; no extra driver to install.
Create a Long-Lived Access Token in Home Assistant (Profile → Security → Long-Lived Access Tokens), export it, and point a REST config at your hub:
# ~/.lablink/devices/home_assistant.toml
type = "rest"
alias = "home_assistant"
timeout_ms = 10000
base_url = "http://homeassistant.local:8123/api"
auth_type = "bearer"
auth_token_env = "HASS_TOKEN" # export HASS_TOKEN=
Then your agent can read and command anything HA manages:
lablink rest get home_assistant /states # every entity's state
lablink rest post home_assistant /services/light/turn_on --body '{"entity_id": "light.kitchen"}'
See [examples/configs/resthomeassistant.toml](examples/configs/resthomeassistant.toml) for the full template.
Scope
LabLink ships five protocol drivers — visa, ssh, rest, serial, and python_shell — on a shared multi-driver dispatch core. (An external routing stub also lets a device be handled by a vendor-supplied MCP server.) GPIB is covered by visa through PyVISA; RS232/RS422/RS485 are electrical variants of the one serial driver.
Deliberately out of scope:
- No server component. LabLink runs on your local machine. There is no cloud
deployment or hosted endpoint.
- No instrument simulation. Tests mock the driver libraries; real use needs
real hardware.
- No GUI. The CLI is the only interface beyond MCP.
- Not a protocol library. LabLink sends commands and returns responses; it
does not parse or interpret SCPI or any other protocol syntax. That knowledge lives in the agent or in techmanual.ai.
- Docker is not a primary install target. USB/serial passthrough into
containers defeats the point of local lab use.
Streaming-first protocols (MQTT, WebSocket) and others (Modbus, OPC-UA, CAN, …) are considered case-by-case as demand surfaces.
Architecture & Contributing
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the data models, driver contract, dispatch model, and a step-by-step guide to adding a new driver. Adding a driver requires no changes to lablink/mcp_server.py or lablink/cli.py — just a new lablink/interfaces// package and one line in each registry.
Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
Running Tests
pip install -e ".[dev]"
pytest tests/
All tests mock hardware drivers — no real instruments required.
Mapping your system (optional)
Create ~/.lablink/topology.toml to give the agent a machine-readable map of how your bench is physically wired — which ports connect to which, what signals flow, and what safety limits apply.
# ~/.lablink/topology.toml
name = "rf_bench"
[[node]]
alias = "siglent_sdg6022"
role = "signal generator"
[[node]]
alias = "tek_mso44"
role = "oscilloscope"
[[node]]
id = "pad_10db" # passive gear: no alias needed
role = "10 dB attenuator"
[[link]]
from = "siglent_sdg6022:OUTPUT1"
to = "pad_10db:IN"
signal = "stimulus"
params = { impedance_ohm = 50 }
[[link]]
from = "pad_10db:OUT"
to = "tek_mso44:CH1"
signal = "stimulus (attenuated)"
[[link]]
from = "keysight_e36313:CH1"
to = "dut_serial:12V_IN"
signal = "DC power"
[[link.constraint]]
severity = "critical"
limit = "voltage <= 13.5"
note = "DUT is damaged above 13.5 V on 12V_IN."
Call system_topology() to retrieve the full map, or system_topology(alias) to get one device's wiring slice. connect() and diagnose(alias) also inject the slice automatically as topology_context.
Constraints are advisory only. LabLink surfaces severity / limit / note to the agent; it does not and cannot enforce them (it does not parse protocol syntax). The agent is responsible for honoring limits.
Validate the file with:
lablink topology validate
lablink topology show # full map
lablink topology show tek_mso44 # one device's slice
See [examples/topology.toml](examples/topology.toml) for a full annotated example.
Override the default path:
export LABLINK_TOPOLOGY_FILE=/path/to/topology.toml
Environment Variables
| Variable | Default | Purpose | |----------|---------|---------| | LABLINK_CONFIG_DIR | ~/.lablink/devices/ | Device config directory | | LABLINK_TOPOLOGY_FILE | ~/.lablink/topology.toml | System topology file (independent of LABLINK_CONFIG_DIR) | | LABLINK_VISA_BACKEND | @py | pyvisa backend (@py or @ni) | | LABLINK_LOG_DIR | ~/.lablink/logs/ | Event log directory; set to "" to disable | | TMAI_API_KEY | — | techmanual.ai API key for agent-directed manual lookups |
License
LabLink is released under the [MIT License](LICENSE).
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: techmanual-ai
- Source: techmanual-ai/lablink-mcp
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.