ai newsDo., 15. Okt.
EilmeldungNvidia expands Nemotron LLM family with hyper-efficient models for agentic systems

Remote MCP servers with OAuth: lessons from Claude, ChatGPT and Codex

On October 15, 2026, we launched remote MCP servers for three data products: PMWallets (Polymarket traders ranked by on-chain realized PnL), LPSignal (concentrated-liquidity pools ranked by net APR) and OutcomeTick (historical data and backtesting for Polymarket and Predict.fun crypto up/down marke

dev.toDonnerstag 18:18 · 15.10.5 Min. Lesezeit
Bild: dev.to

Am 15. Oktober 2026 haben wir remote MCP-Server für drei Datenprodukte gestartet: PMWallets (nach on-chain realisiertem PnL sortierte Polymarket-Trader), LPSignal (nach netto-APR sortierte Concentrated-Liquidity-Pools) und OutcomeTick (historische Daten und Backtesting für Krypto-Up/Down-Märkte auf Polymarket und Predict.fun). Sie teilen sich ein Design mit einer geschützten URL, die OAuth auslöst, und einer separaten anonymen URL. PMWallets verwendet Streamable HTTP mit zustandslosen JSON-Antworten.

Wir haben sie mit claude.ai, Claude Code, Codex CLI und dem ChatGPT-Entwicklermodus getestet. Das meiste, was fehlschlug, lag bei der OAuth-Discovery und der Client-Registrierung; ein Code-Review fand noch ein weiteres Problem bei der Aufräumlogik für Refresh-Tokens.

Ein MCP-Client startet den OAuth-Flow, wenn der Server mit 401 antwortet und dabei ein WWW-Authenticate-Header auf die Metadaten der geschützten Ressource verweist (RFC 9728):

HTTP / 2 401 www-authenticate: Bearer resource_metadata="https://api.pmwallets.com/.well-known/oauth-protected-resource/mcp", scope="pmwallets" Enter fullscreen mode Exit fullscreen mode Wenn eine unauthentifizierte Anfrage stattdessen eine 200-Antwort und eine Tool-Liste erhält, bleibt der Client anonym. Das schließt eine URL aus, die öffentliche Tools für alle und Konto-Tools für angemeldete Nutzer bereitstellt. Jede Haupt-URL antwortet ohne Zugangsdaten mit 401, und die anonymen Tools liegen unter /public, wo nie danach gefragt wird.

Bei PMWallets tragen die Lese-Tools (leaderboard, entity, market, fills, export_quote und weitere) die Annotation readOnlyHint: true. Die Abo- und Kauf-Tools subscribe, buy_export und cancel_subscription tragen destructiveHint: true. LPSignals 8 Tools und OutcomeTicks 14 Tools sind ausschließlich lesend; keiner der beiden Server hat Tools, die Ausgaben verursachen.

{ "name": "leaderboard", "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true } } Enter fullscreen mode Exit fullscreen mode In den aufgezeichneten Tests:

PMWallets verkauft vergangene Fills eines Traders als Dateien, eine pro Wallet und UTC-Tag, und deckt etwa die letzten zwei Monate ab. Zu den Tools gehören export_options, export_quote, buy_export und export_file.

Anfangs erwähnten die Server-Instructions die History-Exports nicht, und Claude teilte einem Nutzer mit, dass Historie vor dem Zeitpunkt des Abos nicht verfügbar sei, obwohl die Export-Tools bereits vorhanden waren. Die Instructions besagen nun, dass vergangene Fills separat als Exports verkauft werden und welches Tool wofür zuständig ist.

PMWallets betreibt einen OAuth-2.1-Authorization-Server mit:

LPSignal hat ebenfalls stündliche, nur für MCP gültige Access-Tokens, rotierende 30-Tage-Refresh-Tokens, Revocation nach RFC 7009 und eine Liste „Connected AI apps".

OutcomeTick hat separate API-Keys für seine Daten-, Smart-Money- und Backtest-Produkte. Die Authorisierungsseite hat ein Feld für jeden davon, und jedes Feld akzeptiert nur den Key des jeweiligen Produkts.

{ "token_endpoint_auth_method": "private_key_jwt" } Enter fullscreen mode Exit fullscreen mode Alle drei Produkte stießen bei dieser Deklaration auf ein Kompatibilitätsproblem. Dasselbe Dokument listet in token_endpoint_auth_methods_supported nichts auf. Es funktionierte, ChatGPT als Public Client mit PKCE zu behandeln, ohne die JWT-Client-Authentifizierung nach RFC 7523 zu implementieren.

Die Erkennung der Wiederverwendung hängt davon ab, dass Aufzeichnungen über bereits eingelöste Refresh-Tokens aufbewahrt werden.

PMWallets hatte einen Cleanup-Job, der benutzte Refresh-Tokens löschte, sobald sie abgelaufen waren. Das wirkte harmlos, da ein abgelaufenes Token ohnehin nicht mehr eingelöst werden kann. Aber sobald die Zeile weg ist, ist ein wiedergespieltes Token nicht mehr „benutzt", sondern einfach unbekannt. Nach etwa 30 Tagen wurde eine Wiedergabe nur noch als gewöhnliches ungültiges Token abgelehnt, und die zugehörige Verbindung blieb bestehen.

Das Codex-Review fand dies in PMWallets, und OutcomeTick bestätigte dasselbe Problem.

LPSignal und OutcomeTick verwenden /v1/mcp; PMWallets nutzte ursprünglich /mcp. Ein Nutzer fügte https://api.pmwallets.com/v1/mcp in ChatGPT ein. Die Anmeldung gelang, dann zeigte ChatGPT:

Authentication succeeded, action discovery failed

Diese Route existierte nicht. Ohne Token erhielt ChatGPTs POST eine 403-Antwort von der Origin-Prüfung, und die pfadspezifischen Metadaten lieferten 404. ChatGPT fiel auf die Root-Metadaten zurück, die /mcp beschrieben, und schloss OAuth ab. Anschließend sendete es einen POST an /v1/mcp mit dem Token, erhielt 404 und meldete einen Discovery-Fehler.

PMWallets stellt /v1/mcp nun als Alias mit eigenen Metadaten für die geschützte Ressource bereit, wobei resource auf https://api.pmwallets.com/v1/mcp gesetzt ist. Die 401-Antwort verweist auf diese Metadaten, und der Alias ist in der Origin-Ausnahme und den Rate-Limits enthalten.

PMWallets löst nutzerangegebene Hostnamen für Webhooks und CIMD-Metadaten-Abfragen auf.

In Node nutzt dns.lookup getaddrinfo im libuv-Thread-Pool, der standardmäßig vier Threads hat. Derselbe Pool führt auch Dateisystemaufrufe und etwas Krypto aus. Ein Nutzer, der den Hostnamen kontrolliert, kann Lookups verlangsamen, und wenige davon halten unabhängige Arbeit im Prozess auf. Für diese Lookups sind wir zum c-ares-basierten dns.Resolver gewechselt, der den Pool nicht verwendet, mit einer gesamten Deadline.

Das zweite Problem lag in net.BlockList. Wir hatten::ffff:0:0/96 aufgenommen, um IPv4-gemappte IPv6-Adressen zu blockieren. Mit dieser Regel in der Liste wurde jede reine IPv4-Adresse als intern klassifiziert, öffentliche Hosts eingeschlossen. Wandle eine gemappte Adresse stattdessen selbst in IPv4 um und prüfe sie gegen die IPv4-Regeln.

PMWallets' export_file streamt und dekomprimiert den Download und liefert nur die angeforderte Seite zurück. Ein Aufruf scannt höchstens 50.000 Zeilen, gleichzeitige Lesevorgänge sind begrenzt, und die Lesung bricht ab, wenn der Client die Verbindung trennt. Ohne die Disconnect-Prüfung hätte der Server weiter heruntergeladen und dekomprimiert, obwohl der Client bereits weg war.

Alle drei Server begrenzen die Rate von MCP-Anfragen. LPSignal und OutcomeTick lehnen JSON-RPC-Batches ab. PMWallets akzeptiert bis zu 10 Nachrichten pro Batch und führt sie einzeln aus.

Für Claude Code und Codex CLI fügt man die geschützte URL hinzu:

# Claude Code claude mcp add --transport http pmwallets https://api.pmwallets.com/mcp # Codex CLI codex mcp add pmwallets --url https://api.pmwallets.com/mcp Enter fullscreen mode Exit fullscreen mode Für die Verbindung zu LPSignal oder OutcomeTick verwendet man die jeweilige URL aus der Tabelle. PMWallets wurde auch mit einem claude.ai-Custom-Connector und einem ChatGPT-Web-Custom-Connector im Entwicklermodus getestet. LPSignal unterstützt Wallet-Anmeldung mit beliebiger Wallet und hat ein kostenloses Konto. PMWallets akzeptiert OAuth oder einen Bearer-API-Key; die Authorisierungsseite von OutcomeTick akzeptiert seine produktspezifischen Keys.

Die /public-URLs benötigen kein Konto. PMWallets stellt ein 20-zeiliges Leaderboard-Beispiel, Trader-Datensätze und Market-Abfragen bereit. LPSignal stellt alles außer my_account bereit. OutcomeTick stellt Coverage und Pläne, Backtest-Kapazität und Quotes, Strategieprüfungen sowie Smart-Money-Pläne und Coverage bereit.

Alle drei sind im offiziellen MCP Registry gelistet ( io.github.polymarketwallets/pmwallets, app.lpsignal/lpsignal, io.github.outcometick/outcometick ) und haben Claude-Code-Plugins. OutcomeTick liefert außerdem einen lokalen stdio-Server ( ot mcp ) mit einem Test, der dessen Tool-Set identisch mit dem des Remote-Servers hält. Einrichtungsanleitungen: pmwallets.com/ai-agents, LPSignals/lpsignal-mcp, outcometick.com/llms-full.txt.

Ich entwickle PMWallets, LPSignal und OutcomeTick.

Automatisch übersetzt. Das Original auf Englisch ist unten aufklappbar.

Original (Englisch) anzeigen

On October 15, 2026, we launched remote MCP servers for three data products: PMWallets (Polymarket traders ranked by on-chain realized PnL), LPSignal (concentrated-liquidity pools ranked by net APR) and OutcomeTick (historical data and backtesting for Polymarket and Predict.fun crypto up/down markets). They share a design with a protected URL that triggers OAuth and a separate anonymous URL. PMWallets uses Streamable HTTP with stateless JSON responses.

We tested them with claude.ai, Claude Code, Codex CLI and ChatGPT developer mode. Most of what broke was in OAuth discovery and client registration; a code review found one more problem in refresh-token cleanup.

An MCP client starts the OAuth flow when the server answers 401 with a WWW-Authenticate header pointing at the protected-resource metadata (RFC 9728):

HTTP / 2 401 www-authenticate: Bearer resource_metadata="https://api.pmwallets.com/.well-known/oauth-protected-resource/mcp", scope="pmwallets" Enter fullscreen mode Exit fullscreen mode If an unauthenticated request gets a 200 and a tool list instead, the client stays anonymous. That rules out one URL that serves public tools to everyone and account tools to signed-in users. Each main URL returns 401 without credentials, and the anonymous tools live at /public, which never asks.

On PMWallets, the read tools ( leaderboard, entity, market, fills, export_quote and others) carry readOnlyHint: true. The subscription and purchase tools, subscribe, buy_export and cancel_subscription, carry destructiveHint: true. LPSignal's 8 tools and OutcomeTick's 14 are all read-only; neither server has spending tools.

{ "name": "leaderboard", "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true } } Enter fullscreen mode Exit fullscreen mode In the recorded tests:

PMWallets sells past fills of a trader as files, one per wallet per UTC day, covering about the last two months. The tools include export_options, export_quote, buy_export and export_file.

Early on, the server instructions didn't mention history exports, and Claude told a user that history from before the subscription was unavailable, although the export tools were already there. The instructions now say that past fills are sold separately as exports and which tool does what.

PMWallets runs an OAuth 2.1 authorization server with:

LPSignal also has one-hour MCP-only access tokens, rotating 30-day refresh tokens, RFC 7009 revocation and a "Connected AI apps" list.

OutcomeTick has separate API keys for its data, smart-money and backtest products. The authorization page has a field for each, and each field accepts only that product's key.

{ "token_endpoint_auth_method": "private_key_jwt" } Enter fullscreen mode Exit fullscreen mode All three products hit a compatibility issue with this declaration. The same document lists none in token_endpoint_auth_methods_supported. Treating ChatGPT as a public client using PKCE worked without implementing RFC 7523 JWT client authentication.

Reuse detection depends on retaining records of refresh tokens that have already been exchanged.

PMWallets had a cleanup job that deleted used refresh tokens once they expired. That looks harmless, since an expired token can't be exchanged anyway. But once the row is gone, a replayed token is no longer "used", just unknown. After about 30 days, a replay was rejected as an ordinary bad token, and the connection it belonged to stayed alive.

Codex review found this in PMWallets, and OutcomeTick confirmed the same issue.

LPSignal and OutcomeTick use /v1/mcp; PMWallets originally used /mcp. A user pasted https://api.pmwallets.com/v1/mcp into ChatGPT. Sign-in succeeded, then ChatGPT showed:

Authentication succeeded, action discovery failed

That route did not exist. Without a token, ChatGPT's POST got a 403 from the Origin check, and the path-specific metadata returned 404. ChatGPT fell back to the root metadata, which described /mcp, and completed OAuth. It then POSTed to /v1/mcp with the token, received 404 and reported a discovery failure.

PMWallets now serves /v1/mcp as an alias with its own protected-resource metadata, with resource set to https://api.pmwallets.com/v1/mcp. The 401 points to that metadata, and the alias is included in the Origin exemption and rate limits.

PMWallets resolves user-supplied hosts for webhooks and CIMD metadata fetches.

In Node, dns.lookup uses getaddrinfo on the libuv thread pool, which has four threads by default. The same pool runs file system calls and some crypto. A user who controls the hostname can make lookups slow, and a few of them hold up unrelated work in the process. For these lookups we switched to the c-ares-based dns.Resolver, which doesn't use the pool, with an overall deadline.

The second problem was in net.BlockList. We added::ffff:0:0/96 to block IPv4-mapped IPv6 addresses. With that rule in the list, every plain IPv4 address was classified as internal, public hosts included. Convert a mapped address to IPv4 yourself and check it against the IPv4 rules instead.

PMWallets' export_file streams and decompresses the download, returning only the requested page. A call scans at most 50,000 lines, concurrent reads are limited, and the read aborts when the client disconnects. Without the disconnect check, the server would keep downloading and decompressing after the client had gone away.

All three servers rate-limit MCP requests. LPSignal and OutcomeTick reject JSON-RPC batches. PMWallets accepts up to 10 messages per batch and executes them one at a time.

For Claude Code and Codex CLI, add the protected URL:

# Claude Code claude mcp add --transport http pmwallets https://api.pmwallets.com/mcp # Codex CLI codex mcp add pmwallets --url https://api.pmwallets.com/mcp Enter fullscreen mode Exit fullscreen mode Use the LPSignal or OutcomeTick URL from the table to connect those servers. PMWallets was also tested with a claude.ai custom connector and a ChatGPT web developer-mode custom connector. LPSignal supports wallet sign-in with any wallet and has a free account. PMWallets accepts OAuth or a bearer API key; OutcomeTick's authorization page accepts its product-specific keys.

The /public URLs need no account. PMWallets exposes a 20-row leaderboard sample, trader records and market lookups. LPSignal exposes everything except my_account. OutcomeTick exposes coverage and plans, backtest capacity and quotes, strategy checks, and smart-money plans and coverage.

All three are listed in the official MCP Registry ( io.github.polymarketwallets/pmwallets, app.lpsignal/lpsignal, io.github.outcometick/outcometick ) and have Claude Code plugins. OutcomeTick also ships a local stdio server ( ot mcp ) with a test that keeps its tool set identical to the remote one. Setup guides: pmwallets.com/ai-agents, LPSignals/lpsignal-mcp, outcometick.com/llms-full.txt.

I build PMWallets, LPSignal and OutcomeTick.

Quelle: dev.to (dev.to). Original öffnen