Skip to main content
Glama
amar-p6

shared-skill-mcp

by amar-p6

shared-skill-mcp

Ein AWS-gehosteter MCP-Server, der dafür gebaut ist, mit der Zeit mehr als ein Tool aufzunehmen – nicht beschränkt auf das Google-Sheets-Abfrage-Tool, mit dem er begonnen hat. Eine gemeinsame Cognito-Authentifizierungsebene (Google-Login) + ein Bedrock AgentCore Gateway (der eigentliche MCP-Server) + eine Lambda pro Tool.

Die vollständige Spezifikation, das Architekturdiagramm und der phasenweise Verlauf für das ursprüngliche Tool query_sheet: Reel AI Workers/skills-spec/sheet-gviz/sheet-gviz.md.

Status (2026-08-24)

Live und Ende-zu-Ende bestätigt funktionsfähig, einschließlich eines echten claude.ai-Connectors, der den Google-Login abschließt und das Tool aufruft – nicht nur curl.

Element

Wert

MCP-Server-URL (Gateway)

https://sheets-gviz-gateway-63psdjvcgs.gateway.bedrock-agentcore.eu-west-1.amazonaws.com/mcp

Cognito-Domain

sheets-gviz-b24dc744.auth.eu-west-1.amazoncognito.com

Benutzerpool-ID

eu-west-1_sfGqYcC0a

AWS-Konto

423566941862, eu-west-1

Aktuelle Werte (einschließlich Secrets) jederzeit abrufen:

AWS_PROFILE=<your profile> terraform -chdir=terraform output
AWS_PROFILE=<your profile> terraform -chdir=terraform output -raw cognito_client_secret

Derzeit verfügbare Tools: query_sheet – führt eine gviz Abfrage (SQL-ähnlich: select/where/group by/pivot/order by) gegen ein Google Sheet aus.

Related MCP server: Google Workspace MCP

Architektur

claude.ai connector
      │  OAuth 2.1 (real Google login, via Cognito's Hosted UI)
      ▼
Cognito User Pool ──federates to──> Google (login only)
      │  issues an access token (no "aud" claim — see gotcha below)
      ▼
AgentCore Gateway (CUSTOM_JWT authorizer, matches by client_id)
      │  invokes under its own service role
      ▼
Lambda tool target (gateway-tool-handler.mjs) ──> gviz.js ──> Google Sheets API

Zwei Google-OAuth-Clients existieren und müssen getrennt bleiben: einen nutzt Cognito für den Login (föderierte Identität), einen nutzt gviz.js zum Lesen von Sheets (Dienst-Zugangsdaten, Refresh-Token-basiert, niemals interaktiv genutzt). Eine Wiederverwendung desselben Clients für beide Zwecke wurde bewusst vermieden – siehe das Framing „zweier Identitäten“ im Spezifikationsdokument.

Wie dieses Repo zu seinem heutigen Stand gekommen ist (lesenswert, bevor Sie das Auth-Setup ändern)

Die erste funktionierende Version verwendete eine selbst gebaute Lambda-Function-URL als MCP-Server; die Lambda selbst prüfte die Cognito-JWTs und stellte die OAuth-Discovery-Metadaten (RFC 9728 / RFC 8414) von Hand bereit. Das funktionierte per curl und per manuellem Postman-OAuth-Flow – vollständiger Roundtrip, echter Google-Login, echte Sheet-Daten – aber der tatsächliche Connector-Client von claude.ai scheiterte dabei jedes Mal still (Couldn't connect / Authorization failed), ohne dass ersichtlich wurde, warum: Die Lambda-Logs zeigten, dass claude.ai die Discovery-Metadaten einmal abrief und dann verstummte – kein Token-Austausch, kein Fehler, gar nichts.

Die damalige Arbeitshypothese: Cognito-Access-Tokens enthalten keinen aud-Claim (eine bekannte, reale Cognito-Einschränkung – durch das Dekodieren eines echten Tokens bestätigt), und die MCP-Spezifikation erwartet, dass der resource-Parameter, den ein Client sendet, in diesen Claim gespiegelt wird. Neue, glaubwürdig wirkende Hinweise aus anderen Teilen des Ökosystems schienen das als die Antwort zu untermauern. Das stellte sich als falsche Falle heraus – ein funktionierendes Referenzprojekt aus einem separaten Projekt (gleiche Person, anderes Repo) zeigte, dass Cognito + claude.ai-Connectors einwandfrei funktionieren, wenn Running environment Bedrock AgentCore Gateway vor Cognito verwendet wird, statt eines selbstpebauten Servers, mit CUSTOM_JWT-Authorizer, der über allowed_clients (Cognito-client_id) abgleicht, nicht über aud. Die eigentliche Ursache des ursprünglichen Fehlschlags wurde nie endgültig eingegrenzten – höchstwahrscheinlich hat etwas in der selbstepasseten JSON-RPC-/Discovery-Implementierung nicht genau dem entsprochen, was der claude.ai-Client erwartet, obwohl alle manuellen Tests bestanden wurden.

Lehre fürs nächste Mal: Ein konform aussehender, selbst gebauter MCP-Server, der curl- und Postman-Tests besteht, ist kein Beweis dafür, dass er gegen den echten Client von claude.ai funktioniert – die beiden können in einer weise stagedzteiden, die keinerlei Fehlersignal erzeugt. Bevorzugen Sie AWS’ eigende MCP-Server-Implementierung (Bedrock AgentCore Gateway) gegenüber einer manuellen Agent.

Implementierung von MCP + OAuth-Discovery, auch wenn das bedeutet, einen zusätzlichen AWS-Service lernen zu müssen und eine enger Gezeitlichere Terraform-Provider-Oberfläche zu haben (siehe Fallstricke unten).

Der selbstentwickelte Function-URL-Server (sheets-gviz-mcp Lambda, modules/mcp-lambda, src/lambda-handler.mjs, src/auth.mjs) wurde in folgenden Schritten erstellt: Thecontent wurde außer Betrieb genommen, sobald Gateway bestätigt war – per Terraform abgebaut (ohne Auswirkungen auf den weiterhin aktiven Cognito User Pool/die/Domain/App-Client, den der Gateway-Weg unverändert weiternutzt) und aus dem Repo gelöscht. Er bleibt der Git-Historie erhalten, falls die Überlegungen oder Implementierung noch einmal nützlich werdenn.

Fallstricke unterwegs (im Code behoben, vor einem erneuten Maßnahme unbedingt wissenswert)

Sheets/www-Ebene (src/gviz.js):

  1. Das OAuth-Token benötigt beide Scopes: .../auth/spreadsheets und .../auth/spreadsheets.readonlyreadonly allein ergibt einem 401, der wie eine HTML-Loginseite aussieht, stattütze sauberen Fehlers.

  2. Der /tq-Endpunkt von gviz benötigt auch bei OAuth-Bearer-Auth ein Segment /a/<domain>/ im Pfad – docs.google.com/a/google.com/spreadsheets/d/<id>/gviz/tq. Konfigurierbar über GVIZ_DOMAIN_SEGMENT, falls google.com für die Domain des betreffenden Google-Kontos nicht funktioniert.

  3. Immer headers=1 übergeben (in querySheet hart cciert). Ohne dieser Parameter get gviz’ Header-Zeilen-Erkennung zurück oder ergibt sich stille real falsch und packt echte Datenzeile zu einem einzigen Riesen-String in cols[].label, wobei sie vollständig verloren gehen.

AWS/–Terraform-Ebene: 4. IAM-Identity-Policy-Änderungen können Dutzdefa Sekunden bis einige Minuten dauern, bis sie tatsächlich wirksam werden, selbst wenn aws iam simulate-principal-policy sie sofort bestätigt. Erwartungs Sie, dass ein neues plan/apply direkt nach dem Erlaubn der neuen Aktion einmal mit 403 antwortet – das ist kein Zeichen für einen Fehler, sondern nur ein kurzer Wait and Retry. 5. ESM-.js-Dateien brauchen eine eigene package.json umschließend ({"type": "module"}), falls sie ohne diejenige im Repo-Wurzelverzeichnis gezippt werden. gviz.js nutzt export/import und löst sich genau deshalb als ESM-Only auf, weil diese Datei in jedem Lambda-ZIP neben ihr liegt (src/package.json). 6. Die Terraform-Ressourcen aws_bedrockagentcore_* sind neu und unter ändern sich laufend – bestätigen Sie die tatsächlichen Argumentstrukt seitSchema des Providers selbst (terraform providers schema -json) statt auf Handbuch- oder Blogposts zu vertrauen, die hinter kaum liegen wollen. Erfordert Provider >= 6.0. 7. Der CUSTOMER_JWT-Authorizer des AgentCore Gateway gleicht Aufrufer anhand von allowed_clients (Cognito-client_id) ab, nicht allowed_audience – genau das macht die Kombination mit Cognito’s nicht standardgemäßen (ohne aud) Access-Tokens ohne zusätzliche Token-Minting-Schicht möglich. 8. Die Umlagerung von bestandenen Terraform-Ressourcen in Module riskierte deren Zerstörung. Sowohl die Refactorisierung von Phase 4 in Module als auch spätere Function-URL-Absettzung nutzten vor jedem apply terraform state mv und einen realen plan-Check (0 Zerstörung aller Objekte, die überleben sollen). Der App-Client, für den claude.ai bereits Anmeldeinformationen besitziguante, wurdent zwischenzeitliche verschoben, ohne zerstört/neu erstett zu werden.

Einrichtung

1. Nachweis, dass die Sheets-Zugangsdaten funktionieren (eigenständig, ohne AWS)

Nachweisen Sie sich, dass die Sheets-Zugangsfunktion tatsächlich funktioniert:

cp .env.example .env   # fill in GOOGLE_CLIENT_ID/SECRET/REFRESH_TOKEN, SPREADSHEET_ID
node scripts/phase1-test.mjs "select *"

Fertig, wenn: Bei einer echten Abfrage {columns, rows} ausgegeben wird. Fehler hier sind Google-seitig (Berechtigungen, Freigabe, Sheets-API nicht aktiviert) – die schnellste Stelle, sie zu findenft, bevor man sich mit AWS beschäftigt.

2. Cognito + Gateway und die Tool-Lambda zubereiten

Benötigt werden AWS-Anmeldeinfos mit den Berechtigung in terraform/iam-policy.json sowie ein zweiter Google-OAuth-Client (Web-Anwendung, getrennt von Sheets-Lese-Client) für den Cognito-Login. Die Redirect-URI braucht Cognito-Domain, die noch nicht existiert – lösen Sie das Henne-Ei-Problem mit einem partiellen, runtime apply:

zeitweilig:

scripts/tf.sh apply -target=module.auth.aws_cognito_user_pool.this \
  -target=module.auth.aws_cognito_user_pool_domain.this

Erstellen Sie den Google-OAuth-Client mit der Redirect-URI https://<that domain output>/oauth2/idpresponse, zugeben Sie dann GOOGLE_LOGIN_CLIENT_ID/GOOGLE_LOGIN_CLIENT_SECRET in .env hinen und führen Sie aus:

scripts/tf.sh apply

CLAUDE_OAUTH_REDIRECT_URI muss nicht gesetzt werden – Standardwert ist https://claude.ai/api/mcp/auth_callback, bestätigt funktionabeltt für echte Connector.

3. Als claude.ai-Connector hinzugefügt

Rufen Sie Einstellungen → Connectors → „Benutzerdefinierten Connector hinzufügen“ auf:

  • Server-URL: die-Ausgabe gateway_url.

  • Erweiterte Einstellungen → OAuth2 Client ID/Secret: cognito_client_id- bzw. cognito_client_secret-Ausgabe.

Das sollte über Cognitos Hosted UI eine echte Google-Login einleiten und Claude daraufhin query_sheet aufrufen lassen (im Chat als Tool-Nutzungsblock sichtbar).

Neues Tool hinzufügen

  1. Einen Lambda-Handler schreiben, der den AgentCore-Lambda-Target-Vertrag beachtet – die event ist flach und gleich den Tool-Argumenten, no JSON-RPC-Wrapping (das Gateway übernimmt das MCP-Framing). Siehe src/gateway-tool-handler.mjs` für das Muster.

  2. Fügen Sie in main.tf einen module "..." { source = "./modules/gateway-tool-lambda" ... }-Block hinzu.

  3. Fügen Sie dafür einen aws_bedrockagentcore_gateway_target-Block hinzu – entweder erweitern Sie modules/agent coregateway so, dass er eine Liste von Targetzielen annimmt, oder legen Sie die Ressource direkt in main.tf an und zeigen auf module.gateway.gateway_id.

Keine neuen Google-OAuth-Clients, keine neue Cognito-Domain-Tools notwa und kein neues Gateway erforderlich – alles in module.auth und module.gateway (Element) zugleich geteilt.

Layout

src/
  gviz.js                  Sheets-reading logic — token refresh, gviz query, response
                            parsing. Host-agnostic; used by gateway-tool-handler.mjs.
  gateway-tool-handler.mjs AgentCore Gateway Lambda-target contract for query_sheet —
                            flat event-in/JSON-out, no JSON-RPC framing (Gateway
                            handles MCP protocol translation itself).
  package.json              {"type": "module"} — required for gviz.js's ESM syntax to
                            resolve once zipped alone, without the repo root's
                            package.json alongside it.
scripts/
  phase1-test.mjs           Standalone local proof the Sheets credential + gviz query
                            round-trip works, no AWS involved.
  tf.sh                     Wraps `terraform` with GOOGLE_*/Cognito vars sourced from
                            .env — use this instead of calling terraform directly.
terraform/
  main.tf                   Root — provider, variables, the shared auth module, the
                            claude.ai connector's Cognito app client, the Gateway, and
                            the query_sheet tool Lambda.
  modules/mcp-auth/         Cognito User Pool + Google identity provider + Hosted UI
                            domain. Shared — instantiate once per AWS account.
  modules/agentcore-gateway/ The Gateway (CUSTOM_JWT authorizer) + the query_sheet
                            Gateway Target. Extend for more targets, or add more
                            gateways for a genuinely separate trust boundary.
  modules/gateway-tool-lambda/ A standalone tool Lambda for a Gateway target — no
                            Function URL, no public permissions, no own Cognito
                            client. Gateway is the only caller, via its service role.
  iam-policy.json            Deploy-time IAM policy for whatever AWS identity runs
                            scripts/tf.sh. Broad on bedrock-agentcore:* deliberately —
                            that service/provider surface is new and evolving.
F
license - not found
Not graded
quality - not tested
B
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
    Not graded
    quality
    B
    maintenance
    MCP server for Google Drive, Docs, and Sheets — built for Claude Code. Gives Claude Code direct read/write access to Google Sheets (cell-level edits, formatting, structure), Google Docs (insert, replace, append), and Drive (search).
    52
    1
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    MCP server for Claude Desktop that provides tools to read/write Google Sheets, manage Gmail, schedule Google Calendar events, and run queries on Neon Postgres databases.

View all related MCP servers

Related MCP Connectors

  • Hosted Amazon Seller Central and Amazon Ads MCP server for Claude, ChatGPT, Cursor, and agents.

  • Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

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/amar-p6/shared-skill-mcp'

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