Skip to main content
Glama
priority-mcp

Priority REST API MCP Server

by priority-mcp

Priority REST API MCP Server

Ein MCP-Server, der KI-Assistenten – Claude und andere – direkt mit einem Priority-ERP-System verbindet. Jede OData-Operation (Abfrage, Erstellen, Aktualisieren, Löschen, Stapelverarbeitung, Anhänge, Textfelder) wird als MCP-Tool bereitgestellt, sodass KI-Agenten ohne benutzerdefinierten Integrationscode auf Live-Geschäftsdaten zugreifen und diese schreiben können.

Version: 0.2.0 · Transport: Streamable HTTP (SSE optional) · Laufzeit: Node.js 18 · Tools: 19


Schnellstart

1. Klonen und installieren

git clone https://github.com/priority-mcp/priority-odata-mcp priority-mcp
cd priority-mcp
npm install

2. .env aus dem Beispiel erstellen

cp .env.example .env

Mindestens diese vier Variablen müssen gesetzt werden:

PRIORITY_BASE_URL=https://<host>/odata/Priority/<tabula.ini>/<company>/
PRIORITY_AUTH_TYPE=basic
PRIORITY_USERNAME=myuser
PRIORITY_PASSWORD=mypassword

3. Server starten

# Development (from source)
node src/index.js

# Production (bundled)
npm run build
node dist/index.js

Beim ersten Start wird, falls ODATA_MCP_TOKEN nicht gesetzt ist, ein zufälliges Bearer-Token generiert und auf stdout ausgegeben. Kopieren Sie es für den nächsten Schritt.

4. Von Claude Code aus verbinden

Fügen Sie Folgendes zu Ihrer MCP-Konfiguration hinzu:

{
  "mcpServers": {
    "priority": {
      "type": "http",
      "url": "http://localhost:3000/mcp",
      "headers": {
        "Authorization": "Bearer <ODATA_MCP_TOKEN>"
      }
    }
  }
}

Related MCP server: mcp_sdk_eyra_accelerator

Transport

Der Server verwendet Streamable HTTP als primären Transport – jede POST /mcp-Anfrage ist vollständig zustandslos. Pro Anfrage werden ein neuer McpServer und ein neuer StreamableHTTPServerTransport erstellt und danach wieder abgebaut.

Endpunkt

Methode

Zweck

/mcp

POST

Primärer MCP-Endpunkt (Streamable HTTP)

/sse

GET

SSE-Stream – erfordert SSE_ENABLED=true

/sse

POST

JSON-RPC-Nachrichten für SSE-Clients

/health

GET

Health-Check – gibt Version und Status zurück

/.well-known/oauth-authorization-server

GET

OAuth-2.1-Discovery (erforderlich für Claude Code ≥2.1.92)

/authorize, /token, /register

GET/POST

OAuth-2.1-PKCE-Ablauf – genehmigt automatisch

Hinweis: Die OAuth-2.1-Endpunkte dienen dazu, den Streamable-HTTP-Verbindungs-Handshake von Claude Code zu erfüllen. Sie genehmigen alle Anfragen automatisch und sind nicht für echte Zugriffskontrolle gedacht – diese wird über ODATA_MCP_TOKEN abgewickelt.


Authentifizierung

Die Authentifizierung erfolgt auf zwei unabhängigen Ebenen.

Ebene 1 – Schutz dieses Servers

Alle Routen (außer /health und OAuth-Endpunkte) erfordern:

Authorization: Bearer <ODATA_MCP_TOKEN>

Setzen Sie ODATA_MCP_TOKEN in .env. Falls nicht vorhanden, wird beim Start eine zufällige UUID generiert und auf stdout ausgegeben.

Ebene 2 – Aufruf von Priority ERP

Wird über PRIORITY_AUTH_TYPE gesteuert:

  • basic – HTTP-Basic-Authentifizierung mit PRIORITY_USERNAME + PRIORITY_PASSWORD

  • pat – Bearer-Token über PRIORITY_PAT

  • oauth2 – wie pat (PAT als Bearer-Token übergeben)

  • none – kein Auth-Header (nur für lokale Tests)

Schreiboperationen (POST/PATCH/DELETE) holen bei Ablehnung der ersten Anfrage automatisch ein X-CSRF-Token und wiederholen die Anfrage damit, gemäß dem CSRF-Schutzmuster von Priority.

