walspro-ai
Headless OAuth device connector for wals.pro AI 4 weclapp.
Install it on an agent host that cannot receive a browser callback — a CLI
agent, an SSH session, a container, a remote desktop. It performs an RFC 8628
device authorization against the hosted issuer and then forwards JSON-RPC
frames between a local stdio MCP client and the hosted /v1/mcp runtime.
It is a transport and authentication adapter only: it registers no MCP tools, implements no business logic, and never sees weclapp API credentials. The tool catalog, the user policy, the write-approval flow and the audit pipeline all stay on the server.
"weclapp" is the ERP this connector talks to. This distribution is published by Wals.pro GmbH and is not a weclapp SE product.
Before you start: your workspace admin must enable device connections
Device authorization is off by default and is never derived from a plan or a tier: a workspace administrator enables it, per workspace, once.
Until they do, the browser approval step fails with HTTP 503 and
Tenant device enrollment capacity is not configured — login then reports the
prerequisite explicitly instead of a generic failure. Ask your workspace admin
before filing a bug.
Install
pipx install walspro-ai # recommended: isolated, on PATH
pip install walspro-ai # or into an existing environment
Python 3.10 or newer. The only runtime dependencies are the MCP SDK, httpx
and anyio.
Use
walspro-ai login # authorize this host (prints a URL and a user code)
walspro-ai status # non-secret local connection status
walspro-ai config # token-free MCP client configuration snippet
walspro-ai run # stdio <-> /v1/mcp transport (started by the MCP client)
walspro-ai logout # remove local credentials only
walspro-ai revoke # revoke the server grant, then remove local credentials
python -m walspro_ai <command> is equivalent and works when the console
script is not on PATH.
Add the output of walspro-ai config to your MCP client configuration. It
contains no tokens; the credentials stay in the local credential file. Use
--server-name to change the generated entry key.
Global options: --credentials PATH (alternate credential file),
--verbose (print the underlying traceback on failure), --version.
login opens a browser only when one can plausibly be reached (a BROWSER
variable, macOS/Windows, or DISPLAY/WAYLAND_DISPLAY). On a headless Linux
host it prints the URL instead of blocking on a terminal browser. Force either
behaviour with --open-browser or --no-browser.
Exit codes
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Error (the message names the cause) |
2 |
Local credentials were removed, but the server grant may still be active — revoke the connection in the dashboard |
130 |
Interrupted (Ctrl-C) |
Where credentials live
| Platform | Default path |
|---|---|
| Linux / BSD | $XDG_CONFIG_HOME/walspro-ai/device.json, otherwise ~/.config/walspro-ai/device.json |
| macOS | ~/.config/walspro-ai/device.json |
| Windows | %APPDATA%\walspro-ai\device.json |
The credential file is created exclusively (O_EXCL, O_NOFOLLOW) with mode
0600, rotated by fsync + atomic replace, and serialized across processes by
an OS file lock on a sidecar. On POSIX the connector refuses to read a
credential file that is group- or world-accessible or owned by another user.
Windows, stated plainly. Windows reports 0o666 for every writable file
regardless of its ACL, so the mode assertion is skipped there, and there is no
os.getuid() to compare against, so the ownership assertion is skipped too.
This connector does not read the Windows ACL as a substitute. What remains
on Windows is the symlink/regular-file check, the exclusive create and the
atomic replace; the file's actual confidentiality is whatever the containing
directory grants. Keep the credential file inside your own user profile (the
default location does) and do not point --credentials at a shared directory.
The POSIX checks themselves are never relaxed. Windows support is implemented
and unit-tested (the platform branches are exercised directly) but continuous
integration runs on Linux only, so please report anything that behaves
differently there — support@wals.pro.
Ambient network configuration is trusted. Both HTTP stacks honour the
process environment's proxy and CA settings (HTTPS_PROXY, SSL_CERT_FILE,
and the platform trust store), which is what makes the connector work behind a
corporate proxy. Treat the environment of the process your MCP client starts as
part of the trust boundary, and review any env block you paste into a client
configuration.
status and config never print bearer or refresh tokens.
Recovering from a broken credential file
logout removes the local credential file without validating it, so a
truncated, hand-edited or wrongly-permissioned file never locks you out. It
does not end the connection on the server — the device grant stays active
and keeps occupying an enrollment slot until you revoke it or remove the
connection in the dashboard.
revoke calls the RFC 7009 revocation endpoint. If the stored file no longer
validates, it still recovers the client id, refresh token and revocation
endpoint from it and revokes with those, as long as the endpoint is the
canonical one on the origin the file itself names. The outcomes are:
| Situation | Exit | Local file |
|---|---|---|
| Grant revoked | 0 |
removed |
| File invalid, but a token was recoverable and revoked | 0 |
removed |
| File unreadable, nothing revocable | 2 |
removed — revoke in the dashboard |
| Revocation call failed (issuer down, network) | 1 |
kept — use logout to remove it |
After any of these, login works again.
Migrating from the connector that shipped inside the server
Until this release the command was weclapp-mcp-device, installed by the
proprietary weclapp-mcp distribution, and its credentials lived in
~/.config/weclapp-mcp/device.json (%APPDATA%\weclapp-mcp\device.json on
Windows). That file holds a live refresh-token family that this connector
cannot revoke, and the command that could is gone.
Before or right after switching: revoke that connection in the dashboard under
Connections, then delete the old directory. login prints a reminder when it
finds one.
Support
There is no public issue tracker. Report defects and questions to
support@wals.pro; include the connector version (walspro-ai --version) and
the exact message, never the credential file.
Security properties
- Strict origin binding: issuer, token, revocation and resource URLs must all live on the same canonical origin, on their exact canonical paths.
- The OAuth calls refuse redirects, time out, and cap responses at 64 KiB.
- Access tokens rotate with the refresh token; a
401triggers exactly one refresh and one retry. A rotation whose local write fails reports that the connection is gone rather than keeping a token the server already retired. - Tokens are never printed, logged or passed on the command line,
--verboseincluded. MCP SDK andhttpxlog records are silenced unless you ask for them, because their tracebacks quote raw upstream response bytes. runfails loudly. The transport read is bounded, and a transport failure answers every unanswered request with a JSON-RPC error naming the sanitized cause and exits non-zero — it never leaves your MCP client waiting.- One stable public client identity per local profile; it is re-registered only after the authorization server explicitly retires it.
License
Apache-2.0. See LICENSE. Copyright 2026 Wals.pro GmbH.
The complete source of this distribution — including its test suite and the
changelog — ships in the sdist (pip download --no-binary :all: walspro-ai).
The repository it is developed in is private, so the package deliberately
declares no Source or Changelog URL rather than a link that 404s.
Release note for maintainers
The PyPI distribution name was registered before any install instruction naming it reached a customer-facing surface. That ordering is deliberate and not optional: an unregistered name printed in a dashboard, a README or a doc is claimable by anyone, and the first person to claim it would be shipping the package customers install as their OAuth device connector. Register the name first, then merge the instruction.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file walspro_ai-0.1.0.tar.gz.
File metadata
- Download URL: walspro_ai-0.1.0.tar.gz
- Upload date:
- Size: 55.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7e4892048b78898820b160f676c1043a51bf2fdf2dc24dacb52d621cd755023d
|
|
| MD5 |
b4d328820f0c09047a36fb1dc057a363
|
|
| BLAKE2b-256 |
321df7c6556f1833e6d621f877da377023893c13e896046ed2db89e865fccd71
|
Provenance
The following attestation bundles were made for walspro_ai-0.1.0.tar.gz:
Publisher:
packages-release.yml on Wals-pro/weclapp-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
walspro_ai-0.1.0.tar.gz -
Subject digest:
7e4892048b78898820b160f676c1043a51bf2fdf2dc24dacb52d621cd755023d - Sigstore transparency entry: 2498307112
- Sigstore integration time:
-
Permalink:
Wals-pro/weclapp-mcp@5e316b6de7891d16ef8e80e191d0f3d8fb895281 -
Branch / Tag:
refs/tags/walspro-ai-v0.1.0 - Owner: https://github.com/Wals-pro
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
packages-release.yml@5e316b6de7891d16ef8e80e191d0f3d8fb895281 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file walspro_ai-0.1.0-py3-none-any.whl.
File metadata
- Download URL: walspro_ai-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e19e3b932316cd520ec28e49578517a941a7dc3e7247099e23f94bd78fa79ecb
|
|
| MD5 |
850a466d4c3454b06ab9f1762a27bd0b
|
|
| BLAKE2b-256 |
d3462d9ec6d1a4e736a8b65d553a3fe2021a79f773cc73d4492aa916533fc4e1
|
Provenance
The following attestation bundles were made for walspro_ai-0.1.0-py3-none-any.whl:
Publisher:
packages-release.yml on Wals-pro/weclapp-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
walspro_ai-0.1.0-py3-none-any.whl -
Subject digest:
e19e3b932316cd520ec28e49578517a941a7dc3e7247099e23f94bd78fa79ecb - Sigstore transparency entry: 2498307131
- Sigstore integration time:
-
Permalink:
Wals-pro/weclapp-mcp@5e316b6de7891d16ef8e80e191d0f3d8fb895281 -
Branch / Tag:
refs/tags/walspro-ai-v0.1.0 - Owner: https://github.com/Wals-pro
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
packages-release.yml@5e316b6de7891d16ef8e80e191d0f3d8fb895281 -
Trigger Event:
workflow_dispatch
-
Statement type: