Skip to main content
Glama

jwx-mcp

The Justworx MCP server — exposes Justworx devices to AI agents (Claude, ChatGPT, agent frameworks) as MCP tools (control) and resources (read-only state), backed entirely by the public Developer API (/api/dev/v1).

It is a thin, standalone client of the Developer API: it calls the gateway over HTTPS, holding no device keys — actuation flows through the gateway to the Justworx platform.

Two run modes, one server core (the tools/resources are transport-agnostic):

  • stdio (src/index.js) — a client (Claude Desktop, etc.) launches it locally with a single jwx_live_ API key. This is the local/desktop path.

  • remote (src/http-entry.js) — a hosted, multi-tenant OAuth 2.1 Resource Server over the MCP Streamable HTTP transport, for clients that can't launch a local process (claude.ai web, ChatGPT connectors). Each caller brings their own OAuth access token; see below.

Tools

Tool

What

list_devices

List accessible devices (filters: status, productId, online; cursor-paginated).

get_device

Full live twin state of one device (IO, rules, network, location).

get_device_events

Recent event history (time window + type filter).

set_io

Set an IO and hold it. confirm:true waits for a confirmed device reply.

pulse_io

Drive an IO for durationMs then revert (momentary actions, e.g. a gate trigger).

set_rule

Enable/disable an on-device rule.

Related MCP server: mcp-auth-proxy

Resources

  • justworx://devices — the accessible device list.

  • justworx://devices/{serial} — live state for one device.

Configure & run

The server speaks stdio (how MCP clients launch a local server). It needs a Developer API key — issue one via the portal / the gateway's /manage/keys API.

// Claude Desktop / MCP client config
{
  "mcpServers": {
    "justworx": {
      "command": "node",
      "args": ["C:/Users/Wkyle101/jwx-mcp/src/index.js"],
      "env": {
        "JWX_API_KEY": "jwx_live_…",
        "JWX_API_BASE_URL": "https://dev-api.justworx.com/api/dev/v1"
      }
    }
  }
}

Inspect it locally with the MCP Inspector:

JWX_API_KEY=jwx_live_… npx @modelcontextprotocol/inspector node src/index.js

Remote mode (hosted, OAuth 2.1)

For hosted clients (claude.ai web, ChatGPT connectors) that can't spawn a local process, run the Streamable HTTP server. It is a standard OAuth 2.1 Resource Server: it does not issue tokens, it validates the ones from the OAuth authorization server and forwards each caller's token to the Developer API (the gateway accepts either an API key or an OAuth token). Fully multi-tenant — a fresh server is built per request, bound to that caller's token; no shared key, no cross-tenant state.

npm run start:http     # → http://0.0.0.0:$MCP_HTTP_PORT/mcp
  • Endpoint: POST /mcp (Streamable HTTP, stateless). GET /healthz for liveness.

  • OAuth discovery (so clients self-register + authorize): GET /.well-known/oauth-protected-resource (RFC 9728 → points at the AS) and GET /.well-known/oauth-authorization-server (RFC 8414 mirror). An unauthenticated call returns 401 + WWW-Authenticate: Bearer resource_metadata="…".

  • Tokens must be audience-bound (RFC 8707) to MCP_RESOURCE_URL; scopes map to Developer-API scopes.

Deployment: run this server behind an HTTPS reverse proxy or tunnel and publish it at your resource URL (e.g. mcp.justworx.com). It validates tokens from the OAuth authorization server at https://oauth.justworx.com. The OAuth Resource-Server layer is complete and covered by tests against a stub issuer. See DEPLOY-REMOTE.md.

Config (env)

Var

Default

Notes

JWX_API_KEY

(stdio only)

A jwx_live_ Developer API key (local/stdio mode).

JWX_API_BASE_URL

https://dev-api.justworx.com/api/dev/v1

Gateway base; point at a local gateway for testing.

JWX_API_TIMEOUT_MS

30000

Per-request timeout.

MCP_HTTP_PORT

8790

Remote server listen port.

MCP_RESOURCE_URL

https://mcp.justworx.com