Optionale anwendungsspezifische Lizenz-Header werden mit jeder Priority-Anfrage gesendet, wenn PRIORITY_APP_ID und PRIORITY_APP_KEY gesetzt sind (X-App-Id / X-App-Key).


Konfiguration

Kopieren Sie .env.example nach .env. Der Server sucht nach .env in dieser Reihenfolge: ENV_FILE_PATH → ./mcp-servers/Priority-REST-API-MCP-Server/.env → ./.env.

Erforderlich

Variable

Beschreibung

PRIORITY_BASE_URL

OData-Stamm-URL – Format: https://<host>/odata/Priority/<tabula.ini>/<company>/

PRIORITY_AUTH_TYPE

basic | pat | oauth2 | none

PRIORITY_USERNAME

Benutzername – erforderlich bei AUTH_TYPE=basic

PRIORITY_PASSWORD

Passwort – erforderlich bei AUTH_TYPE=basic

Priority-Authentifizierung (optional)

Variable

Beschreibung

ODATA_MCP_TOKEN

Bearer-Token zum Schutz von /mcp. Bei nicht gesetztem Wert wird eine zufällige UUID verwendet.

PRIORITY_PAT

Persönliches Zugriffstoken (bei AUTH_TYPE=pat oder oauth2)

PRIORITY_APP_ID

Anwendungslizenz-ID – wird als X-App-Id-Header gesendet

PRIORITY_APP_KEY

Anwendungslizenzschlüssel – wird als X-App-Key-Header gesendet

PRIORITY_LANGUAGE

Überschreibt den Accept-Language-Header (z. B. en)

HTTP-Server

Variable

Standard

Beschreibung

HTTP_HOST

0.0.0.0

Bindungsadresse

HTTP_PORT

3000

Lauschport

SSE_ENABLED

false

Aktiviert den /sse-Endpunkt

Timeouts & TLS

Variable

Standard

Beschreibung

PRIORITY_HTTP_TIMEOUT_MS

30000

Lese-Timeout für Priority-API-Aufrufe (ms)

MCP_WRITE_TIMEOUT

15000

Timeout für POST/PATCH/DELETE-Operationen (ms)

MCP_PROC_TIMEOUT

45000

Timeout für Stapeloperationen (ms)

TLS_REJECT_UNAUTHORIZED

false

In Produktion auf true setzen, um selbstsignierte Zertifikate abzulehnen

Debugging

Variable

Standard

Beschreibung

LOG_LEVEL

INFO

DEBUG protokolliert jede Anfrage und Antwort

MCP_DEBUG

false

Vollständige OData-URLs, Parameter und Ergebnisanzahlen ausgeben

PRIORITY_ENABLE_TRACE

false

Fügt jeder Priority-Anfrage X-App-Trace: 1 hinzu

STRICT_DATA_INTEGRITY

true

Wirft Fehler bei leeren/Mock-API-Antworten – nur für Tests deaktivieren

ENV_FILE_PATH

—

Pfad zur .env-Datei überschreiben (nützlich für Submodul-Bereitstellungen)


Tools

Alle 19 Tools sind in src/tools/ definiert und in src/tools/priorityTools.js registriert.

System & Metadaten

Tool

Beschreibung

Parameter

version_get

Die Version des Priority-Dienstes und die Antwort-Header abrufen

—

metadata_entities_list

Alle OData-Entitätssets auflisten; nur auf REST-fähige Formulare filtern

apiOnly?, includeMetadata?

metadata_schema_get

Feld-Schema für eine Entität abrufen, indem ein Beispieldatensatz abgerufen wird. Leitet Unterformularnamen automatisch auf übergeordnetes Formular + $expand um

entity, sample?, top?

metadata_refresh

Serverseitigen Metadaten-Cache leeren und aktualisieren. Führt immer einen vollständigen Flush durch (siehe Bekannte Einschränkungen)

entity?

Abfragen

Tool

Beschreibung

Parameter

entity_get

Einen einzelnen Datensatz per Schlüssel oder Lookup abrufen, mit optionalem $expand und $select

entity, key, lookup, select?, expand?

query_run

Eine OData-Abfrage mit vollständiger Filter-/Select-/Top-/Skip-/Orderby-/Expand-/Count-Unterstützung ausführen. Validiert Datumsfilter-Ergebnisse nach dem Abruf

entity, filter?, select?, top?, skip?, orderby?, expand?, count?, deltaToken?

safe_query_run

Wie query_run, entdeckt aber zuerst automatisch gültige Felder und validiert $select-Feldnamen vor der Ausführung – verhindert 400-Fehler durch ungültige Spaltennamen

entity, filter?, select?, top?, skip?, expand?, count?

query_sum

Ein numerisches Feld über eine Entität mit optionalem Filter summieren. Versucht zuerst $apply=aggregate; fällt auf einen vollständigen Paging-Scan zurück

entity, field?, filter?

Erstellen / Aktualisieren / Löschen

Tool

Beschreibung

Parameter

entity_create

Einen neuen Datensatz erstellen. Unterstützt Unterformular-Erstellung über parentEntity + parentKey + subform

entity, data, parentEntity?, parentKey?, parentLookup?, subform?

entity_update

Einen Datensatz per PATCH mit If-Match: * aktualisieren. Unterstützt zusammengesetzte Schlüssel

entity, key, data, parentEntity?, parentKey?, subform?

entity_delete

Einen Datensatz per DELETE mit If-Match: * löschen. Unterstützt Unterformular-Löschungen

entity, key, parentEntity?, parentKey?, subform?

batch_operations

Mehrere POST/PATCH/DELETE-Operationen in einer $batch-Anfrage mit Abhängigkeitsverkettung ausführen

requests[] (id, method, url, body?, dependsOn?)

Textfelder

Tool

Beschreibung

Parameter

entity_text_get

Den Rich-Text-Inhalt der /Text-Unterressource eines Datensatzes abrufen

entity, key

entity_text_create

Neuen Textinhalt per POST an /Entity(Key)/Text senden

entity, key, textData

entity_text_update

Vorhandenen Textinhalt per PATCH auf /Entity(Key)/Text aktualisieren

entity, key, textData

Anhänge

Tool

Beschreibung

Parameter

entity_attachments_get

Anhänge eines Datensatzes auflisten

entity, key

entity_attachments_upload

Eine Datei als multipart/form-data in die /Attachments-Unterressource eines Datensatzes hochladen. fileData muss base64-kodiert sein

entity, key, fileData, fileName, contentType?

Konfiguration & Hilfe

Tool

Beschreibung

Parameter

instructions_get

Gibt den vollständigen Betriebsleitfaden zurück: OData-Syntax, Subformular-Muster, Drosselungsgrenzen, Regeln zur Datumsbehandlung, bekannte Fehlermuster und Architekturbeispiele. Rufen Sie dieses Tool zuerst auf, wenn Sie eine unbekannte Entität erkunden

—

config_restflag_update

Setzt RESTFLAG=Y oder N in der Tabelle FORMLIMITED, um den REST-API-Zugriff für ein Priority-Formular zu aktivieren oder zu deaktivieren

formName, restFlag, formType?


Prompts & Ressourcen

Der Server registriert MCP-Prompts (wiederverwendbare Anweisungsvorlagen) und Ressourcen (Live-Daten-Endpunkte).

Prompts (src/prompts/)

Name

Zweck

query_priority_entity

Leitfaden zum Erstellen von OData-Abfragen gegen eine Entität

explore_entity_relationships

Erläutert die Subformular-Hierarchie einer bestimmten Entität

modify_priority_data

Führt durch Erstellungs-, Aktualisierungs- und Löschoperationen

date_handling_guide

Wichtige Regeln für Datumsfilter — ISO-Format, Operatorvalidierung

known_failure_patterns

Dokumentierte 404/501/400-Muster und ihre Workarounds

pagination_guide

Erläutert $top/$skip- und Zählmuster

Ressourcen (src/resources/)

URI

Zweck

priority://entities/list

Live-Liste aller REST-fähigen Entitäten (RESTFLAG=Y)

priority://entity-schema/{entity}

Schema für eine bestimmte Entität (Template-URI)

priority://queries/common

Bibliothek einsatzbereiter Abfragebeispiele

priority://subforms/reference

Referenzhandbuch für Subformular-Muster und -Operationen


Beispiel für einen Tool-Aufruf

Fragen Sie die drei neuesten Verkaufsaufträge für Kunde 1011 ab — gesendet als JSON-RPC 2.0 an POST /mcp:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "query_run",
    "arguments": {
      "entity":  "ORDERS",
      "filter":  "CUSTNAME eq '1011'",
      "select":  ["ORDNAME", "CUSTNAME", "CURDATE", "TOTPRICE"],
      "top":     3,
      "orderby": "CURDATE desc"
    }
  }
}

Der Server sendet:

