Skip to main content
Glama
msjgriffiths

Sense Family MCP

by msjgriffiths

Sense Family MCP for ChatGPT

An OAuth-protected AWS gateway that lets a small, explicitly invited group use the Sense family calendar MCP server from ChatGPT without giving ChatGPT the underlying Sense API key.

Sense authenticates its MCP endpoint with a bearer API key. ChatGPT custom apps expect a remote MCP server with OAuth. This project bridges those two models: ChatGPT authenticates each adult through Amazon Cognito, the gateway validates the resulting access token, and only then does it substitute the encrypted Sense key for the upstream request.

The reference deployment has been tested end to end with ChatGPT Pro. OAuth code exchange and the upstream tools/list call succeeded, and ChatGPT discovered all twelve allowed actions. No calendar or reminder record was read or changed during that verification.

IMPORTANT

This is a private family-data gateway, not a public proxy. Deploy your own stack, invite only the intended users, and never commit a Sense key or.env file. This project is not affiliated with Sense or OpenAI.

Architecture

ChatGPT account A ── OAuth + PKCE ──┐
                                    ├── Amazon Cognito
ChatGPT account B ── OAuth + PKCE ──┘          │
                                               │ short-lived JWT
                                               ▼
                                     CloudFront distribution
                                      - disables caching
                                      - restores OAuth challenge headers
                                               │
                                               ▼
                                      Lambda Function URL
                                      - validates JWT claims
                                      - binds client to user
                                      - enforces scopes
                                      - filters MCP tools
                                      - selects encrypted key
                                               │
                                               │ Sense bearer key
                                               ▼
                                  https://api.getsense.ai/mcp/

CloudFront is used because Lambda Function URLs do not preserve the standards-required WWW-Authenticate response header in the form ChatGPT needs for OAuth discovery. A small CloudFront response function restores the header; the Lambda remains the authentication and authorization boundary.

Related MCP server: Google Calendar MCP Server

Security model

  • Cognito public clients use authorization code flow with PKCE S256.

  • Self-registration is disabled; the deployment creates only invited users.

  • Cognito managed login v2 binds the canonical MCP resource URL into the access token audience.

  • The gateway verifies signature, issuer, audience, expiry, token type, OAuth client, Cognito username, and required scope.

  • Each OAuth client is bound to one Cognito identity and one explicitly selected SSM parameter path.

  • Sense keys are encrypted SecureString parameters and never enter the CloudFormation template, Git history, Lambda environment, or application logs.

  • The inbound ChatGPT access token is never forwarded to Sense.

  • Both advertised tools and guessed tools/call requests are allowlisted.

  • Request bodies, response bodies, calendar content, names, OAuth codes, and credentials are excluded from logs. Logs expire after seven days.

  • Lambda reserved concurrency is capped at five.

  • An optional AWS Budget sends alerts around a USD 1 monthly threshold.

The OAuth implementation follows the official OpenAI authentication guidance: protected-resource metadata, authorization-server metadata, resource indicators, PKCE, exact redirect URIs, audience validation, and per-request token verification.

Allowed actions

Read actions:

  • get_family_members

  • get_events

  • search_events

  • get_reminders

  • search_reminders

  • get_reminder_by_id

Optional write actions:

  • create_event

  • update_event

  • create_reminder

  • create_reminders

  • update_reminder

  • complete_reminder

Delete, account, billing, family-management, import, bulk-mutation, and other Sense tools remain blocked. Write actions are enabled only when the stack is deployed with -EnableWrites true.

Prerequisites

  • An AWS account

  • AWS CLI v2 authenticated with a named profile

  • Node.js 22 or newer

  • PowerShell 7 or Windows PowerShell

  • One Sense API key for a shared family identity, or one key per adult

  • ChatGPT accounts that can create custom MCP apps

The included deployment scripts currently pin AWS resources to us-east-2.

Local verification

npm ci
npm run check

npm run check runs the Node test suite and builds the Lambda bundle in dist/index.cjs.

The tests cover OAuth discovery, token-proxy redaction, JWT audience checks, client/user binding, origin restrictions, read/write scopes, tool filtering, blocked guessed tools, and replacement of the inbound token with the selected Sense key.

Deploy to AWS

1. Authenticate the AWS CLI

The scripts default to the profile sense-mcp:

aws configure sso --profile sense-mcp
aws sso login --profile sense-mcp

Any AWS authentication method that makes the profile usable is fine. Confirm it before deploying:

aws sts get-caller-identity --profile sense-mcp --region us-east-2

2. Bootstrap the stack

