CurseForge ARK MCP Server
curseforge-ark-mcp
Ein schreibgeschützter MCP-Server für die Kuration, Entdeckung und Update-Überwachung von CurseForge-Mods für ARK: Survival Ascended.
DIES IST v0. NICHTS HIER WURDE EINER LIVE-ANTWORT GEGENÜBER ÜBERPRÜFT.
Es existiert noch kein CurseForge-API-Key. Der Schlüssel ist kein Self-Service – er wird auf Antrag von Overwolf gewährt – daher wurde von diesem Repository, von niemandem, zu keinem Zeitpunkt ein authentifizierter Aufruf durchgeführt. Jeder Feldpfad in jedem Fixture und jeder Tool-Ausgabe ist eine Hypothese, die aus einem veröffentlichten Schema abgelesen wurde.
Das ist keine Bescheidenheit. Das Schwester-Repository
nitrado-ark-mcphat seine Fixtures auf die gleiche sorgfältige Weise aus der Dokumentation erstellt, und Commit5481c04dort korrigierte drei Feldpfade, die bis zur Überprüfung gegen Live-Antworten falsch waren. Gehen Sie davon aus, dass dieses Repository drei eigene Fehler hat, die noch darauf warten, entdeckt zu werden.Die Versionsnummer ist
0.1.0und sie ist eine Aussage über den Überprüfungsstatus. Es gibt keinen Abschnitt „Gegen das Live-Konto verifiziert“ in dieser README, und sein Fehlen ist zutreffend und keine Auslassung.
Was heute verifiziert ist, ist das eigene Verhalten dieses Repositorys: die Endpunkt-Zulassungsliste, der Host-Pin, die Pfadnormalisierung, die Paginierungsgrenzen, die Bearbeitung des Envelopes und die Disziplin des Drei-Zustands (fehlend/leer/unbekannt). Alles wird gegen einen injizierten gefälschten fetch getestet, ohne Schlüssel und ohne Netzwerk. 146 Tests, 0 Fehlschläge zum Zeitpunkt des Schreibens.
Design-Dokumentation: docs/adr/ADR-002-endpoint-allow-list.md (Status: PROPOSED). Jeder Abschnittsverweis unten (§1, §4.3, §14.3 …) verweist darauf.
Was es tut und was es bewusst nicht tun kann
Sieben Tools, alle schreibgeschützt:
Tool | Antworten |
| „Welche ASA-Mods passen zu diesem Begriff?“ |
| „Was ist Projekt 777001?“ |
| „Welche Dateien hat dieser Mod veröffentlicht?“ |
| „Was ist diese spezifische Datei?“ |
| „Gibt es eine neuere Datei für diesen Mod als die, die ich ausführe?“ |
| „Was zieht dieser Mod mit ein?“ (gebündelt, eine Anfrage pro Baumebene) |
| „Liegt es an mir, am Schlüssel oder an CurseForge?“ — und „wie ehrlich ist dieser Build?“ |
Es kann nicht:
Irgendetwas herunterladen oder installieren.
GET /v1/mods/{modId}/files/{fileId}/download-urlist ein dokumentierter Lesevorgang, auf dem gepinnten Host, und es wird zurückgewiesen – weil es nicht auf der Endpunkt-Zulassungsliste steht (DEC-002 §11.3). Nitrado installiert Mods selbst.Irgendetwas, irgendwo schreiben. Kein Eintrag der Zulassungsliste benennt einen mutierenden Endpunkt. CurseForge betreibt eine mutierende Upload-API auf einem anderen Host (§14.2); der Host-Pin weist sie aus einem zweiten, unabhängigen Grund zurück.
Einen Mod veröffentlichen oder erstellen. Wird vollständig zurückgewiesen (DEC-002 Entscheidung 2). Durchgesetzt durch eine Start-Behauptung, nicht durch ein Versprechen: Die Registrierung eines Tools, das etwas anderes als Tier 1 deklariert, führt dazu, dass der Prozess sich weigert zu starten.
Nitrado berühren. Es existiert keine
NITRADO_*Variable in der Konfigurationsoberfläche dieses Repositorys, und ihr Fehlen ist eine Kontrolle. Dieser Server hält kein Nitrado-Token und liest keine Nitrado-Konfiguration.Durch einen Timer aufwachen und Ihren Server aktualisieren. Kein Scheduler, keine Polling-Schleife, kein persistierter „zuletzt gesehener“ Versionstatus (§10). Überwachung bedeutet, dass das Modell eine neue Version beobachten kann. Es darf nicht handeln.
Der Engpass: eine Endpunkt-Zulassungsliste, keine Methodenprüfung
Dies ist die eine Designentscheidung, die es wert ist, gelesen zu werden, bevor man den Code anfasst.
CurseForge verwendet POST zum LESEN. POST /v1/mods und POST /v1/mods/files sind Massenabrufe, und sie sind der Grund, warum resolve_mod_dependencies eine Anfrage pro Abhängigkeits-Ebene kostet, anstatt eine pro Knoten. Also würde die Regel des Schwester-Repositorys method !== "GET" → verweigern hier auf die teuerste Art und Weise versagen: Es würde funktionieren. Es würde Dinge ablehnen, seine eigenen Tests bestehen und den Server leise schlecht in seiner Aufgabe machen.
Und die offensichtliche Korrektur ist schlimmer als der Fehler:
allowed = { GET } → the batch reads are refused (broken, loudly)
allowed = { GET, POST } → every request this client can construct is allowedDie dokumentierte Katalog-API enthält nur GET und POST. Eine Pforte, die beide akzeptiert, akzeptiert alles – während sie weiterhin präsentabel aussieht.
Stattdessen muss jede ausgehende Anfrage mit einem expliziten Eintrag in einer geschlossenen Liste von {method, path}-Paaren übereinstimmen. Sieben Einträge, in src/allowlist.ts:
# | Methode | Pfad | Dient |
E1 |
|
| Spiel-ID-Auflösung, |
E2 |
|
|
|
E3 |
|
|
|
E4 |
|
|
|
E5 |
|
|
|
E6 |
|
|
|
E7 |
|
|
|
Mechanisch:
Abgeglichen auf
{method, path}gemeinsam. E3 autorisiert nichtDELETE /v1/mods/123. E6 autorisiert nichtPOST /v1/mods/123.Der Host ist gepinnt auf
https://api.curseforge.com, und der Pin ist eine Zulassung einer einzelnen Herkunft und keine Ablehnung einer anderen benannten Herkunft.ID-Segmente binden an
[0-9]+, nicht an[^/]+. Dies ist von Bedeutung: ein permissives{modId}lässt E3/v1/mods/searchverschlucken. Die numerische Bindung macht diese Mehrdeutigkeit strukturell unmöglich anstatt abhängig von der Übereinstimmungsreihenfolge – und es gibt einen Test, der die gesamte Liste umkehrt, um zu beweisen, dass die Reihenfolge nicht das ist, was sie rettet.Eine Normalisierung, vor der Prüfung, und die URL wird aus ihrer Ausgabe erstellt. Prozentdekodieren Sie einmal; weisen Sie jedes verbleibende
%zurück; falten Sie Backslashes; weisen Sie.,..und leere Segmente zurück.Nur E6/E7 dürfen einen Body tragen, dessen Form vor dem Versand überprüft wird. Ein Body bei einem GET-Eintrag wird zurückgewiesen, nicht verworfen.
Nur
resolve_mod_dependenciesdarf einen POST-Eintrag erreichen (§8), durchgesetzt im Transport.
Der Fehlermodus ist „nicht übereinstimmende Anfrage wird zurückgewiesen“, niemals „unerkannte Anfrage gesendet.“ Und das Hinzufügen einer Fähigkeit ist eine überprüfbare Einzeiler-Änderung, deren Überprüfungsfrage – „Ist dieser Endpunkt ein Lesevorgang?“ – eine ist, die ein Mensch tatsächlich beantworten kann.
Der Test, der beweist, dass es eine Zulassungsliste ist
GET /v1/mods/{modId}/files/{fileId}/download-url wird zurückgewiesen. Es ist ein dokumentierter Lesevorgang, ein GET, auf dem gepinnten Host, mit wohlgeformten numerischen IDs. Es wird ausschließlich zurückgewiesen, weil es nicht auf der Liste steht. Wenn dieser Test jemals aus einem anderen Grund besteht – einer Host-Pin-Zurückweisung, einer Pfad-Zurückweisung – ist die Eigenschaft nicht implementiert, daher prüft der Test den Code und das Detail der Zurückweisung, nicht nur, dass etwas geworfen wurde.
Jeder Zurückweisungstest prüft auch den Aufrufzähler des gefälschten fetch, weil „vor dem Aufbau der Anfrage zurückgewiesen“ die tatsächliche Bestimmung ist, und ein Fehler, der nach dem Versand geworfen wird, eine schwächere Behauptung erfüllen würde. Und der Zurückweisungssuite ist ein Urbild-Test vorangestellt, der beweist, dass alle sieben Einträge versandt werden – eine Zurückweisungssuite über einem Client, der nichts senden kann, besteht perfekt und beweist nichts.
Noch nicht verifiziert
Jede Zeile unten ist eine HYPOTHESE. Dies sind §14.3 von ADR-002, vollständig wiedergegeben. Feldpfade werden aus veröffentlichten Schemata abgelesen, was genau die Artefaktklasse ist, die drei falsche Pfade im Schwester-Repository erzeugt hat.
# | Anspruch | Grundlage | Warum es wichtig ist |
U1 | Der ASA | Ohne den Schlüssel nicht auffindbar (§5) | Ein falscher Wert liefert saubere, leere, falsche Suchergebnisse |
U2 | Ob ASA für den gewährten Schlüssel überhaupt sichtbar ist | Ohne den Schlüssel nicht auffindbar | Könnte v1 vollständig blockieren |
U3 |
| Veröffentlichtes Schema | Jede Tool-Ausgabe |
U4 |
| Veröffentlichtes Schema |
|
U5 |
| Veröffentlichtes Schema |
|
U6 | Die numerische Enum-Zuordnung von | NICHT GEKLÄRT. Drei Versuche anhand der Dokumentation; die Seite zeigt | Bestimmt, ob eine Kante erforderlich, optional, ein Werkzeug oder inkompatibel ist – d.h. ob sie überhaupt verfolgt wird. |
U7 | Das numerische Enum | Nicht aus der Dokumentationsseite geklärt. Nur teilweise Bestätigung: Die Upload-API verwendet die Namen |
|
U8 | Ob | Dokumentierte Form; nie beobachtet | Dieser Client gibt einen Fehler aus, anstatt eine Seite anzunehmen |
U9 | Ob ASA-Mods tatsächlich | Schema sagt, dass sie können; ASA-spezifisches Verhalten unbekannt | Ein immer leeres Feld ist eine Fähigkeitslücke, kein Fehler – und die Drei-Zustands-Regel erfordert, sie zu unterscheiden |
U10 | Jede ID-Anzahl-Obergrenze für | Nicht dokumentiert. Die 200-ID-Obergrenze in diesem Client ist unsere, nicht die des Anbieters | Chunking-Strategie |
U11 | CurseForge-Ratenbegrenzungen | Undokumentiert. Kein veröffentlichter Wert gefunden |
|
U12 | Tatsächliches Paginierungsverhalten jenseits von | Nur dokumentierte Einschränkung | Die Offenlegung der Kürzung in §4.3 |
U13 | Basis-URL | Aus der Dokumentation abgeleitet | Der Host-Pin hängt davon ab |
Zwei Konsequenzen, die Sie in der Tool-Ausgabe sehen werden
relationType und releaseType werden als rohe Ganzzahlen ausgegeben und niemals zugeordnet. Nicht zu
required/optional, nicht zu release/beta/alpha. CurseForge veröffentlicht für keine von beiden eine Wertetabelle,
und eine falsche Bezeichnung würde eine Abhängigkeitsliste – oder eine Update-Empfehlung – erzeugen, die
in einer Weise falsch ist, die niemand überprüfen würde. resolve_mod_dependencies folgt daher jeder Kante
und sagt dies: es sammelt übermäßig, und seine Ausgabe stellt dies klar dar. Ein weites Netz ist zumindest
sichtbar weit.
get_latest_file erfordert, dass Sie sagen, was „neueste“ bedeutet. Die neueste nach fileDate, die neueste,
die einer Spielversion entspricht, und die neueste mit einem bestimmten releaseType liefern unterschiedliche Antworten, und
eine Mod-Update-Entscheidung, die auf der falschen basiert, ist genau die Klasse von selbstbewusst-falschen Antworten, gegen die dieses Repository
eingerichtet ist. selection hat keinen Standardwert:
| Erfordert auch | Bedeutung |
| — | Neueste aller Kandidatendateien, nach |
|
| Neueste Datei, die diese Spielversion deklariert |
|
| Neueste Datei mit diesem Release-Typ-Ganzzahl |
Es gibt keinen benannten release/beta/alpha-Filter, da U7 ungeklärt ist und dieser Server
keine Zuordnung erfinden wird. Sie übergeben die Ganzzahl, die Sie meinen.
Diese Definition ist eine OFFENE PRODUKTFRAGE. ADR-002s offene Frage 2 kennzeichnet sie als eine Gründerentscheidung, die noch nicht getroffen war, als dies gebaut wurde, sodass das Werkzeug parametrisiert und nicht meinungsstark ist: Wenn die Antwort eintrifft, wird sie zu einem Standardwert oder einer Variante weniger – eine kleine Änderung statt einer Neuschreibung. Jede Antwort wiederholt die verwendete Sortierung, wonach gefiltert wurde, wie viele Kandidaten berücksichtigt wurden und woher die Kandidaten stammen.
Einrichtung
Node 20+ (entwickelt auf 22). Kein Build-Schritt zu konfigurieren; npm test baut zuerst.
npm install
npm test # builds, then runs the suite — no key, no network
npm run typecheck
npm run smoke # refuses cleanly until a key exists, naming what it would probeSobald Sie einen Schlüssel haben:
cp .env.example .env
# set CURSEFORGE_API_KEY, then:
npm run smokeMCP-Client-Konfiguration (stdio):
{
"mcpServers": {
"curseforge-ark": {
"command": "node",
"args": ["C:/path/to/curseforge-ark-mcp/dist/src/server.js"],
"env": { "CURSEFORGE_API_KEY": "your-key" }
}
}
}Der Server weigert sich, ohne einen Schlüssel zu starten, und nennt beide Orte, die er durchsucht hat, die genaue Variable und die Tatsache, dass der Schlüssel nicht selbstbedient ist. Ein stdio-MCP-Server, der sauber startet und dann bei allen sieben Werkzeugen einen Fehler wirft, ist eine elende Sache zum Debuggen.
Über den Schlüssel
Der API-Schlüssel wird als x-api-key-Anforderungsheader gesendet. Es ist kein
Authorization: Bearer-Token – das ist das Schema des Schwester-Repositories Nitrado, und dieses Repository
unterstützt bewusst nicht beide, da die Unterstützung beider bedeuten würde, dass dieser Code die Anmeldeinformationen
in einer Form übertragen könnte, die CurseForge nie dokumentiert hat.
Der Schlüssel wird durch Antrag an Overwolf gewährt und ist nicht übertragbar. Die praktische
Konsequenz und der einzige Grund, warum dieser Absatz existiert: Ein Leck bedeutet Widerruf und erneuten Antrag, und
der erneute Antrag ist eine Warteschlange, kein Selbstbedienungs-Reset. Sie können ihn nicht bei einer Tasse Kaffee neu generieren
und Sie können sich nicht den eines anderen ausleihen. Behandeln Sie ihn entsprechend – .env ist in gitignoriert, .env.example
trägt den Variablennamen und einen leeren Wert, und kein Schlüsselwert erscheint in einer committeten Datei.
Es gibt keine Bereichsmatrix in diesem Repository, und das ist kein Versehen: CurseForge veröffentlicht keinen Nur-Lese-Bereich und keine Bereichsauswahl, daher gibt es nichts zu matrixen. Die Nur-Lese-Eigenschaft dieses Servers stammt von seiner eigenen Endpunkt-Zulassungsliste, nicht von einer engeren Anmeldeinformation. Es gibt auch kein Token-Leck-Playbook – ein durchgesickerter Schlüssel gewährt Lesezugriff auf einen öffentlichen Katalog plus Kontingentverbrauch, was real ist und nicht in dieselbe Kategorie fällt wie das Nitrado-Token des Schwester-Repositories (dokumentiert als gleichwertig mit vollständiger Kontrolle über einen Spielserver). Diese richtige Größenordnung wird in ADR-002 §12 argumentiert, und sie beruht auf einer dort genannten Behauptung, damit sie widerlegt werden kann: CurseForge-Katalogdaten sind von Natur aus öffentlich.
Schwärzung, alles davon
Eine Regel: Gib niemals den API-Schlüssel aus. Eine Funktion, src/scrub.ts, angewendet auf Fehlermeldungen und auf jeden Upstream-Body-Ausschnitt. Anfrageheader erscheinen nie in Fehlern — weder der Schlüssel, noch ein geschwärzter Schlüssel, noch eine Liste von Headernamen. get_api_diagnostics meldet, ob ein Schlüssel konfiguriert ist, und niemals seinen Wert, ein Präfix davon oder seine Länge.
Verhaltensweisen, die man kennen sollte, bevor man die Ausgabe liest
Leer ist nicht unbekannt.
data: []bedeutet, dass CurseForge mit "keine" geantwortet hat — eine echte Antwort, bei der die Abfrage wiederholt wird, damit Sie sehen, was nichts zurückgegeben hat. Ein fehlendes Feld istnull, niemals0,""oder[]. Eine Anfrage, die nicht abgeschlossen wurde, oder eine Antwort mit falscher Form, ist ein Fehler — niemals ein Wert.Ein fehlender
data-Schlüssel ist ein Fehler, kein leeres Ergebnis. Das Erzwingen auf[]würde eine kaputte Integration in "keine Ergebnisse gefunden" verwandeln.Ein fehlendes
paginationan einem paginierten Endpunkt ist ebenfalls ein Fehler. Die Annahme einer Seite ist, wie ein Tool 50 von 900 Mods meldet, als ob es alle wären (U8 ist genau diese offene Frage).pageSize > 50wird abgelehnt, nicht begrenzt, und ebensoindex + pageSize > 10000— mit der größten zulässigen Seitengröße bei diesem Index, die in der Nachricht genannt wird. Ein Modell, das nach 200 fragt und stillschweigend 50 erhält, wird über eine Seite argumentieren, als ob sie eine Menge wäre.Wenn
totalCount10000 überschreitet, sagt die Tool-Ausgabe, dass das Ende UNREACHABLE ist, in diesen Worten, und rät, den Filter zu verengen anstatt zu blättern.Die ASA
gameIdwird zur Laufzeit ermittelt vonGET /v1/gamesund für die Lebensdauer des Prozesses zwischengespeichert; sie ist nie fest codiert und nie erraten. Wenn sie nicht aufgelöst werden kann, schlägt der Server laut fehl, wobei er benennt, wonach gesucht wurde und wie viele Spiele der Schlüssel sehen konnte — denngameIdist ein erforderlicher Suchfilter, sodass eine falsche ID saubere, leere, völlig falsche Ergebnisse anstelle eines Fehlers zurückgibt. Setzen SieCURSEFORGE_GAME_SLUG, wenn sich die eingebauten Kandidaten als falsch erweisen.resolve_mod_dependenciesist begrenzt auf Tiefe 4 und 400 Knoten, mit einer besuchten Menge für Zyklen. Wenn eine Grenze erreicht wird, wird das Ergebnis als truncated gemeldet, in diesem Wort, mit der unerforschten Grenze aufgelistet.
Repo-Struktur
src/
allowlist.ts THE CHOKEPOINT — seven entries, host pin, normalization, bounds, body checks
client.ts the single transport; the ONLY place x-api-key is attached; envelope unwrap
config.ts refuse-to-start; no NITRADO_*, no mode switch, no settable base URL
coerce.ts empty / absent / unknown, kept apart
errors.ts the error taxonomy
game.ts runtime gameId resolution (injected, process-lifetime cache)
registry.ts ToolDef + tier, and the boot assertion that refuses a non-tier-1 tool
scrub.ts never echo the key. That is the whole module.
probe-plan.ts one probe per unverified row, asserted complete by a test
server.ts stdio entry point
smoke.ts the key-arrival command
tools/ the seven tools
test/ 146 tests; fixtures are synthetic in content, structural in shape
scripts/ buildinfo generator, test enumeratorsrc/buildinfo.ts ist generiert und gitignored, mit dem Commit und einem dirty-Flag vor jedem tsc-Lauf gestempelt und wird von get_api_diagnostics bereitgestellt. dist/ ist gitignored und der Server läuft daraus als langlebiger Prozess, daher ist "welcher Code hat diese Antwort erzeugt?" nicht zur Laufzeit aus git beantwortbar — es muss mit dem Artefakt reisen.
Abweichungen vom Geschwister-Repo, bewusst genannt
ADR-002s offene Fragen 7 und 8 verlangen, dass diese dort benannt werden, wo sie auftreten:
Gleiche Basis, absichtlich. Node ≥20, TypeScript 5.9.3,
@modelcontextprotocol/sdk1.30.0,zod4.4.3,node:testüber denselbenscripts/run-tests.mjs-Enumerator. Gleicher Reviewer, gleiche Idiome, geringere Kosten für das Lesen beider.@cfworker/json-schemaist hier keine Abhängigkeit. Es unterstützt die Cron-Ausdrucksvalidierung des Geschwisters, und es gibt keinen Schreibpfad zu validieren.registry.tswird in der Struktur portiert und behälttier, lässt aber die Mode/Enabled-Liste-Mechanik weg — es hätte nichts zu filtern, da jedes Tool Tier 1 ist und jeder Endpunkt ein Lesevorgang ist. Eine Mode-Variable ohne dahinterliegende Funktionalität kündigt eine Steuerung an, die nicht existiert. Eine fünfzeilige Boot-Assertion ersetzt das Subsystem.redact.tswird nicht portiert (§12.1). Siehe "Schwärzung, alles davon" oben.Kein
UNKNOWN_OUTCOME-Fehlercode. Das Geschwister benötigt ihn, weil eine verlorene Antwort auf einenPUTmöglicherweise die Welt verändert hat. Jede Anfrage, die dieser Client stellen kann, ist ein Lesevorgang, daher bedeutet ein Timeout wirklich "es ist nicht passiert" und ein Wiederholungsversuch ist sicher.npm run smokebeendet mit 0, wenn es wegen eines fehlenden Schlüssels ablehnt. Die Ablehnung ist das erwartete Ergebnis, wenn man es heute ausführt, und das Banner sagt unübersehbarSMOKE NOT RUN. Wenn Sie möchten, dass eine Pipeline bei einem fehlenden Schlüssel fehlschlägt, steuern Sie die Pipeline über den Schlüssel und nicht über diesen Exit-Code.
Verwandte Aufzeichnungen
Im Geschwister-Repo nitrado-ark-mcp, von hier aus schreibgeschützt — nichts in diesem Repo wurde von diesem hier geändert:
docs/decisions/EXECUTIVE-BOARD-2026-08-16-curseforge-mods.md— die Vorstandsprotokolle (DEC-002), die dieses Repo ausführt. Seine Vorsitzentscheidungen sind bindend.docs/decisions/decision-log.md— DEC-002, und DEC-001 für die Aufteilung des Umfangs, auf der §10 beruht.docs/adr/ADR-001-write-path-enforcement.md— die Form, die ADR-002 portiert, und die Quelle der Normalisierungsregel, der Boot-Check-Begründung und der Begründung für die Verweigerung des Starts.
Die beiden Server bleiben unabhängig. nitrado-ark-mcp antwortet "diese Projekt-IDs sind in active-mods"; dieses Repo antwortet "Projekt X's neueste Datei ist v2.1". Das Modell hält beide. Kein Server ruft den anderen auf, und keiner hält jemals die Anmeldeinformationen des anderen.
This server cannot be installed
Maintenance
Related MCP Connectors
A MCP server built for developers enabling Git based project management with project and personal…
MCP server for doc2mcp documentation, generated by doc2mcp.
Official MCP server for Lovable, the AI-powered full-stack app builder.
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/JShort-bufr/curseforge-ark-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server