GET /odata/Priority/.../ORDERS?$format=json&$filter=CUSTNAME+eq+'1011'
  &$select=ORDNAME,CUSTNAME,CURDATE,TOTPRICE&$top=3&$orderby=CURDATE+desc

Antwort:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{
      "type": "text",
      "text": "{\"value\":[{\"ORDNAME\":\"SO25000001\",\"CUSTNAME\":\"1011\",\"CURDATE\":\"2025-07-15T00:00:00+03:00\",\"TOTPRICE\":15000.0},...],\"_mcp_metadata\":{\"entity\":\"ORDERS\",\"resultCount\":2,\"filterApplied\":true}}"
    }],
    "isError": false
  }
}

Datumsformat: Priority gibt Daten als ISO 8601 mit einem Zeitversatz zurück (z. B. 2025-07-15T00:00:00+03:00), nicht als UTC Z. Verwenden Sie in Datumsfiltern die Syntax CURDATE ge 2025-01-01 — nicht das ISO-Z-Format.


Bereitstellung

Docker

# Build
docker build -t priority-mcp .

# Run
docker run --env-file .env -p 3000:3000 priority-mcp

Das Dockerfile verwendet node:18-slim, führt npm run build aus, um src/ über esbuild zu dist/ zu bündeln, und startet dann dist/index.js. Ein Docker-Compose-Setup und ein Generator für lokale TLS-Zertifikate befinden sich in PT/Home deployment/local/.

Produktions-Checkliste

  • Setzen Sie ODATA_MCP_TOKEN explizit — verlassen Sie sich nicht auf das automatisch generierte

  • Setzen Sie TLS_REJECT_UNAUTHORIZED=true

  • Setzen Sie STRICT_DATA_INTEGRITY=true (Standard)

  • Setzen Sie LOG_LEVEL=INFO (Standard — unterdrückt Systemrauschen)

  • Binden Sie HTTP_HOST an eine bestimmte Schnittstelle, falls nicht öffentlich bereitgestellt


Bekannte Einschränkungen

Bekannte Priority-ERP-spezifische Verhaltensweisen, die Sie vor der Entwicklung kennen sollten.

Ratenlimit — 100 Aufrufe pro Minute pro Benutzer Priority Cloud begrenzt auf 100 API-Aufrufe pro Minute und Benutzer, maximal 10 parallele Anfragen, 3 Minuten Timeout pro Aufruf. Gestalten Sie Agenten so, dass sie Operationen wo möglich bündeln.

Antwortlimit — MAXFORMLINE Priority kappt Antworten stillschweigend an der Systemkonstante MAXFORMLINES, unabhängig von $top. Wenn Sie alle Datensätze benötigen, verwenden Sie eine Pagination auf Basis von $skip.

Subformulare sind keine eigenständigen Entitäten Eine direkte Abfrage PORDERITEMS_SUBFORM liefert HTTP 404. Subformulare müssen über die übergeordnete Entität mit $expand=PORDERITEMS_SUBFORM abgerufen werden. metadata_schema_get erkennt dies automatisch und leitet um.

$apply=aggregate wird nicht unterstützt query_sum fällt immer auf einen vollständigen Seiten-Scan zurück, da $apply=aggregate(...) auf dieser Priority-Version nicht unterstützt wird.

GET /ENTITY/$count liefert 500 Verwenden Sie stattdessen ?$top=0&$count=true. Intern versucht tryEstimateCount() zuerst /$count und pagiiert dann in Batches von 500 (begrenzt auf 10.000).

contains()/startswith() werden bei einigen Feldern nicht unterstützt EPROG.ENAME und EREP.ENAME unterstützen nur den exakten Abgleich mit eq — Zeichenfunktionen liefern HTTP 501.

Metadaten-Aktualisierung auf Entitätsebene liefert 400 metadata_refresh ignoriert das Argument entity und führt immer einen vollständigen Cache-Reset durch, da Priority entitätsscharfe Clearnderungen ablehnt.

Batch-URL-Kodierung URLs innerhalb von batch_operations-Anfragen werden nie automatisch kodiert. Leerzeichen und Sonderzeichen müssen manuell Prozent-kodiert werden (Leerzeichen → %20).

Zusammengesetzte Schlüssel Einige Entitäten verwenden zusammengesetzte Schlüssel, z. B. FORMLIMITED: ENAME='X',TYPE='F'; AINVOCES: IVNUM='T9696',IVTYPE='A',DEBIT='D'. Geben Sie den vollständigen zusammengesetzten Schlüssel an entity_update und entity_delete weiter.