The first deployment uses harmless placeholder values for the public MCP resource and ChatGPT callback URLs:

.\scripts\deploy.ps1 -BudgetEmail 'your-alert-address@example.com'

Copy the McpUrl output, then redeploy once so Cognito scopes and token audiences use that exact CloudFront URL:

.\scripts\deploy.ps1 -McpResourceUrl '<McpUrl output>'

On an existing stack, omitted resource URL, callback URL, key-path, budget, and write-mode arguments are read from CloudFormation and preserved. An ordinary redeploy therefore cannot silently reset working OAuth settings.

3. Invite the two Cognito users

.\scripts\create-users.ps1 `
  -PrimaryEmail 'adult-a@example.com' `
  -PartnerEmail 'adult-b@example.com'

The intended user must complete the temporary-password change and MFA setup interactively. Do not automate or share those credentials.

4. Store the Sense key

Create a local file outside Git containing either a raw key or:

SENSE_API_KEY=sense_replace_with_a_real_key

Upload it directly to encrypted SSM Parameter Store:

node .\scripts\upload-sense-key.mjs `
  --person primary `
  --file C:\secure\path\sense.env

For separate adult Sense identities, upload a second key with --person partner. To use one shared family key, map both OAuth clients to the same encrypted parameter:

.\scripts\deploy.ps1 `
  -PartnerKeyParameter '/sense-mcp/primary/key'

The source key file should remain outside the repository and be deleted or secured after upload.

5. Enable the desired action set

Read-only is the deployment default. To expose the six reviewed write actions:

.\scripts\deploy.ps1 -EnableWrites true

This does not expose Sense deletion or administrative actions.

Connect ChatGPT

Repeat this process separately in each ChatGPT account:

  1. Enable developer mode in ChatGPT.

  2. Open Plugins and choose Create app.

  3. Select Server URL and enter the stack's McpUrl output.

  4. Select OAuth.

  5. Open Advanced OAuth settings and confirm that the discovered scopes end with /mcp/read and, when enabled, /mcp/write.

  6. Choose User-Defined OAuth Client and enter the matching PrimaryClientId or PartnerClientId CloudFormation output.

  7. Keep the token endpoint authentication method set to none.

  8. Copy the exact callback URL displayed by ChatGPT.

  9. Before completing the connection, deploy that callback into Cognito:

    .\scripts\deploy.ps1 -PrimaryCallbackUrl '<exact ChatGPT callback URL>'

    Use -PartnerCallbackUrl for the second account.

  10. Finish creating the app and sign in as the Cognito user bound to that client.

ChatGPT uses a callback-ID-specific redirect when the authorization server does not advertise RFC 9207 issuer identification. The callback must therefore be copied exactly from ChatGPT rather than guessed or shortened. See the OpenAI OAuth redirect guidance.

If OAuth scopes change after a ChatGPT app has already been created, create a fresh app definition. ChatGPT can cache the old scope list, and repeatedly reconnecting that old definition may continue to return invalid_scope.

Smoke tests and operations

Test the upstream Sense key without reading calendar content:

node .\scripts\smoke-upstream.mjs

That script calls only MCP initialize and tools/list and prints server metadata plus the tool count.

Tail safe gateway logs:

aws logs tail /aws/lambda/sense-mcp-gateway `
  --since 10m `
  --profile sense-mcp `
  --region us-east-2 `
  --format short

Rotate a Sense key by uploading the replacement to the same SSM parameter. New Lambda execution environments will use the new value. Revoke the old key in Sense after confirming the replacement works.

Cost

The design avoids a VPC, NAT gateway, API Gateway, load balancer, custom domain, and provisioned concurrency. At family-scale traffic it is intended to stay within or close to the free allowances for Cognito, Lambda, CloudFront, SSM standard parameters, and CloudWatch. AWS pricing changes, so verify current Cognito, Lambda, Systems Manager, CloudFront, and CloudWatch pricing for your account and region.

Repository layout

src/                    Lambda gateway, JWT validation, and SSM access
test/                   Node test suite
scripts/deploy.ps1      Build, package, and deploy the CloudFormation stack
scripts/create-users.ps1
scripts/upload-sense-key.mjs
scripts/smoke-upstream.mjs
template.yaml           AWS SAM / CloudFormation infrastructure
PROPOSAL.md              Architecture, threat model, costs, and rollout notes

For the detailed design rationale and acceptance criteria, see PROPOSAL.md.

License and support

No license is currently granted beyond the rights provided by GitHub's terms of service. This is a small personal project and comes without warranty or vendor support.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers