Skip to main content
Glama
Aa-ronJS

Doorknock

by Aa-ronJS

Doorknock

Ein entfernter MCP-Server, der ein Unternehmen anhand seiner eigenen Domain recherchiert, es gegen ein von Ihnen geliefertes Lead-Profil bewertet und das Ergebnis in HubSpot schreibt.

Alles, was er berichtet, wurde live von der eigenen Website des Unternehmens oder seinen öffentlichen DNS-Einträgen gelesen und trägt die URL oder DNS-Abfrage, die es erzeugt hat. Er kauft nichts von einem Datenanbieter und leitet nichts über Umsatz, Mitarbeiterzahl oder Eigentümerschaft ab.

Live: https://doorknock-eight.vercel.app MCP-Endpunkt: https://doorknock-eight.vercel.app/mcp OpenAPI: https://doorknock-eight.vercel.app/openapi.json Health: https://doorknock-eight.vercel.app/health

Verbinden

claude mcp add --transport http doorknock https://doorknock-eight.vercel.app/mcp

Jeder MCP-Client, der Streamable HTTP spricht, kann dieselbe URL verwenden. Es ist nur POST: Der Server ist zustandslos, daher antworten GET und DELETE absichtlich mit 405.

Die Recherche-Tools benötigen überhaupt keine Anmeldeinformationen. Die HubSpot-Tools benötigen ein privates App-Token mit crm.objects.companies.read und .write, das als Header übergeben wird:

claude mcp add --transport http doorknock https://doorknock-eight.vercel.app/mcp \
  --header "X-HubSpot-Token: pat-na1-..."

Für alles, was nicht MCP spricht, sind die identischen Operationen unter /v1/<operation> verfügbar und werden durch /openapi.json beschrieben, das aus denselben Konstanten generiert wird, die der Router verwendet, sodass die beiden nicht auseinanderdriften können. Darauf sollte eine benutzerdefinierte GPT-Action oder ein n8n-HTTP-Knoten zeigen.

Related MCP server: HubSpot Extended MCP Server

Die sieben Tools

Tool

Was es tut

research_company

Liest die Startseite und die DNS. Gibt die Marketing- und CRM-Tools zurück, die auf der Seite geladen sind, welche Standardseiten existieren, wer deren E-Mail verwaltet und ob deren ausgehende E-Mail geschützt ist.

qualify_lead

Führt die Recherche durch und bewertet sie dann anhand eines Profils, das Sie übergeben, und gibt eine Stufe mit der Begründung für jede Regel zurück.

check_email_posture

MX, SPF und DMARC, in einfachen Worten gelesen. Hält „Wird meine E-Mail sie erreichen“ und „Kommt ihre E-Mail an“ getrennt, weil es unterschiedliche Fragen sind.

list_signals

Das Vokabular, gegen das Profilregeln geschrieben werden: jede benannte Tatsache, was sie bedeutet und was ihr Fehlen beweist und nicht beweist.

hubspot_check_connection

Bestätigt, dass das Token funktioniert, und meldet das Portal und die Bereiche, bevor ein Schreibvorgang im schlimmsten Moment fehlschlägt.

hubspot_find_company

Findet ein Unternehmen anhand der exakten Domain, damit eine Anreicherung kein Duplikat erzeugt.

hubspot_write_company

Erstellt oder aktualisiert das Unternehmen und fügt optional eine Timeline-Notiz hinzu.

Drei Entscheidungen, über die es sich zu streiten lohnt

Die Anmeldeinformationen berühren niemals das Modell. Das naheliegende Design ist ein token-Parameter für die HubSpot-Tools. Das legt das Geheimnis in den Prompt, in den Kontextfenster, in das Transkript des Clients und in jedes Protokoll, das Tool-Aufrufe aufzeichnet, und macht das Token zu etwas, das ein Modell dazu überredet werden kann, es woanders hinzuschicken. Hier reist es stattdessen in der HTTP-Anfrage, in einem X-HubSpot-Token-Header, und kein Tool-Schema hat ein Feld dafür. Das Modell kann eine Schreiboperation anfordern; es hat niemals die Anmeldeinformationen in der Hand. Eine der adversarischen Prüfungen existiert ausschließlich, um zu bestätigen, dass kein Tool-Schema jemals ein Anmeldefeld bekommen hat.

Die Regeln sind Daten, kein Code. Qualifikationsregeln kommen mit dem Aufruf und kommen mit der Antwort zurück, sodass die Logik, die ein Urteil erzeugt hat, immer sichtbar ist und die Änderung, wer als gutes Lead gilt, niemals eine Bereitstellung erfordert. Eine Regel, die ein Signal benennt, das nicht existiert, wird als unbekanntes Signal gemeldet, anstatt stillschweigend als Fehlschlag gezählt zu werden, und eine Regel, deren Signal nicht bestimmt werden konnte, blockiert die Stufe, anstatt sie fehlschlagen zu lassen, weil „wir konnten es nicht sagen“ und „nein“ ein Lead an verschiedene Orte schicken.

Abwesenheit wird als Abwesenheit gemeldet. Ein Tag kann über einen Tag-Manager geladen werden, hinter einem Consent-Banner sitzen oder nur auf einer inneren Seite leben. Die Antwort sagt also „auf der Startseite nicht erkannt“, niemals „sie verwenden HubSpot nicht“, und jedes Signal trägt einen Satz darüber, was sein Fehlen nicht beweist.

Lokal ausführen

npm install
npm run typecheck     # tsc, no emit
npm run smoke         # every operation against the real internet
npm run smoke:mcp     # every endpoint over a real node:http server
npm run smoke:live -- https://doorknock-eight.vercel.app    # the deployment, via the official client SDK
npm run adversarial -- https://doorknock-eight.vercel.app   # tries to break it
npm run prove -- https://doorknock-eight.vercel.app         # independent evidence

Es gibt nirgendwo Mocks. Ein gemockter Resolver beweist, dass mein Mock das zurückgibt, was ich ihm gesagt habe; die Fehler, die es sich zu fangen lohnt, sind eine sich ändernde Form des Upstreams, und kein Mock hat jemals einen gefangen.

npm run adversarial ist das, was Dinge findet. Es zielt auf den Cloud-Metadaten-Endpunkt, wirft feindselige Hostnamen, falsche Typen, 4000-Zeichen-Domains und fehlerhafte Protokollrahmen auf den bereitgestellten Server und behandelt eine selbstbewusste Antwort auf eine Frage, die der Server hätte ablehnen sollen, als die schlimmste Art von Fehler. Es fand drei echte Defekte beim ersten Lauf.

Überprüfen, ohne diesem Repository zu vertrauen

npm run prove existiert, weil das Bestehen meiner eigenen Tests jemandem, der sie nicht geschrieben hat, sehr wenig beweist. Es ruft den bereitgestellten Server über das offizielle MCP-Client-SDK auf, holt dann jeden DNS-Fakt von einem anderen Resolver als dem, den der Server verwendet hat, und holt die Seite direkt vom Unternehmen, vergleicht Feld für Feld und druckt jede Quell-URL.

Drei weitere Möglichkeiten, die nichts von hier benötigen:

# Anthropic's own inspector, not my code
npx @modelcontextprotocol/inspector --cli https://doorknock-eight.vercel.app/mcp --transport http --method tools/list

# raw JSON-RPC, no client, no session, because it is stateless
curl -s -X POST https://doorknock-eight.vercel.app/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

# let your own client run its health check against it
claude mcp add --transport http doorknock https://doorknock-eight.vercel.app/mcp
claude mcp list

Und die Version, die nur einen Browser benötigt. Öffnen Sie beide und vergleichen Sie:

Was kaputtging und was ich dagegen getan habe

Bisher sechs Defekte. Drei kamen vom adversarischen Skript beim ersten Lauf gegen die Bereitstellung, einer vom unabhängigen Verifikationsskript, und einer war in einem Test und nicht im Server.

1. Eine Ablehnung, die in einen Erfolg eingewickelt war. Die Frage an den Server nach 169.254.169.254 oder metadata.google.internal gab HTTP 200 mit einem Ergebnisobjekt zurück. Nichts leckte: Der Fetch-Guard lehnte die Anfrage korrekt ab, sodass keine interne Adresse jemals kontaktiert wurde. Aber der Recherche-Aufruf führt den Seitenabruf und die DNS-Lookups parallel aus, und die DNS-Hälfte machte fröhlich weiter, sodass der Aufrufer eine 200 um eine Ablehnung herum bekam. Defense in Depth hatte funktioniert, und der Antwortvertrag nicht. Die Adressregeln laufen jetzt in normaliseDomain, an der Eingangstür, sodass die gesamte Operation mit 400 ablehnt.

2. Redirects wurden von der Laufzeit verfolgt, die nichts prüfte. Die erste Version übergab redirect: 'follow' und validierte nur den ersten Hop. Ein öffentlicher Host, der mit 302 auf eine interne Adresse antwortet, wäre direkt durch den Guard gesegelt. Redirects werden jetzt von Hand verfolgt, maximal fünf, wobei jeder Hop neu aufgelöst und geprüft wird, bevor er genommen wird, und die Kette wird in der Antwort zurückgegeben, weil wohin eine Domain Sie schickt, selbst ein Befund ist.

3. Eine 4000-Zeichen-Domain wurde akzeptiert. Keine Längenprüfung irgendwo. DNS selbst stoppt bei 253 Zeichen und 63 pro Label, also kann alles Längere kein echter Name sein. Jetzt mit einer Erklärung abgelehnt.

4. MX-Einträge mit gleicher Priorität kamen bei jedem Aufruf in anderer Reihenfolge zurück. Gefunden vom unabhängigen Verifikationsskript, das einen Unterschied zwischen dem, was der Server sagte, und dem, was ein zweiter Resolver sagte, meldete. Die Einträge waren identisch; nur die Reihenfolge unterschied sich, weil Resolver Antworten mit gleicher Priorität rotieren und die Sortierung nur nach Priorität erfolgte, was keine totale Ordnung ist. Gleichstände werden jetzt nach Hostname aufgelöst, sodass dieselben Einträge immer dieselbe Ausgabe erzeugen.

5. Ein Test, der an etwas scheiterte, das er nie ansah. Das adversarische Skript kürzte jeden Antwortkörper auf 600 Zeichen, bevor es ihn prüfte, sodass die Assertion für unbekannte Signale nach einem Feld etwa vier Kilobyte in der Antwort suchte, es nie sah und den Server als defekt meldete, obwohl der Server korrekt war. Das kostete mehr Zeit als jeder der echten Defekte. Der Körper wird jetzt ganz behalten und nur beim Drucken gekürzt. Ein Test, der ein Bestehen oder Scheitern aus etwas entscheidet, das er nie tatsächlich gelesen hat, ist schlimmer als kein Test, weil ihm geglaubt wird.

6. Die Plattform übergibt dem Handler eine Node-IncomingMessage, keine Web-Request. Geerbt vom vorherigen Server, den ich so gebaut habe, und der Grund, warum npm run smoke:mcp einen echten node:http-Server aufstellt und über einen Socket mit ihm spricht, anstatt Request-Objekte im Speicher zu bauen. Ein Test, der seine eigene Request-Form baut, testet nur diese Form.

Grenzen, klar ausgesprochen

  • Es liest nur die Startseite. Ein Tag, das über einen Tag-Manager geladen wird oder auf einer inneren Seite lebt, wird übersehen, und die Antwort sagt das, anstatt zu implizieren, dass das Tool abwesend ist.

  • Es weiß nichts über Mitarbeiterzahl, Umsatz, Eigentümerschaft oder Kontaktnamen und wird keine Domain aus einem Firmennamen erraten.

  • DKIM wird nicht geprüft. Der Selektor kann nicht aus DNS entdeckt werden, also bedeutet das Prüfen Raten, und ein Fehlversuch sieht identisch aus wie eine Domain ohne DKIM.

  • Der Adress-Guard löst den Namen auf, prüft die Adressen und holt dann per Namen, sodass eine DNS-Änderung zwischen diesen beiden Schritten nicht vollständig geschlossen ist. Das Pinnen der Verbindung auf die geprüfte Adresse erfordert einen Agenten, den diese Laufzeit nicht bereitstellt. Die Abmilderung ist, dass kein Antwortkörper jemals roh zum Aufrufer gelangt, nur benannte übereinstimmende Signale, sodass ein erfolgreicher Rebind nichts Lesbares an denjenigen zurückgibt, der es versucht hat. Das steht auch im Code.

Wie es aufgebaut ist

src/core.ts            the operations, shared by both front doors
src/mcpServer.ts       the MCP tool surface
src/lib/guard.ts       what this server is allowed to fetch
src/lib/dns.ts         DNS over HTTPS, so every fact has a URL
src/lib/site.ts        redirect-by-hand page fetching and reading
src/lib/fingerprints.ts  the technology table, one literal string per entry
src/lib/email.ts       MX, SPF and DMARC, read in plain words
src/lib/signals.ts     the published vocabulary
src/lib/qualify.ts     the rules engine
src/lib/hubspot.ts     the CRM writes, with the caller's own token
api/                   the four endpoints
scripts/               five suites, no mocks

MIT-lizenziert.

A
license - permissive license
Not graded
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 Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that provides AI agents with ICP Triangulation Framework™ for scoring prospects across firmographics, behaviors, and growth signals, plus RFM analysis and pipeline health scoring, with optional HubSpot integration.
    3
    Business Source 1.1
  • F
    license
    Not graded
    quality
    B
    maintenance
    An MCP server that uses a browser extension to interact with HubSpot through the logged-in browser, enabling reading, searching, creating, and updating HubSpot records without API tokens.
    9
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP-native sales intelligence server enabling prospect enrichment, LinkedIn scraping, and CRM push to HubSpot/Salesforce via natural language.
    80
    Mozilla Public 2.0

View all related MCP servers

Related MCP Connectors

  • Remote MCP server to enrich company profiles with structured B2B data and confidence scores.

  • A paid remote MCP for hosted MCP server, built to return verdicts, receipts, usage logs, and audit-r

  • A paid remote MCP for Skybridge, built to return verdicts, receipts, usage logs, and audit-ready JSO

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/Aa-ronJS/doorknock'

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