This server's public URL = its OAuth resource id (token audience).

OAUTH_ISSUER

https://oauth.justworx.com

The OAuth authorization server (issuer) whose tokens are accepted.

OAUTH_JWKS_URL

<issuer>/.well-known/jwks.json

AS JWKS for token validation.

Test

npm test   # node:test — connects a real MCP client over an in-memory transport

Tests drive an actual MCP Client against the server with an injected fake API client; the HTTP client itself is also verified end-to-end against a live jwx-dev-api (mock upstream).

Layout

src/apiClient.js   thin fetch client for /api/dev/v1 (bearer: api key OR OAuth token)
src/server.js      buildServer({client}) — tools + resources (transport-agnostic)
src/config.js      env config (stdio + remote/OAuth)
src/index.js       stdio entrypoint
src/oauth.js       OAuth 2.1 token verifier (JWKS) — Resource Server side
src/http.js        remote app: Streamable HTTP + OAuth discovery + per-request token forwarding
src/http-entry.js  remote entrypoint (npm run start:http)
test/server.test.js  stdio: MCP client ⇄ server over in-memory transport
test/http.test.js    remote: real Streamable-HTTP MCP client + stub AS (JWKS) → authed tool calls

Available Tools

6 tools
get_deviceGet deviceA

Full live state of one device (IO, rules, network, location) from its digital twin.

ParametersJSON Schema
NameRequiredDescriptionDefault
serialYesthe device's 8-char serial (e.g. ABCD1234)

TDQS

A3.8/5.0
Behavior3/5

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

No annotations are provided, so the description carries full responsibility. It discloses that the operation returns a live state and enumerates the data categories, but it does not explicitly state that the operation is read-only or side-effect-free. For a get operation this is implied, yet the description could be more transparent about the real-time nature and lack of mutation.

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?

The description is a single, front-loaded sentence that conveys the scope and content of the return value without wasted words. It is concise while still being informative.

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

Completeness4/5

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

The tool is simple (one parameter, no output schema), and the description adequately summarizes the returned data by listing the key domains. However, it could be slightly more explicit about the return format or mention that it is a snapshot, but given the simplicity, the description is sufficiently complete.

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

Parameters3/5

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

Schema description coverage is 100%: the serial parameter is fully documented with a pattern, required flag, and example. The description adds no parameter-level detail, but with full schema coverage the baseline of 3 is appropriate.

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?

The description clearly states that the tool retrieves the full live state of a single device, enumerating specific dimensions (IO, rules, network, location). This distinguishes it from siblings like list_devices (lists all devices) and get_device_events (retrieves events), and from mutation tools like set_io and pulse_io.

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

Usage Guidelines3/5

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

The description implies usage for retrieving a comprehensive snapshot of one device, but it does not explicitly state when to use this tool over alternatives or when not to use it. The wording 'from its digital twin' hints that it provides live state rather than events, but exclusions are not named.

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

get_device_eventsGet device eventsA

Recent event history for a device (newest first). Optional time window + type filter.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoISO-8601 end
fromNoISO-8601 start
typeNo
limitNo
cursorNo
serialYesthe device's 8-char serial (e.g. ABCD1234)

TDQS

A3.9/5.0
Behavior3/5

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

No annotations exist, so the description must carry behavioral context. It discloses ordering ('newest first') and optional filters, but does not mention pagination behavior, cursor/limit semantics, or data retention/availability, leaving gaps.

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?

A single sentence that front-loads the core action and ordering, followed by available filters. No wasted words.

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

Completeness3/5

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

For a tool with six parameters and no annotations or output schema, the description provides the essential purpose and filters but omits pagination/cursor context and return-value expectations. The existence of cursor and limit suggests paging, which should be clarified for complete usage.

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

Parameters3/5

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

The schema covers serial, from/to, type, and limit partially, but cursor lacks a description. The description adds the key meaning that from/to and type are optional filters, which helps, but it does not explain cursor pagination or limit semantics.

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?

The description uses the specific verb 'get' with the resource 'device events' and clearly states it retrieves recent event history for a device, newest first. This distinguishes it from siblings like get_device or set_io.

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

Usage Guidelines4/5

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

It establishes clear context: this tool is for retrieving recent device events with optional time/type filters. It does not explicitly name alternatives or when-not-to-use, so a point is deducted.

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

list_devicesList devicesA

List devices the API key can access. Optional filters: status, productId, online. Cursor-paginated.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
cursorNo
onlineNo
statusNo
productIdNo

TDQS

A4.4/5.0
Behavior4/5

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

With no annotations provided, the description carries the full burden. It discloses important behavioral traits: access is scoped to the API key and results are cursor-paginated. It does not describe response format or error handling, but for a simple list tool this is adequate.

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?

The description is two sentences, front-loaded with the primary verb and resource, and every word adds value. No filler or redundancy.

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

Completeness4/5

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

Given the absence of an output schema and the relative simplicity of a list operation, the description covers the essential aspects: what is listed, access scope, filters, and pagination. It could mention default limit or sorting, but this is not critical for invocation.

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

Parameters4/5

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

The input schema has 0% description coverage, so the description compensates by naming the filter parameters (status, productId, online) and labeling them as optional. It also clarifies that limit and cursor are for pagination, adding meaning beyond the bare schema.

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?

The description clearly states the tool's function with a specific verb ('List') and resource ('devices'), and defines the scope ('the API key can access'). It distinguishes from sibling tools like get_device (single-device fetch) and mutation tools like set_io.

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

Usage Guidelines4/5

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

The description implies usage (to enumerate accessible devices) and provides context about optional filters and pagination. It does not explicitly name alternatives or exclusions, but the context is clear enough for an agent to choose this tool over siblings.

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

pulse_ioPulse an IOA

Drive an IO to a state for durationMs, then revert. Useful for momentary actions (e.g. a gate trigger).

ParametersJSON Schema
NameRequiredDescriptionDefault
ioYes
stateYeshigh/low for digital, or a number for analog
serialYesthe device's 8-char serial (e.g. ABCD1234)
confirmNo
durationMsYes
revertStateNohigh/low for digital, or a number for analog

TDQS

A3.9/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It discloses the core behavior (drive then revert), but it does not specify whether the operation blocks for durationMs or returns immediately, what the default revert state is, or the role of the confirm parameter. This leaves meaningful behavioral gaps for a tool with no annotation fallback.

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?

The description is two sentences, front-loaded with the action and followed by a concrete use case. Every word earns its place; there is no filler or redundancy.

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

Completeness3/5

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

The tool has six parameters, four required, and no output schema. The description explains the core mechanism and provides an example, but it omits the 'confirm' parameter, revert behavior details (e.g., what it reverts to if not specified), and any timing semantics. Given the complexity, a more complete description would cover these points.

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

Parameters3/5

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

The description adds meaning for core parameters: 'IO', 'state', 'durationMs', and the revert action implicitly explains 'revertState'. However, the 'confirm' parameter is not mentioned at all, and schema descriptions already cover 'serial', 'state', and 'revertState'. With 50% schema coverage, the description only partially compensates for missing parameter detail.

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?

The description clearly states the tool's function: 'Drive an IO to a state for durationMs, then revert.' It identifies the specific action (pulse), the resource (IO), and the time-based behavior. It also distinguishes from siblings like set_io by explicitly mentioning the revert behavior, making it evident this is for momentary actions.

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

Usage Guidelines4/5

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

The description provides a clear usage context: 'Useful for momentary actions (e.g. a gate trigger).' This implies when to use this tool versus a persistent set, but does not explicitly name alternatives or when-not-to-use scenarios. The context is strong enough for an agent to infer appropriate usage, though it stops short of fully explicit guidance.

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

set_ioSet an IO (latch)A

Set a device IO to a state and hold it. Pass confirm:true to wait for a confirmed device reply.

ParametersJSON Schema
NameRequiredDescriptionDefault
ioYes
stateYeshigh/low for digital, or a number for analog
serialYesthe device's 8-char serial (e.g. ABCD1234)
confirmNo

TDQS

A3.7/5.0
Behavior3/5

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