Projektstruktur

/
├── src/
│   ├── index.js                    Entry point — creates and starts PriorityMCPServer
│   ├── server.js                   Express app, all routes, auth guard, OAuth 2.1 PKCE
│   ├── sseServer.js                SSE connection manager
│   ├── config.js                   Reads all env vars, resolves .env path
│   ├── version.js                  SERVER_VERSION, KNOWN_ISSUES list
│   │
│   ├── priority/
│   │   └── client.js               PriorityClient — axios instance, auth headers,
│   │                               all API methods (runQuery, createEntity, …)
│   │
│   ├── mcp/
│   │   ├── handler.js              JSON-RPC 2.0 dispatcher (SSE path)
│   │   ├── registry.js             ToolRegistry — registerTool, callTool, listTools
│   │   ├── prompt-registry.js
│   │   ├── resource-registry.js
│   │   ├── priority-mcp-sdk-server.js   Wires registries into McpServer (SDK path)
│   │   ├── tool-call-runner.js          Executes tool, wraps result for MCP response
│   │   └── json-schema-to-zod.js        JSON Schema → Zod conversion
│   │
│   ├── tools/                      One file per tool + priorityTools.js (registration)
│   ├── prompts/                    One file per prompt + priorityPrompts.js
│   ├── resources/                  One file per resource + priorityResources.js
│   └── utils/
│       ├── data-integrity.js       ensureNoMockData(), validateApiResponse()
│       ├── date-handling.js        Date parsing and validation helpers
│       ├── errors.js               createPriorityApiError(), FilterNotAppliedError
│       ├── filter-resolver.js      OData filter string building
│       ├── expand-resolver.js      $expand normalization
│       ├── entity-resolver.js      Entity name / subform name resolution
│       ├── resolve-query-args.js
│       └── subform-query-resolver.js
│
├── data/
│   └── entity-relationships.json   Hardcoded subform map (PORDERS, ORDERS, …)
│
├── tests/
│   ├── scripts/                    Manual test scripts
│   └── results/                    Saved JSON/Markdown test output
│
├── docs/                           Design docs (DATA_INTEGRITY_POLICY, DATE_HANDLING_RULES, …)
├── postman/                        Postman collection for manual API testing
├── deployment/local/               Docker Compose + TLS cert generator
├── build.js                        esbuild bundler: src/ → dist/
└── .env.example                    All env vars documented with descriptions

Tests

Es gibt keinen automatisierten Testenable. Die Tests sind manuelle Skripte, die eine Live-Priority-Verbindung benötigen:

# Read operations
node tests/scripts/test-priority-operations.js

# Write operations (interactive — asks for confirmation)
node tests/scripts/test-write-operations.js

# Test all 19 MCP tools via the running server
node tests/scripts/test-all-mcp-tools-via-server.js

# Standalone resolver smoke tests
node test-keyresolver.js
node test-resolver.js

Warnung: Schreibtests werden echte Datensätze erstellen, aktualisieren und löschen. Führen Sie sie nur gegen ein Entwicklungsunternehmen aus.


Tech-Stack

  • Laufzeit: Node.js 18, ES-Module ("type": "module")

  • MCP-SDK: @modelcontextprotocol/sdk ^1.29.0

  • HTTP-Server: express ^4.21.1

  • HTTP-Client: axios ^1.7.7

  • Schema-Validierung: zur ^4.3.6`

  • Bundler: esbuild ^0.25.0 (über npm run build)

  • Weiteres: cors, dotenv, form-data, uuid, http-errors

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A generic MCP server that dynamically converts OpenAPI-defined REST APIs into tools for LLMs like Claude. It supports multiple authentication methods and transport protocols, enabling seamless interaction with any OpenAPI-compliant API.
    18 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    A standalone MCP server that exposes API endpoints as tools for AI assistants by proxying requests to a target API defined in an OpenAPI specification. It supports various authentication methods and utilizes Server-Sent Events (SSE) to facilitate integration with clients like Claude and ChatGPT.
    -
  • A
    license
    C
    quality
    D
    maintenance
    An MCP server that bridges AI agents to the eyeot ERP, exposing ~600 business actions (CRM, sales, stock, HR, finance, etc.) as MCP tools over stdio via OAuth 2.1 authentication.
    33
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A config-driven MCP server that exposes OData and REST APIs as MCP tools, enabling AI assistants to query, manage, and monitor SAP backends through natural language.
    112 npm
    32
    MIT