Skip to main content
Glama
olykov

@olykov/node-red-contrib-mcp-server-readonly

by olykov

@olykov/node-red-contrib-mcp-server-readonly

Generische Model Context Protocol (MCP)-Servernodes für Node-RED: Machen Sie jeden Flow als MCP-Tool über einen OAuth-geschützten Endpunkt verfügbar, mit optionaler schreibgeschützter Node-RED-Admin-Flow-Inspektion. Keine Hausautomations- oder andere Domänenkopplung – dies ist ein nackter Baustein, um Node-RED-Flows in MCP-Tools zu verwandeln, die KI-Assistenten (Claude, Codex usw.) aufrufen können.

Breaking Change in 0.5.0 – nur noch öffentlicher Client (PKCE). Client-Secrets und die node-seitige Redirect-URI-Whitelist sind entfernt: Der offene Client-Registrierungs-Endpunkt hat jedem Aufrufer jedes konfigurierte Secret ausgehändigt, und Redirect-URIs werden ohnehin vom Identity Provider bei /authorize validiert. Migration: Stellen Sie den IdP-Client auf öffentlich mit PKCE um (ein weiterhin vertraulicher Client schlägt beim Token-Austausch mit invalid_client fehl), stellen Sie sicher, dass die MCP-Client-Callback-URLs beim IdP auf der Whitelist stehen, und wenn der Node vor einem gespeicherten Secret warnt, öffnen Sie seine Konfiguration, klicken Sie auf Fertig und stellen Sie bereit, um es zu löschen. MCP-Clients, die vor dem Upgrade verbunden waren, haben möglicherweise die alte Registrierung zwischengespeichert – entfernen Sie den Server im Client und fügen Sie ihn erneut hinzu, wenn die Anmeldung nicht richtig funktioniert.

Nodes

  • mcp-server (Konfigurationsknoten) – hostet einen eigenständigen MCP-JSON-RPC-Endpunkt unter POST /mcp/<path>, OAuth-2.0-Protected-Resource-Discovery (RFC 9728), Authorization-Server-Discovery (RFC 8414) mit Proxy zu einem echten OIDC-Identity-Provider sowie einen Shim für die dynamische Client-Registrierung, sodass OAuth-fähige MCP-Clients (z. B. Claude.ai) sich selbst registrieren und authentifizieren können. Mehrere mcp-server-Knoten können koexistieren, jeder mit eigenem Pfad und eigener unabhängiger Auth-Konfiguration.

  • mcp-in – definiert ein MCP-Tool (Name, Beschreibung, JSON-Schema-Parameter und ein optionales Zugriffsgate pro Tool). Wenn ein MCP-Client das Tool aufruft, sendet der Knoten eine Nachricht mit den Aufrufargumenten; verdrahten Sie den Rest des Flows, um die eigentliche Arbeit zu erledigen. Die Argumente in msg.payload sind nicht vertrauenswürdige Aufrufereingaben – das JSON-Schema ist Dokumentation für das Modell, keine Validierung – daher muss der Flow sie validieren und maskieren, bevor sie in Shell-Befehlen, Dateipfaden, URLs oder Abfragen verwendet werden.

  • mcp-out – löst einen ausstehenden Tool-Aufruf auf. Verdrahten Sie das Ende Ihres Flows hierher, wobei msg._mcpCallId intakt ist (aus der ursprünglichen mcp-in-Nachricht) und msg.payload auf das Ergebnis gesetzt ist.

Eine einzelne mcp-in → ... → mcp-out-Kette ist ein MCP-Tool. Bauen Sie beliebig viele Ketten gegen denselben mcp-server-Knoten, um ein ganzes Toolset verfügbar zu machen.

Admin-Read-only-API-Tools

Aktivieren Sie Admin-Read-only-API-Tools auf einem mcp-server-Knoten, um zusätzlich ein Tool verfügbar zu machen, das auf Node-REDs eigener Admin-HTTP-API arbeitet, gesteuert durch einen konfigurierbaren JWT-Anspruch (Standard: groups enthält admin):

  • get_flow – listet alle Flow-Tabs (id, label, Knotenanzahl) auf oder gibt das vollständige JSON eines Tabs zurück, wenn mit einer id aufgerufen.

Konfigurieren eines mcp-server-Knotens

  • Allgemein: Name, path (→ registriert POST /mcp/<path>), die öffentliche Server-URL, unter der diese Node-RED-Instanz erreichbar ist, optionaler Servername/Anweisungen, die dem Modell angezeigt werden, und ein optionaler Hostname-Filter (siehe unten).

  • Auth: eine OIDC-Identity-Provider-Issuer-URL (erforderlich – Endpunkte werden automatisch aus /.well-known/openid-configuration ermittelt, mit PocketID-artigen Fallback-Pfaden; wenn Sie dies leer lassen, entsteht ein defektes OAuth-Discovery-Dokument mit relativen Endpunkten und ohne funktionierende Authentifizierung, daher lässt der Editor Sie ohne sie nicht bereitstellen), eine Client-ID (der IdP-Client muss öffentlich mit PKCE sein – Client-Secrets werden nicht mehr unterstützt, und Redirect-URIs werden nur beim IdP konfiguriert und validiert), Scopes, Token-Audience, ein optionales lokales Debug-Token, das den IdP für lokale Tests vollständig umgeht (setzen Sie eine beliebige Platzhalter-URL in Identity provider und verlassen Sie sich auf das Debug-Token – es wird nie kontaktiert, wenn das Debug-Token übereinstimmt; der groups-Anspruch, den der Debug-Benutzer erhält, ist konfigurierbar, sodass auch die Zugriffsgates lokal getestet werden können), und das Access-claim- / Server-access-Gate (siehe unten).

  • Admin: Aktivieren/Deaktivieren der Admin-Read-only-API-Tools, Admin-Token (für die Node-RED-Admin-API), Admin-API-Port und das Read-only-access-Gate, das zusätzlich nur die schreibgeschützten Admin-Tools einschränkt.

Zugriffskontrolle

Ein Anspruchsname, viele Wertelisten. Access claim auf dem Auth-Tab (Standard groups) benennt den einzelnen JWT-Anspruch, gegen den jedes Gate prüft. Jedes andere Autorisierungsfeld ist eine kommagetrennte Any-of-Liste der Werte dieses Anspruchs – media, ops besteht, wenn der Anspruch mindestens einen davon enthält. Eine leere Liste erlegt keine Einschränkung auf.

Verschachtelte Ansprüche werden über einen Punktpfad angesprochen, für Anbieter, die Rollen nicht auf oberster Ebene des Tokens ablegen: realm_access.roles liest Keycloaks Realm-Rollen, und jede Tiefe funktioniert. Ein Schlüssel, der wörtlich existiert, gewinnt immer, sodass ein Anspruch, der tatsächlich einen Punkt im Namen hat, weiterhin auf sich selbst aufgelöst wird. Nur Zeichenfolgen und Arrays von Zeichenfolgen werden abgeglichen – das Zeigen des Anspruchs auf ein Containerobjekt gewährt nichts, anstatt versehentlich zu matchen.

Feld

Wo

Einschränkung

Server access

mcp-server, Auth-Tab

jedes Tool auf diesem Server

Tool access

mcp-in

dieses eine Tool, zusätzlich

Read-only access

mcp-server, Admin-Tab

get_flow, zusätzlich

Die Listen werden mit UND kombiniert. Ein Tool zu erreichen bedeutet, die Liste des Servers und die eigene Liste des Tools zu erfüllen. Admin-Read-only-API-Tools sind kein Sonderfall – ihr Feld ist einfach die Tool-Liste für get_flow.

Access claim: groups     Server access: staff
tool A: (empty)   tool B: media   Admin access: admin

groups=[staff]         → A
groups=[staff, media]  → A, B
groups=[staff, admin]  → A + get_flow
groups=[media]         → nothing            (server list not cleared)
groups=[guest]         → nothing

Server access empty:
groups=[media]         → A, B
groups=[guest]         → A

Jeder mit einem gültigen Token verbindet sich weiterhin – initialize gelingt immer – aber Tools, die ein Aufrufer nicht erreichen kann, werden in tools/list und in den initialize-Anweisungen ausgeblendet. Ein direkter tools/call auf eines davon wird als MCP-Tool-Ergebnis mit isError: true und einer erklärenden Nachricht abgelehnt (kein roher JSON-RPC-Protokollfehler), sodass der Grund das aufrufende Modell erreicht, anstatt in einem generischen „Tool-Ausführung fehlgeschlagen“ zusammenzufallen.

Die Client-Achse: erforderlicher Scope

Die obigen Listen beantworten, was dieser Benutzer tun darf. Required scope beantwortet eine andere Frage – was dieser Client im Namen des Benutzers tun durfte – und beide werden mit UND geprüft.

Sie sind nicht austauschbar. Eine Gruppe sagt, wer an der Tastatur sitzt; ein Scope sagt, wie viel von der Autorität dieser Person an die Software delegiert wurde, die das Token hält. Wenn man sie in ein Feld zusammenfasst, wird nur eines berücksichtigt: Ein Client mit einem Nur-Lese-Scope, der von jemandem bedient wird, der schreiben darf, würde schreiben. Die Gewährung des Clients muss die Rechte des Benutzers begrenzen, nicht ignoriert werden.

Der erforderliche Scope wird automatisch zu scopes_supported hinzugefügt, sodass im Scopes-Feld nichts wiederholt werden muss, und er wird in der WWW-Authenticate-Challenge bei einer 401 genannt.

Der Scope-Anspruch wird so gelesen, wie OAuth es definiert (RFC 6749 §3.3): eine durch Leerzeichen getrennte Zeichenfolge oder ein Array, falls Ihr Anbieter eines sendet. Der Anspruchsname ist nicht konfigurierbar, da er standardisiert ist; scp wird als Fallback für Microsoft Entra und Okta gelesen. Das Feld selbst ist eine kommagetrennte Any-of-Liste. Leer bedeutet keine Einschränkung, sodass eine Installation, die es nie ausfüllt, nicht betroffen ist; ein konfigurierter Scope, den das Token nicht trägt, wird abgelehnt, auch wenn das Token überhaupt keinen Scope-Anspruch hat.

Upgrade: Das Admin-Gate hat kein eigenes Anspruchsnamen-Feld mehr – es prüft wie alles andere gegen den Access claim des Auth-Tabs. Wenn Sie einen anderen Anspruchsnamen für Admin-Tools festgelegt hatten, verschieben Sie diesen Wert auf den Auth-Tab oder passen Sie die Admin-Liste entsprechend an. Ein Wert, der wörtlich ein Komma enthält, wird jetzt als Liste statt als eine einzelne Zeichenfolge gelesen. Die Gate-Felder wurden auch umbenannt (Required claim/Required valueAccess claim/Server access/Admin access); die zugrunde liegenden Einstellungen sind unverändert, sodass bestehende Flows unverändert weiter funktionieren.

Protokoll

Der Endpunkt spricht MCP-Protokollversion 2024-11-05 über einfaches HTTP-POST – jede Anfrage ist eine JSON-RPC-Nachricht, jede Antwort ein JSON-Body. initialize, tools/list, tools/call und ping werden unterstützt; es gibt keinen SSE/Streaming-GET-Kanal und keine serverinitiierten Nachrichten. Dies ist die Teilmenge, die heutige OAuth-fähige MCP-Clients (z. B. Claude) tatsächlich gegen einen Nur-Tools-Server verwenden. Die beworbene Version ist absichtlich festgelegt, anstatt das Angebot des Clients zu spiegeln.

Hostname-Filter

Standardmäßig deaktiviert. Wenn Nur Anfragen für diesen Hostnamen bedienen aktiviert ist, antwortet der Knoten nur auf Anfragen, deren Host-Header mit dem Hostnamen in seiner Server-URL übereinstimmt. Dadurch können mehrere mcp-server-Knoten denselben path auf einer Node-RED-Instanz teilen, wobei jeder nur auf seinen eigenen virtuellen Host antwortet – nützlich hinter einem Reverse-Proxy, der mehrere Hostnamen für ein Node-RED-Backend bedient. Lassen Sie es für einen einzelnen Server deaktiviert, oder wenn ein Reverse-Proxy den Host-Header umschreibt.

Reverse-Proxy

Jeder mcp-server-Knoten ist seine eigene OAuth-Ressource – anders als ein einzelner gemeinsamer MCP-Endpunkt registriert jede Instanz ihre eigenen Discovery- und Registrierungsrouten, unter ihrem path. Für einen Knoten mit path: docker und Server-URL: https://mcp.example.com existieren diese sechs Routen:

Methode & Pfad

Zweck

POST /mcp/docker

Der JSON-RPC-MCP-Endpunkt (durch Bearer-Token geschützt)

GET /mcp/docker/.well-known/oauth-protected-resource

Ressourcen-Metadaten (RFC 9728), Pfad-eingefügte Form

GET /.well-known/oauth-protected-resource/mcp/docker

Ressourcen-Metadaten (RFC 9728), RFC-8414-Form

GET /mcp/docker/.well-known/oauth-authorization-server

Auth-Server-Metadaten (RFC 8414), Pfad-eingefügte Form

GET /.well-known/oauth-authorization-server/mcp/docker

Auth-Server-Metadaten (RFC 8414), RFC-8414-Form

POST /mcp/docker/oauth/register

Shim für dynamische Client-Registrierung

Client-ID-Metadaten-Dokumente (CIMD). MCP 2026-07-28 verwirft die dynamische Client-Registrierung zugunsten von CIMD, bei dem die ID eines Clients die HTTPS-URL eines Metadaten-Dokuments ist, das er selbst hostet. Dieser Knoten bewirbt client_id_metadata_document_supported, indem er spiegelt, was das Discovery-Dokument Ihres IdP sagt – es wird hier nie konfiguriert, weil der IdP die Client-ID auflöst und dieser Server nicht versprechen kann, Unterstützung zu bieten, die der IdP nicht hat. Discovery wird einmal abgerufen und für die Lebensdauer des Knotens zwischengespeichert, sodass das Aktivieren oder Deaktivieren von CIMD beim IdP beim nächsten Neustart oder Bereitstellen von Node-RED übernommen wird – nicht live.

Der DCR-Shim ist standardmäßig deaktiviert und sollte deaktiviert bleiben. Er existiert für eine Situation: einen Client, der CIMD nicht verwenden kann, der mit einem IdP spricht, der DCR selbst nicht kann. Wenn er aktiviert ist, bewirbt dieser Server sich selbst als Autorisierungsserver, damit der Registrierungsendpunkt auffindbar ist – was auch bedeutet, dass das iss, das Ihr IdP zurückgibt, nicht mit dem Issuer übereinstimmt, den der Client aufgezeichnet hat, und ein Client, der RFC 9207 durchsetzt (von MCP 2026-07-28 gefordert), sich weigern wird, den Ablauf abzuschließen. Wenn er deaktiviert ist, werden Clients direkt zum IdP geschickt und müssen CIMD oder eine vorregistrierte Client-ID verwenden. Ein Knoten, der vor der Einführung dieses Schalters konfiguriert wurde, behält den Shim an, da er das bisher getan hat.

Beide Mechanismen bleiben absichtlich verfügbar. Clients wählen in der Reihenfolge der Spezifikation – zuerst vorregistriert, dann CIMD, dann DCR –, sodass ein Client ohne CIMD-Unterstützung weiterhin genau wie zuvor den Registrierungs-Shim verwendet. Welchen Mechanismus jeder Client verwendet hat, ist im Log ablesbar: MCP CIMD client authenticated: <url> beim ersten Mal, wenn ein CIMD-Client nach einem Neustart gesehen wird, und MCP DCR fallback für einen Client, der sich registriert hat, obwohl der IdP CIMD bewirbt. Zusammen decken die beiden Zeilen jeden Client ab, der den Server erreicht.

Tokens von einem CIMD-Client tragen diese Dokument-URL als Audience anstelle Ihrer vorregistrierten Client-ID, und sie werden akzeptiert, wann immer der IdP CIMD bewirbt. Dieser Knoten führt keine eigene zweite Zulassungsliste, daher ist die Liste der akzeptierten Metadaten-Dokumente des IdP die Grenze – jeder CIMD-Client auf dieser Liste kann diesen Server erreichen, wobei das Claim-Gate die verbleibende Prüfung ist.

Beide Well-Known-Formen werden beworben, weil verschiedene MCP-Clients unterschiedliche abfragen – bieten Sie beide an. Da die Routen jeder Instanz die Formen /mcp/<path> und /.well-known/*/mcp/<path> teilen, deckt ein Satz Wildcard-Regeln jeden aktuellen und zukünftigen mcp-server-Knoten ab (solange alle über dieselbe Domain/denselben Upstream erreichbar sind) – keine Reverse-Proxy-Änderung erforderlich, wenn ein neuer path hinzugefügt wird. Beispiel mit Caddy über caddy-docker-proxy-Labels:

labels:
  caddy_1: mcp.example.com
  caddy_1.reverse_proxy_0: /mcp/* "{{upstreams 1880}}"
  caddy_1.reverse_proxy_1: /.well-known/oauth-protected-resource/mcp/* "{{upstreams 1880}}"
  caddy_1.reverse_proxy_2: /.well-known/oauth-authorization-server/mcp/* "{{upstreams 1880}}"

Node-RED selbst gibt für jeden Pfad, der keine tatsächlich registrierte Route ist, einen 404 zurück, sodass die Wildcard nichts über das hinaus exponiert, was jeder bereitgestellte mcp-server-Knoten bereits registriert. Wenn ein path auf einer anderen Domain als die anderen erreichbar sein muss, geben Sie ihm einen eigenen caddy_N-Site-Block (oder kombinieren Sie ihn mit Hostname-Filterung oben).

Was der Identitätsanbieter unterstützen muss (gleiche Anforderungen wie lib/mcp-auth.js):

  • Ein OIDC-Anbieter mit Discovery – Endpunkte werden aus ‹issuerUrl›/.well-known/openid-configuration gelesen, mit Rückgriff auf das Pfad-Layout von PocketID, falls Discovery nicht verfügbar ist.

  • JWT-Zugriffstokens, signiert mit einem Schlüssel, der auf dem JWKS des Anbieters veröffentlicht ist (Tokens werden lokal verifiziert; opaque/nur-Introspection-Zugriffstokens werden nicht unterstützt).

  • Ein öffentlicher Client mit PKCE (S256), Grant-Typen authorization_code + refresh_token, und die Redirect-URI(s) des MCP-Clients sind auf die Whitelist gesetzt (für Claude.ai: https://claude.ai/api/mcp/auth_callback). Redirect-URIs werden nur beim Identitätsanbieter konfiguriert und validiert – der Knoten führt keine eigene Zulassungsliste mehr, sodass die Wildcard-Unterstützung des IdP (z. B. die von PocketID) unverändert funktioniert. Client-Secrets werden nicht mehr unterstützt: Der offene Client-Registrierungs-Endpunkt hat jedes konfigurierte Secret jedem Aufrufer ausgehändigt, sodass es nie wirklich geheim sein konnte. Falls ein Secret aus einer früheren Version noch gespeichert ist, wird es mit einer Warnung ignoriert – stellen Sie den IdP-Client auf öffentlich um, öffnen Sie dann die Konfiguration des Knotens, klicken Sie auf Fertig und stellen Sie bereit, um das gespeicherte Secret zu löschen und die Warnung zu beseitigen.

Getestet mit Caddy (Reverse-Proxy) + PocketID (Identitätsanbieter) + Claude.ai und Hermes (MCP-Clients). Jeder spezifikationskonforme OIDC-Anbieter, der JWT-Zugriffstokens ausstellt, sollte hinter einem beliebigen Reverse-Proxy, der die obigen Routen weiterleitet, auf dieselbe Weise funktionieren.

Beispiele

Siehe examples/ für neun importierfertige Flows (Jellyfin, Calibre, Docker, Music Assistant, Radarr, iRobot/rest980, Overseerr, Sonarr, Spotify), jeder mit einem eigenen mcp-server-Knoten (Serverbeschreibung vorausgefüllt, Server URL/Identity provider für Sie zum Ausfüllen leer gelassen) und mcp-in/mcp-out-Tools – eine gute Referenz zum Anbinden eigener Tools.

Entwicklung

npm install
npm test

Lizenz

ISC

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2

  • Self-hosted MCP gateway: turn any API, database or MCP server into AI connectors — no code.

  • MCP Hub: AI service discovery, per-user OAuth, and multi-service workflow orchestration

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/olykov/node-red-contrib-mcp-server-readonly'

If you have feedback or need assistance with the MCP directory API, please join our Discord server