With no annotations, the description carries the transparency burden. It discloses the core behavior (set and hold) and the confirm behavior. However, it does not mention side effects, overwrite semantics, permissions, or return values. Essential behavior is present but limited.

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?

Two sentences, front-loaded with the action, no filler. Efficiently conveys purpose and confirm option.

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

Completeness3/5

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

This is a simple tool, but with no output schema and no annotations, the description should explain return values and prerequisites. It explains the confirm behavior but not the response format or what happens on failure. The 'io' parameter is undefined, leaving a key aspect incomplete.

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

Parameters3/5

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

Schema coverage is 50% (serial and state have descriptions). The description adds meaning for 'confirm' by explaining 'wait for a confirmed device reply', which the schema lacks. It does not clarify the 'io' parameter (integer), so the description only partially compensates for the coverage gap.

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?

The description uses the specific verb 'Set' with a clear resource ('device IO') and the latch behavior 'hold it'. It inherently distinguishes from sibling tool 'pulse_io' (which implies a temporary pulse versus a held state).

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

Usage Guidelines3/5

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

The description implies usage for latching an IO state, but does not explicitly compare to alternatives like 'pulse_io'. It gives a clear directive for the confirm parameter ('Pass confirm:true'), but no when-not or alternative references.

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

set_ruleEnable/disable a ruleB

Enable or disable an on-device rule by its ruleId.

ParametersJSON Schema
NameRequiredDescriptionDefault
ruleIdYes
serialYesthe device's 8-char serial (e.g. ABCD1234)
confirmNo
enabledYes

TDQS

B3.3/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It does not disclose behavioral traits such as whether changes take effect immediately, whether confirmation is needed, reversibility, or permissions. The optional 'confirm' parameter is not explained at all.

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?

The description is a single, front-loaded sentence with no filler. Every word contributes to the core purpose.

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?

The tool has 4 parameters, no output schema, and no annotations, yet the description is minimal. It lacks information about expected return values, confirmation behavior, or any edge cases. The unexplained 'confirm' parameter and lack of behavioral detail make it incomplete for an agent to invoke correctly.

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

Parameters2/5

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

Schema description coverage is only 25%, and the description adds minimal value: it clarifies that ruleId identifies the rule and 'enable/disable' implies the 'enabled' boolean, but it does not explain the 'confirm' parameter. The schema already documents 'serial'.

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?

The description clearly states a specific action ('Enable or disable') on a specific resource ('on-device rule by its ruleId'). It distinguishes itself from sibling tools like set_io/pulse_io which target I/O.

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

Usage Guidelines3/5

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

The description implies usage for toggling a rule's state but does not explicitly state when to use it vs alternatives or mention any prerequisites/exclusions. Sibling names make the context somewhat clear, but there is no direct guidance.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedget_device
    • First observedget_device_events
    • First observedlist_devices
    • First observedpulse_io
    • First observedset_io
    • First observedset_rule

TDQS

A4/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct operation: listing vs. fetching a single device, retrieving events, controlling IO persistently or momentarily, and managing rules. set_io and pulse_io are clearly differentiated by hold vs. transient behavior.

Naming Consistency5/5

All tool names use a consistent verb_noun pattern (list_, get_, set_, pulse_), with clear and predictable naming that mirrors the operation type.

Tool Count5/5

With 6 tools, the server is well-scoped for a device interaction API, covering essential read and write operations without unnecessary bloat or missing core functionality.

Completeness5/5

The surface covers device discovery, state inspection, event history, and both persistent and momentary IO control, plus rule management. This is a thorough set for the apparent domain of device control and monitoring.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Bridges stdio-based LLM harnesses to OAuth-protected remote MCP servers via Streamable HTTP, handling PKCE browser login and token refresh automatically.
    6
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI clients like Claude to interact with Cartena tools via MCP, supporting remote OAuth or local stdio authentication.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to discover and interact with iOS apps through a local MCP gateway, converting remote Streamable HTTP MCP endpoints into stdio tools. Provides dynamic device discovery, tool schema introspection, and deterministic tool calling for app analysis.
    -