vrchat-mcp
vrchat-mcp
Ein MCP-Server für die VRChat-API. Alle 297 Operationen aus der OpenAPI-Spezifikation, zur Build-Zeit generiert, plus handgeschriebene Tools für Dinge, die ein einzelner Endpunkt nicht leisten kann: Zwei-Faktor-Login, Datei-Uploads, Bildanzeige und die Ereignis-Pipeline.
Läuft lokal über stdio, als Unterprozess von Claude Code oder Claude Desktop. Schreibgeschützt, bis du etwas anderes sagst.
Basiert auf Bun, dem offiziellen MCP-TypeScript-SDK v2 und dem offiziellen
vrchat JavaScript-SDK. Die Tools stammen
aus der VRChat-OpenAPI-Spezifikation und sind
eingecheckt, sodass die Oberfläche dem Upstream folgt, statt dagegen zu verrotten.
Spickzettel
bun install && bun link # `vrchat-mcp` is now on PATH
cp .env.example .env # fill in username, password, contact
claude mcp add vrchat -- vrchat-mcpMinimale .env:
VRCHAT_USERNAME=you
VRCHAT_PASSWORD=hunter2
VRCHAT_CONTACT=you@your-domain.tld # must be real, VRChat 403s generic agentsIch möchte | Tu das |
Erstellen und Bearbeiten aktivieren |
|
Löschen und Moderieren aktivieren |
|
Ausgeben von Guthaben aktivieren |
|
Nur Storefront-Tools freigeben |
|
Alles freigeben |
|
Herausfinden, warum ein Tool fehlt |
|
Riesige Payloads aus dem Kontext halten |
|
Ein Bild ansehen |
|
Ein Bild hochladen |
|
Einen Login in einem neuen Netzwerk entstören | Den E-Mail-Link öffnen, dann |
Toolnamen tragen ihre Herkunft. Zwei Unterstriche bedeuten aus der Spezifikation generiert
(vrchat__getCurrentUser), der Name ist also in VRChats eigener Doku durchsuchbar. Ein
Unterstrich bedeutet: Dieser Server hat es geschrieben (vrchat_authStatus).
Handgeschriebene Tools, vollständig:
Tool | Funktion |
| Login-Zustand, Rate-Limiter und welche Tool-Gruppen durch welche Env-Variable verborgen sind |
| Beantwortet einen geparkten Login mit dem Code, den der Benutzer vorgelesen hat |
| Startet einen Login neu, nachdem ein Neues-Netz-E-Mail-Link geöffnet wurde |
| Löscht die gespeicherte Sitzung |
| Lädt ein VRChat-Bild herunter und gibt es als anzeigbares Bild zurück |
| Führt VRChats vierschrittigen Upload für Nicht-Bild-Dateien aus |
| Lädt ein Bild hoch und hängt es an ein Store-Produkt |
| Ereignisse seit einem Cursor |
| Blockiert, bis das nächste passende Ereignis eintrifft |
| Volltextsuche über die gespeicherte Ereignishistorie |
| Socket-Zustand und Aufbewahrung pro Typ |
Die letzten vier erscheinen nur mit VRCHAT_MCP_WEBSOCKET=1.
Related MCP server: Portals MCP
Installation
bun link legt eine vrchat-mcp-ausführbare Datei auf deinen PATH, sodass nichts
nachgelagert wissen muss, wo das Checkout liegt.
bun install
bun link # from the repo rootRegistriere es per Namen:
claude mcp add vrchat -- vrchat-mcpOder für Claude Desktop in claude_desktop_config.json:
{
"mcpServers": {
"vrchat": {
"command": "vrchat-mcp"
}
}
}Das ist die gesamte Konfiguration. Anmeldedaten kommen aus der .env des Repos, müssen hier
also nicht wiederholt werden, obwohl alles, was du in einen env-Block schreibst, gewinnt.
Entferne den Befehl mit bun unlink.
Wenn du lieber nichts auf deinen PATH legen möchtest, verweise mit einem absoluten Pfad auf die Einstiegsdatei. Der Server wird aus einem beliebigen Arbeitsverzeichnis gestartet, ein relativer Pfad reicht also nicht.
claude mcp add vrchat -- bun run /abs/path/to/vrchat-mcp/src/index.tsDie Kontakt-Anforderung
VRChat lehnt generische User-Agents mit einem 403 ab. VRCHAT_CONTACT fließt in den
beschreibenden User-Agent, den das SDK bei jeder Anfrage sendet, API und WebSocket gleichermaßen,
und ist praktisch Pflicht.
Der Wert muss echt sein. Das SDK weigert sich, Kontakt mit @example.com zu akzeptieren, also
ist der offensichtliche Platzhalter genau der Wert, der garantiert fehlschlägt. Der Server meldet
das als Konfigurationsfehler beim ersten Tool-Aufruf, statt es als mysteriösen 403 auftauchen zu
lassen.
Konfiguration
Drei Ebenen, höchste Priorität zuerst. Ein Projekt kann eigene Optionen setzen, ohne deine Anmeldedaten zu wiederholen.
Echte Umgebungsvariablen, einschließlich des
env-Blocks eines MCP-Clients.envim Verzeichnis, aus dem der Befehl läuft, das Bun automatisch lädt.envim Repo-Root
Ein Projekt, das nur Storefront-Tools will und deine bereits konfigurierten Anmeldedaten nutzt, braucht also eine Zeile daneben:
# ~/my-project/.env
VRCHAT_MCP_TAGS=storeVariable | Standard | Wirkung |
| keine | Kontobenutzername oder E-Mail |
| keine | Kontopasswort |
| keine | Base32-TOTP-Geheimnis. Gesetzt und Login fragt nie nach |
| keine | Kontaktstring im User-Agent. Praktisch erforderlich |
| alle | Zu registrierende Tags. |
| aus | Erstellen und Bearbeiten |
| aus | Löschen und Moderieren. Braucht auch das Schreib-Gate |
| aus | Guthaben ausgeben. Braucht auch das Schreib-Gate |
| aus | Admin-Operationen. Unabhängig vom Schreib-Gate |
| 20 | Anfragen pro Sekunde. |
| 30000 | Wie lange ein Aufruf hinter dem Limiter wartet, bevor er aufgibt |
| aus | Öffnet die Ereignis-Pipeline und registriert die Ereignis-Tools |
| Low-Noise-Set | Zu abonnierende Ereignistypen. Ersetzt den Standard, erweitert ihn nicht |
| 1000 | Ereignisse pro Typ aufbewahrt. Pro-Typ-Überschreibungen: |
| 30d | Altersobergrenze. |
| Projekt- | Ereignisdatenbank-Pfad |
| Projekt- | Sitzungsdatei-Pfad |
| keine | HTTP- oder HTTPS-Proxy für API- und WebSocket-Verkehr |
| 300000 | Wie lange ein geparkter Login auf einen Code wartet |
| aus | Optiert in die Live-Test-Suite |
Booleans akzeptieren 1 oder true, ohne Beachtung der Groß-/Kleinschreibung.
Wo der Zustand lebt
Der Zustand ist pro Projekt. Starte den Server in einem Projekt und seine Sitzung und
Ereignishistorie leben in dessen .vrchat-mcp/. Die Projektwurzel wird gefunden, indem man vom
Arbeitsverzeichnis aus nach oben geht und nach .git, package.json, deno.json,
pyproject.toml oder go.mod sucht. Ein Start aus einem Unterverzeichnis erreicht also
denselben Zustand, statt eine zweite Sitzung eine Ebene tiefer zu stranden.
Das Verzeichnis versteckt sich selbst vor der Versionskontrolle: vrchat-mcp schreibt bei der
Erstellung eine .gitignore mit * hinein, sodass die Sitzungsdatei, die eine
Anmeldeberechtigung ist, geschützt ist, ohne dass das Host-Projekt eine Regel dafür braucht.
Jedes Projekt meldet sich also separat an, und der erste Aufruf in einem neuen Projekt kann nach einem 2FA-Code fragen. Um einen Login überall zu teilen, weise jede Installation auf dieselbe Datei:
VRCHAT_MCP_SESSION=/abs/path/to/shared/session.jsonSicherheits-Gates
Der Server startet schreibgeschützt. 150 der 297 Operationen registrieren sich standardmäßig. Nichts, was schreibt, löscht, ausgibt oder moderiert, erscheint, bis du danach fragst.
Klasse | Was sie abdeckt | Benötigt | Beispiele |
| Jedes | nichts |
|
|
|
|
|
| Jedes |
|
|
| Kaufen und Tilia/KYC/Payout-Pfade |
|
|
| Admin- und Kontolebenszyklus |
|
|
Destruktiv und Geld schichten auf Schreiben auf, also gewährt das Aktivieren von Schreiben genau die Fähigkeit zu erstellen und zu bearbeiten, nie zu löschen oder auszugeben. Admin steht allein und wird von nichts impliziert: Einem Agenten das Bearbeiten eigener Inhalte zu erlauben, darf niemals auch das Löschen des Kontos erlauben.
Wofür du dich entscheidest:
ALLOW_WRITESlässt einen Agenten Dinge erstellen und ändern, die dir gehören. Umkehrbar, meist von Hand.ALLOW_DESTRUCTIVE_WRITESfügt die Aufrufe ohne Rückgängig hinzu. Löschen, Sperren, Kicks, Schließen von Instanzen, Löschen der Benutzerpersistenz.ALLOW_PURCHASESlässt einen Agenten echtes Guthaben ausgeben.purchaseProductListingist eine Live-Transaktion. Setze das nicht, weil eine Tool-Liste unvollständig aussah.ALLOW_ADMINlegt unter anderemdeleteUserfrei. Die meisten davon geben auf einem normalen Konto 403, aberdeleteUserist das, was niemals ein Unfall sein darf.
Gesperrte Operationen bleiben in der generierten Tabelle, sodass die Abdeckung 1:1 mit der
Spezifikation bleibt und die Denylist im Diff überprüfbar ist. MCP-Annotationen (readOnlyHint,
destructiveHint) sind ebenfalls gesetzt, sodass Clients, die sie anzeigen, warnen können.
Welche Tools fehlen mir?
Ein abgeschaltetes Tool ist schlicht nicht vorhanden, was sich als „VRChat kann das nicht“ liest statt als „diesem Server wurde untersagt, das zu tun“. Dieser Fehler ist in der Praxis bereits passiert: Ein Agent meldete die Economy-API als schreibgeschützt, obwohl die Schreib-Tools existierten und nur hinter einem Flag lagen.
vrchat_authStatus schließt diese Lücke. Es meldet jedes Tag und jede Sicherheitsklasse, wie viele Operationen jeweils dazugehören, wie viele aktuell verfügbar sind und die genaue .env-Änderung, die den Rest freischalten würde.
{
"availability": {
"toolsRegistered": 12,
"toolsHidden": 285,
"tagFilter": ["store"],
"kinds": { "write": { "enabled": false, "hidden": 88 } },
"nextSteps": [
"88 `write` operations are hidden. Ask the user to set VRCHAT_MCP_ALLOW_WRITES=1 ..."
]
}
}Rufen Sie es auf, bevor Sie etwas als nicht unterstützt einstufen.
Welche Tools freigeschaltet werden
VRCHAT_MCP_TAGS wählt Tags aus. Ist die Variable nicht gesetzt, wird alles registriert, und everything sagt das explizit, was einfacher ist, als einen Schlüssel aus einer JSON-Konfiguration zu löschen. all und * funktionieren ebenfalls.
VRCHAT_MCP_TAGS=everything # all 297 operations
VRCHAT_MCP_TAGS=store # just the storefront, 19 operations
VRCHAT_MCP_TAGS=store,users,worlds # matches any of the threeSpec-Tags: authentication, avatars, calendar, economy, favorites, files, friends, groups, instances, inventory, invite, jams, miscellaneous, notifications, playermoderation, prints, props, users, worlds. Dazu kommt store, das dieser Server hinzufügt.
Ein Tag, das auf nichts passt, wird beim Start über stderr gemeldet und von vrchat_authStatus angezeigt. Ohne das würde ein Tippfehler wie stores keine generierten Tools registrieren und genau wie ein defekter Server aussehen.
Anmelden
Die Anmeldung erfolgt erst bei Bedarf. Beim Start wird nichts authentifiziert, daher funktioniert tools/list auch ganz ohne Anmeldedaten, und der Server bleibt inspizierbar. Der erste Tool-Aufruf, der eine Sitzung benötigt, löst die Anmeldung aus.
Wenn VRCHAT_TOTP_SECRET gesetzt ist, ist das die ganze Geschichte. Keinerlei Aufforderungen.
Ohne das schickt VRChat einen Code per E-Mail, und der Aufruf kommt geparkt zurück, statt zu hängen:
vrchat__getCurrentUser
-> Login paused: VRChat emailed a code. Ask the user for it, call
vrchat_submitTwoFactorCode { requestId: 'a1b2c3d4', code: '……' },
then retry the original call.Beantworten Sie es mit vrchat_submitTwoFactorCode und versuchen Sie es dann erneut. Die Sitzung bleibt erhalten, sodass dies einmal pro Projekt passiert, bis sie abläuft.
Anmeldung aus einem neuen Netzwerk
Der Wechsel von Proxy, VPN oder ISP löst eine Prüfung aus, die kein Zwei-Faktor-Code ist, und beides sieht einander ähnlich genug, um echte Zeit zu verschwenden. VRChat antwortet mit einem der folgenden:
401 It looks like you're logging in from somewhere new! Check your email for a message from VRChat.
429 Logging in from too many places? Check your email for verification linkBeide bedeuten dasselbe, und keins ist das, was es zu sein scheint. Die E-Mail enthält einen Link, keinen sechsstelligen Code, daher kann vrchat_submitTwoFactorCode nicht helfen. Die Anmeldung erfordert zwei Runden:
Ein Tool-Aufruf schlägt mit einer dieser Meldungen fehl.
Der Benutzer öffnet den Link in der E-Mail.
Rufen Sie
vrchat_retryLoginauf. VRChat sendet den eigentlichen Code erst beim zweiten Versuch.Der Benutzer liest den Code vor; rufen Sie
vrchat_submitTwoFactorCodeauf.Wiederholen Sie das ursprüngliche Tool.
Die 429 ist eine Auth-Herausforderung, die den Status einer Rate-Limit-Meldung trägt, deshalb ignoriert sie der lokale Begrenzer. Warten behebt sie nicht, und jeder weitere Versuch kostet einen der begrenzten Sitzungsplätze des Kontos, was die 429 überhaupt erst verursacht. Eine fehlgeschlagene Anmeldung wird 30 Sekunden lang zwischengespeichert, damit aus einem Schub von Tool-Aufrufen kein Schub von Anmeldeversuchen wird. vrchat_retryLogin leert diesen Cache, weil der Benutzer bis dahin das getan hat, worauf der Fehler gewartet hat.
Parallele Aufrufe während der Anmeldung
Agents stoßen Tool-Aufrufe gleichzeitig an, und bei einem Kaltstart landen sie alle auf einem nicht authentifizierten Client. Ein Aufruf steuert die Anmeldung. Die anderen warten bis zu drei Sekunden und geben dann login_pending zurück, statt zu blockieren. So hält eine langsame Anmeldung einen Tool-Aufruf auf statt alle, und eine Anmeldung, die auf einen Code wartet, erzeugt eine Aufforderung statt mehrerer.
_responseKeys
Jedes Tool akzeptiert _responseKeys, und jedes Tool gibt standardmäßig die rohe Upstream-Payload zurück. Es gibt keine serverseitige Kuratierung, denn eine handverlesene Feldliste rät, was wichtig ist, ist für den falsch, der das andere Feld braucht, und müsste für 297 Operationen gegen eine sich bewegende Spezifikation gepflegt werden. Der Agent weiß, was er bei diesem Aufruf will. Er sollte es sagen.
Ein World-Objekt ist ungefähr 4 KB groß. Eine Einschränkung reduziert das meist um mehr als die Hälfte.
Muster | Wählt aus |
| die gesamte Antwort, Byte für Byte |
| diese Top-Level-Felder |
| einen verschachtelten Pfad |
|
|
| dieses Feld aus jedem Element von |
| alles unterhalb jedes Elements |
| schließt aus und kombiniert mit |
Die Projektion behält die Form. Objekte bleiben verschachtelt, Arrays behalten ihre Reihenfolge und Länge, sodass ein Pfad, der in einem Aufruf gelernt wurde, auch im nächsten funktioniert.
Das Entdecken ist wichtiger als die Projektion. Ein Agent kann nicht nach Schlüsseln fragen, von denen er nicht weiß, dass es sie gibt, und ein stilles, leeres Ergebnis würde dieses Design schlechter machen als das Beschneiden. Daher wird ein Pfad, der auf nichts passt, als _unmatched zurückgegeben, zusammen mit _availableKeys, das auflistet, was tatsächlich vorhanden war. Array-Element-Schlüssel werden als *.id, *.name benannt, also in der Form, die als _responseKeys-Eintrag funktioniert.
["*"] gibt die Eingabe per Referenz zurück, sodass der rohe Pfad nachweislich verlustfrei ist und nichts jemals verborgen bleibt.
Bilder anzeigen
vrchat_getImage lädt ein VRChat-Bild herunter und gibt es als Bildblock zurück, sodass das Modell es ansehen kann, statt nur eine URL zu melden.
{ "name": "vrchat_getImage",
"arguments": { "url": "https://api.vrchat.cloud/api/1/file/file_.../1/256" } }Übergeben Sie eine beliebige imageUrl oder thumbnailImageUrl von einem Benutzer, einer Welt, einem Avatar, einem Print oder einem Produkt, oder übergeben Sie fileId und lassen Sie das Tool die URL erstellen. savePath schreibt die Bytes zusätzlich auf die Festplatte.
Bevorzugen Sie eine URL, die auf /256 oder /512 endet, sofern eine solche existiert. Das Bild wird als Base64 übertragen, daher kostet eine Textur in voller Größe viel Kontext und bringt kein zusätzliches Detail. Alles über 4 MB wird abgelehnt; erhöhen Sie maxBytes, wenn Sie es ernst meinen.
Das Tool ruft nur bei VRChat gehostete Bilder ab, und nur an api.vrchat.cloud wird jemals Ihr Sitzungscookie gesendet. Ein Tool, das eine vom Aufrufer gelieferte URL abruft, während es eine Sitzung hält, ist ein Grundbaustein für Request Forgery, sofern es nicht eingeschränkt ist, und ein Cookie, das an ein CDN gesendet wird, ist ein verschenktes Cookie.
Dateien hochladen
Übergeben Sie einen lokalen Dateipfad. Der Server läuft auf Ihrem Rechner und liest die Datei selbst, daher gelangen die Dateiinhalte nie in die Unterhaltung. Ein 2-MB-PNG als Base64 inline einzubetten würde ungefähr 2,7 MB an Tool-Argumenten kosten, mehr als alles andere im Aufruf zusammen.
Wenn keine Datei auf der Festplatte liegt, etwa ein Bild, das der Agent gerade erzeugt hat, akzeptiert dasselbe Argument die Bytes inline:
{ "file": { "data": "iVBORw0KGgo...", "mimeType": "image/png", "filename": "icon.png" } }Auch an der String-Position funktioniert eine data:-URI, daher ist "file": "data:image/png;base64,iVBORw0..." gleichwertig. filename ist optional und wird bei Weglassen aus dem MIME-Typ abgeleitet, weil VRChat einen Upload ablehnt, den es nicht benennen kann. Bevorzugen Sie einen Pfad, wann immer einer existiert: Inline kostet etwa 1,33 Bytes Tool-Argument pro Byte Datei, und das stammt aus demselben Kontextbudget wie alles andere.
Acht Operationen nehmen eine Datei direkt entgegen, jeweils ein Aufruf:
Tool | Feld | Verwendung |
|
| Icons, Galerie, Emoji, Sticker, Produktbilder ( |
|
| Prints |
|
| Profilbilder |
|
| Galerie |
|
| Ersetzen des Bilds eines Prints |
|
| Einladungsfotos |
|
| Einladungsanfragen |
|
| Einladungsantworten |
{ "name": "vrchat__uploadImage",
"arguments": { "file": "C:/Users/me/Pictures/icon.png", "tag": "icon" } }Das Ergebnis benennt die gesendeten Bytes und die Form, in der sie angekommen sind. Das ist die einzige Möglichkeit, einen erfolgreichen Upload der richtigen Datei von einem erfolgreichen Upload der falschen zu unterscheiden:
{ "uploaded": [
{ "field": "file", "name": "icon.png", "bytes": 48211, "type": "image/png", "source": "path" }
],
"result": { "id": "file_...", "name": "icon.png" } }Für alles andere führt vrchat_uploadFile VRChats Vier-Schritte-Sequenz aus (Datensatz anlegen, eine vorab signierte URL anfordern, die Bytes übertragen, abschließen) und gibt den vollständigen Dateidatensatz zurück. Verwenden Sie es für Asset-Bundles und unity packages. Die Bytes gehen mit einer einfachen Anfrage direkt an VRChats Speicheranbieter, bewusst nicht über den API-Client, weil dieser Client Ihr Sitzungscookie an alles anhängt, was er sendet, und der Speicherhost ein Dritter ist.
Uploads sind Schreibvorgänge, daher benötigt das alles VRCHAT_MCP_ALLOW_WRITES=1. Dateien sind auf 100 MB begrenzt, und eine leere Datei wird abgelehnt, bevor sie VRChat erreicht, das andernfalls einen defekten Datensatz speichern würde. Wenn vrchat_uploadFile auf halbem Weg scheitert, nennt es den Dateidatensatz, den es angelegt hat, sodass Sie ihn mit vrchat__getFile untersuchen und mit vrchat__deleteFile entfernen können.
Einen Shop betreiben
Die Verwaltung einer Storefront ist ein gewöhnlicher Schreibvorgang, keine money-Operation. Ein Produkt zu erstellen, umzubenennen, sein Bild zu ändern, ein Angebot zu veröffentlichen oder zurückzuziehen: Nichts davon gibt Geld aus oder nimmt Geld ein, daher ist nur VRCHAT_MCP_ALLOW_WRITES=1 nötig. Das money-Gate ist für Käufe und den Zahlungsabwickler.
VRCHAT_MCP_TAGS=store
VRCHAT_MCP_ALLOW_WRITES=1Das Setzen eines Produktbilds erfordert einen Aufruf:
{ "name": "vrchat_setProductImage",
"arguments": { "productId": "prod_...", "file": "/abs/path/cover.png" } }Das lädt mit tag: "product" hoch und setzt die zurückgegebene Datei-ID als imageId des Produkts. Von Hand sind das vrchat__uploadImage mit tag: "product" oder "listinggallery" und danach vrchat__updateProduct mit der zurückgegebenen ID.
Eines erlaubt VRChat selbst nicht: Ein Angebot legt nur active zum Bearbeiten offen, daher können Preis, Titel und Beschreibung nach der Erstellung nicht geändert werden. Löschen Sie das Angebot und erstellen Sie ein neues. Name, Beschreibung und Bild liegen am Produkt und sind über vrchat__updateProduct bearbeitbar.
Paginierung
Eine Seite pro Aufruf. Paginierte Tools verwenden standardmäßig 25 Ergebnisse und geben ein nextOffset zum Fortsetzen zurück. Es gibt bewusst keine interne Paginierungsschleife: Ein verstecktes automatisches Weiterblättern würde das Anfragebudget und einen großen Teil des Kontexts verbrauchen, und zwar innerhalb eines Aufrufs, der für den Agenten wie ein einzelner aussieht.
Eine kurze Seite bedeutet das Ende. VRChat meldet keine Gesamtzahl, daher ist das das einzige zuverlässige Signal.
WebSocket-Ereignisse
Standardmäßig deaktiviert, weil ein im Leerlauf dauerhaft geöffneter Socket einen Sitzungsplatz verbraucht. Setzen Sie VRCHAT_MCP_WEBSOCKET=1, um ihn zu öffnen und die vier vrchat_events*-Tools zu registrieren.
VRCHAT_MCP_WS_EVENTS wählt aus, welche Typen abonniert werden, und ersetzt statt zu erweitern die Standardmenge aus notification, notification-v2, economy-update, friend-online, friend-offline und instance-queue-ready.
Pipeline-Nachrichten sind doppelt kodiert: Das Feld content ist stringifiziertes JSON und muss ein zweites Mal geparst werden, außer bei see-notification und hide-notification, die nackte IDs tragen. All das wird beim Empfang einmal normalisiert, sodass kein Tool Ihnen jemals einen JSON-String innerhalb von JSON übergibt. Der eigene Socket des SDK verwirft diese beiden Nachrichtentypen stillschweigend, was ein Grund dafür ist, dass dieser Server es nicht verwendet. Der andere Grund ist, dass es keinen Proxy akzeptiert.
Aufbewahrung pro Typ
Der Verlauf wird in SQLite unter .vrchat-mcp/events.db abgelegt, und es werden 1000 Ereignisse pro Ereignis Typ aufbewahrt, nicht 1000 insgesamt. Ein gesprächiger Typ wie friend-location kann einen seltenen, wertvollen Typ wie economy-update nie verdrängen, was eine einzige globale Obergrenze innerhalb von Minuten tun würde.
VRCHAT_MCP_HISTORY=1000,friend-location:200,economy-update:5000
VRCHAT_MCP_HISTORY_MAX_AGE=7dEine Altersobergrenze läuft parallel zum Mengenlimit, und was zuerst greift, gewinnt. Nur die Menge würde einen selten ausgelösten Typ monatelang alte Ereignisse behalten lassen, die wie aktuell wirken. Nur das Alter würde einen Schwall die Datenbank sprengen lassen. vrchat_eventsStatus meldet, welches Limit pro Typ gerade greift, sodass das Zeitfenster nachvollziehbar ist, statt unbemerkt zu bleiben.
Der Verlauf überlebt Neustarts, daher kann vrchat_eventsSearch beantworten, was passiert ist, während Sie nicht da waren. Ein reiner Live-Puffer kann das nicht.
Proxy
VRCHAT_MCP_PROXY leitet den Datenverkehr über einen HTTP- oder HTTPS-Proxy, mit optionalen user:pass@-Zugangsdaten.
VRCHAT_MCP_PROXY=http://127.0.0.1:8080
VRCHAT_MCP_PROXY=https://user:pass@proxy.internal:8443SOCKS wird nicht unterstützt. Buns fetch lehnt socks5:// rundweg ab, sodass eine SOCKS-URL beim Start mit einem Konfigurationsfehler fehlschlägt, der die Einschränkung benennt, anstatt nur halb zu funktionieren. Stellen Sie stattdessen einen lokalen HTTP-Proxy davor.
Der Proxy deckt sowohl API- als auch WebSocket-Datenverkehr ab. Die beiden laufen über unterschiedliche Mechanismen, und der Fehlerfall, nur die Hälfte richtig zu machen, ist ein Server, der wie ein Proxy aussieht, während er seine echte IP im Event-Stream preisgibt.
Wenn der Proxy nicht erreichbar ist, schlagen Aufrufe mit einem klaren Fehler fehl. Der Server fällt niemals stillschweigend auf eine direkte Verbindung zurück, denn für jeden, der dies zur IP-Trennung nutzt, wäre das das schlechtestmögliche Ergebnis. Die Proxy-URL wird nie protokolliert, da sie Anmeldedaten enthalten kann.
Entwicklung
bun link # install the vrchat-mcp command on PATH
bun unlink # remove it
bun run generate # regenerate tools from the latest upstream spec
bun run generate --offline # regenerate from the committed snapshot, no network
bun test # offline suite
bun run test:live # live suite, needs VRCHAT_LIVE_TESTS=1
bun run inspect # MCP Inspector against this server
bun run typecheck # tsc --noEmitbun run generate ruft vrchatapi/specification auf main ab, bündelt es und schreibt die gebündelte Spezifikation plus spec/VERSION.json (Upstream-SHA, Zeitstempel, Inhalts-Hash) zusammen mit der neu generierten src/generated/operations.ts. Beide werden committet, sodass jede Regenerierung zwei überprüfbare Diffs erzeugt, die Spezifikationsänderung und die dadurch verursachte Tool-Änderung, und ein schlechter Upstream-Commit ist revertierbar statt tragend. --offline reproduziert die Ausgabe aus dem committeten Snapshot Byte für Byte ohne jegliches Netzwerk.
src/generated/operations.ts wird generiert. Nicht von Hand bearbeiten.
Zehn operationIds haben keine passende Methode im VRChat SDK, weil die Spezifikation schneller voranschreitet als die Client-Bibliothek. Diese laufen über einen Raw-Request-Fallback auf demselben Client, sodass Cookies, User-Agent, Proxy und Ratenbegrenzung weiterhin gelten, und die 1:1-Abdeckung bleibt wahr, anstatt stillschweigend zur Lüge zu werden. Codegen gibt die Liste bei jedem Lauf aus.
stdout ist der JSON-RPC-Kanal. Die gesamte Protokollierung erfolgt über stderr, und ein einzelnes console.log beschädigt den Protokollstrom.
Tests
bun test ist die Offline-Suite: Codegen-Ausgabe, Gating, der Ratenbegrenzer gegen eine simulierte Uhr, Aufbewahrung und Suche des Verlaufs, Projektion, Fehlerzuordnung, Behandlung von Upload-Pfaden. Kein Netzwerk, keine Anmeldedaten, kein Konto. Das wird standardmäßig ausgeführt.
bun run test:live greift auf ein echtes Konto zu, das mit VRCHAT_LIVE_TESTS=1 aktiviert wird und andernfalls übersprungen wird. Regeln, an die es sich hält:
Nur Lese- und Ersteller-eigene Schreibvorgänge. Es lehnt alles, was als
moneyoderadminklassifiziert ist, hart ab, bevor überhaupt ein Client konstruiert wird. Eine Testsuite darf kein Geld ausgeben können.Jeder Schreibvorgang räumt nach sich selbst auf und ist markiert, sodass verirrte Artefakte im Spiel identifizierbar sind.
Es läuft durch denselben Begrenzer wie die Produktion und bleibt klein. Ein Lauf, der VRChats Drosselung auslöst, ist schlimmer als kein Lauf.
Assertions betreffen Form und Status, niemals volatile Inhalte. Freundeszahlen und Weltlisten ändern sich zwischen Läufen.
Verwenden Sie, wo möglich, ein dediziertes Konto. Anmeldedaten stammen nur aus
.env.
Sicherheit
.envund.vrchat-mcp/sind gitignored, und.vrchat-mcp/ignoriert sich auch selbst von innen, sodass es in anderen Projekten verborgen bleibt..vrchat-mcp/session.jsonist eine Anmeldeinformation, ein gültiges Session-Cookie. Behandeln Sie es wie ein Passwort. Das Löschen oder der Aufruf vonvrchat_logouterzwingt eine neue Anmeldung.2FA-Codes, Passwörter, TOTP-Geheimnisse und Proxy-URLs werden nie protokolliert, auch nicht auf stderr.
Ihr Session-Cookie geht an
api.vrchat.cloudund sonst nirgendwohin. Uploads an VRChats Speicheranbieter und Bildabrufe von dessen CDN umgehen bewusst den authentifizierten Client.Fehler kommen als strukturierte Ergebnisse zurück, die Status, VRChats eigene Meldung und einen umsetzbaren Hinweis enthalten. Rohe Ausnahmen und Stack-Traces erreichen nie das Transkript.
Nur stdio, nur lokal. Kein HTTP-Transport, keine Isolierung von Anmeldedaten für mehrere Benutzer. Dieser Server ist für ein Konto auf einer Maschine.
Projektlayout
scripts/generate-tools.ts # build-time codegen: spec -> src/generated/operations.ts
spec/openapi.bundled.json # committed snapshot of the upstream spec
spec/VERSION.json # upstream SHA + fetch timestamp + content hash
src/config.ts # the entire env surface, read once
src/types.ts # shared contracts
src/generated/operations.ts # committed, generated, 297 entries, do not edit
src/vrchat/client.ts # lazily-authed VRChat client, proxy, 2FA sniffing
src/vrchat/twofactor.ts # pending-code broker
src/vrchat/ratelimit.ts # token bucket + global 429 backoff
src/vrchat/events.ts # websocket client + waiter registry
src/vrchat/history.ts # bun:sqlite event store, per-type retention + FTS5 search
src/tools/auth.ts # authStatus / submitTwoFactorCode / retryLogin / logout
src/tools/images.ts # getImage
src/tools/upload.ts # uploadFile / setProductImage
src/tools/events.ts # eventsRecent / eventsWait / eventsSearch / eventsStatus
src/registry.ts # gating, registration, the one shared handler
src/project.ts # _responseKeys path projection
src/upload.ts # local path -> File, with size and type guards
src/errors.ts # HTTP status -> structured tool error with hint
src/index.ts # serveStdio entry point
tests/ # offline suite; tests/live/ is the opt-in live suite
docs/PLAN.md # design document
PROGRESS.md # build status and verified SDK behaviourLizenz
Siehe LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables remote control of Lovense toys through Claude using natural language commands. Supports vibration patterns, presets, and intensity control from any device via Cloudflare Workers.4Apache 2.0
- AlicenseNot gradedqualityNot gradedmaintenanceEnables Claude to design and build interactive 3D games within the Portals virtual platform through direct API integration. It facilitates automated asset placement, interaction logic configuration, and quest management using natural language commands.4
- AlicenseAqualityDmaintenanceConnects Claude to Open WebUI, enabling chat management, RAG knowledge bases, files, functions, and prompts directly from Claude.26252MIT
- AlicenseNot gradedqualityAmaintenanceBridges any OpenAPI 3.x REST API to Claude Code by automatically generating one tool per endpoint from your spec, with full argument validation and auth support.18MIT
Related MCP Connectors
WHOOP recovery, strain, sleep and workouts in Claude via official WHOOP OAuth. Free, open source.
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/TheArmagan/vrchat-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server