MCP server that gives AI agents (Claude Code, Claude Desktop, custom agents) tool access to all PSI machine data — BOM, PLC programs, electrical drawings, project provenance, supply chain, fault diagnostics.
Overview
The PSI Machine Intelligence MCP Server exposes 51 tools over the Model Context Protocol standard. It connects to the UniData REST API for ERP data, reads network file shares (LDS/CAD via UNC paths) for PLC programs, electrical drawings, and engineering files, and uses Azure OpenAI for AI-powered assessments.
The vision: An engineer asks “Machine 2399 is throwing a low air pressure fault — what sensor is that, where’s the wiring diagram, and have we seen this on other machines?” and gets a complete answer.
Ask the Fleet is the first production web application consuming the MCP server. It embeds an AI chat panel inside PSI Explorer where users ask questions in plain English. The Express.js backend connects to PS-PROXY:3100 as an MCP client, passes the 51 tools to Azure OpenAI (GPT 5.2), and streams responses back to the browser via SSE. No AI expertise or developer tools required — anyone on VPN can use it at explorer.progressivesurface.com.
Two Transport Modes
Mode
Flag
Use Case
Stdio
node mcp-server.js (default)
Single-user, local Claude Code / Claude Desktop
HTTP
node mcp-server.js --http
Multi-user, network access, remote agents
Stdio mode — Claude Code spawns the server as a child process. Communication is JSON-RPC over stdin/stdout. This is the standard MCP pattern for local tools.
HTTP mode — Runs an Express server on port 3100 supporting both the newer Streamable HTTP protocol (POST/GET/DELETE /mcp) and legacy SSE (GET /sse, POST /messages). Any MCP client on the network can connect.
Tools Reference (51 Tools)
Category 1: Project & Machine Identity
Tool
Description
get_project_info
Project metadata with resolved machine type names, customer, team names, schedule, hours
find_similar_machines
Sibling projects with same machine type — paginated, with resolved machine type names, customer names, status labels
Full PLC analysis (modules, tags, routines, faults). Reads from fleet archive first, falls back to ACD analyzer
analyze_acd
Directly analyze an ACD file using the Python ACD analyzer
lookup_fault
Search fault catalog by tag name, severity, or keyword — returns classified faults with abort/hold/inhibit severity. On zero results, suggests available keywords and sample faults
get_io_map
I/O cross-reference enriched with tag descriptions from analysis (tag ↔ slot ↔ device ↔ drawing ↔ BOM part)
lookup_plc_tag
Look up a specific PLC tag (data type, scope, usage)
lookup_pc_read_write
Decode PC_Read[n] or PC_Write[n] from IO spreadsheet
Root cause analysis combining all sources — flags CHRONIC_SHRINKAGE, WO_OVERPICK_LIKELY, RTS_LIKELY, etc.
Category 10: Cost Analysis & Floor Stock
Tool
Description
analyze_part_cost_leakage
Classify every material transaction by WO type (Fabrication, Assembly, FloorStock, GlDirect, etc.), compute extended cost per category, and quantify cost leakage — material costs not attributed to any job
get_job_cost_attribution
Given a job number, classify all its work orders by type and show cost attribution breakdown (how many Fabrication vs Assembly vs Misc vs Floor Stock WOs)
Category 11: Customer Lookup & Sales Orders
Tool
Description
search_customers
Fuzzy search 4,600+ PSI customers by name — paginated (offset/limit, max 200). Returns customer number, name, location, account type. Call this first to resolve a customer name to a number before using quote/sales tools
get_open_quotes
List open spare parts quotes by customer number, contact number, or contact email. Returns quote date, value, description, status (open/ordered/expired)
get_quote_detail
Full detail for a specific quote: header + all line items with part numbers, pricing, quantities, and linked sales orders
get_sales_orders
Open sales orders for a customer with linked quote numbers. Use to check if a customer PO has been received for a quote
get_sales_history
Invoiced sales history (VB_SODET.REV4): what was sold to a customer, with quantities, prices, ship dates, and 24-field line detail
Category 12: Fleet Intelligence & Templates
Tool
Description
recommend_template
Given specs (robot type, I/O range, safety required, machine family), scores fleet candidates and returns top matches with gap analysis per area (I/O, safety, quality, robot type)
audit_safety_compliance
Fleet-wide safety audit: finds GuardLogix without safety task, scores below threshold, no E-stop detection, no fault aggregation
get_fleet_overview
Fleet-wide statistics and trends
fleet_parsing_summary
Summary of parsed/unparsed projects across the fleet
fleet_reuse_summary
Module and tag reuse analysis across projects
fleet_scorecard_summary
Scorecard distribution and trends across fleet
search_fleet_summaries
Search fleet summaries by keyword or criteria
get_machine_summary
Summary for a specific machine type across fleet
compare_machine_summaries
Compare two machine type summaries side-by-side
get_plc_scorecard
Quality scorecard for a specific project
Category 13: AI-Powered Assessment
Tool
Description
get_ai_assessment
Azure OpenAI-powered deep analysis of a PLC program — generates fault catalog with test procedures, safety assessment narrative, design quality review, and commissioning checklist. Results cached as ai_assessment.json in fleet archive. Sections: faultCatalog, safetyAssessment, designQuality, commissioningChecklist
Authentication
The HTTP transport is an OAuth 2.1 Resource Server secured with Microsoft Entra ID bearer
tokens (added 2026-06-23). Every route is protected except/health and the discovery doc.
App registration:PSI Machine MCP — client/app id 0dfb7d0a-b815-4611-93ba-ccdf3213187b,
App ID URI api://0dfb7d0a-b815-4611-93ba-ccdf3213187b.
Required: delegated scope Mcp.Invoke (user tokens) or app role Mcp.Invoke.App
(daemon / managed-identity tokens).
Validation: RS256 signature via tenant JWKS, plus iss (PSI tenant), aud (the app), and
scope/role checks. Missing/invalid token → 401; valid token without the scope/role → 403.
Fail-closed — if MCP_APP_CLIENT_ID is unset the server rejects all protected requests.
Discovery: RFC 9728 Protected Resource Metadata at /.well-known/oauth-protected-resource,
plus a 401 WWW-Authenticate: Bearer resource_metadata=… header.
How clients get a token
Client
Mechanism
Claude Code
headersHelper runs az account get-access-token --resource api://0dfb7d0a-… per connection (see Option 1). The Azure CLI client is pre-authorized, so any PSI user with az login gets a delegated Mcp.Invoke token.
Daemon / web backend (e.g. PSI Explorer bom-explorer-web)
App Service managed identity granted the Mcp.Invoke.App app role; DefaultAzureCredential.getToken('api://0dfb7d0a-…/.default').
VS Code / Copilot
Static Authorization header via a .vscode/mcp.jsoninput (no headersHelper support).
Network posture
Private by default — bound to the PSI network with the firewall scoped to private ranges; no public
exposure. stdio connections (Option 2) bypass HTTP auth entirely (local child process, launching
user’s identity). Public access for cloud clients (e.g. M365 Copilot) requires a separate public
front (gateway / App Proxy) — not configured.
Setup
Option 1: Connect to Production Server (Recommended)
The MCP server runs on PS-PROXY as a Windows service, reachable from the PSI network (LAN/VPN).
The HTTP transport requires an Entra bearer token (see Authentication) — an
unauthenticated request returns 401.
Claude Code — use headersHelper to mint a token per connection via az (requires az login):
VS Code / GitHub Copilot — uses a different schema (.vscode/mcp.json, servers key, no
headersHelper); supply a static Authorization header via an input (token from the same az
command). See the MCP standard.
Option 2: Local Stdio (Dev/Offline)
For local development or when PS-PROXY is unavailable: