You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add delegated MCP-to-API JWT authentication: a route-, scope-, and
subject-bound token verifier (pkg/auth) and a Fiber middleware
(MCPDelegationAuth) that loads the existing user auth context from the
token's Firebase-UID subject when the token is valid for the exact
method/path/scope of the request.
MCPDelegationAuth is registered before BearerAuth so a cryptographically
valid but insufficiently-scoped or misbound MCP token is rejected with
403 directly, instead of falling through to Firebase ID token
verification. BearerAuth now short-circuits when a prior middleware has
already populated the auth context, and no longer logs the raw bearer
token on verification failure.
The verifier is wired into the DI container from MCP_AUTH_ISSUER,
MCP_AUTH_AUDIENCE, and MCP_AUTH_JWKS_URL; it is disabled when all three
are empty and container construction fails fast when only some are set.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9ff1e38a-b018-4cf7-a5e9-5044a2efd03c
Add GET /v1/messages/incoming, scoped to messages:read, that reuses
MessageService.SearchMessages while forcing types=[mobile-originated].
The endpoint has no CAPTCHA requirement, unlike /v1/messages/search
which remains unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9ff1e38a-b018-4cf7-a5e9-5044a2efd03c
Review round 1 fixes for Task 3:
- Remove the unused firebase.google.com/go dependency and its entire
transitive graph. It pulled a Go 1.26 floor via a transitive dep while
this module must stay on Go 1.25; the approved Task 5 design uses a
custom Firebase certificate/JWT verifier instead of the Admin SDK.
go.mod remains `go 1.25.0`; the still-needed-later pins
(modelcontextprotocol/go-sdk v1.7.0, redis/go-redis/v9, otelhttp) are
preserved per the multi-task plan.
- Replace KeySet's exported, freely-mutable Issuer/MCPAudience/APIAudience
fields with a private atomic.Pointer[keySetConfig] published exactly
once via a new Configure(issuer, mcpAudience, apiAudience string) error.
Configure rejects empty values and a second call; signing methods fail
closed until Configure has succeeded. Publishing the whole config behind
a single CompareAndSwap (rather than a bool flag written before the
fields) avoids a visibility race where a reader could see "configured"
before the fields were set.
- Add tests: unconfigured signing rejected, successful configuration,
reconfiguration rejection (with slot-not-consumed-by-invalid-call and
original-values-preserved checks), and a concurrent-Configure-calls test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9ff1e38a-b018-4cf7-a5e9-5044a2efd03c
- Pin the CIMD document fetch's actual TCP connection to the single
IP address already validated as public (resolve exactly once),
instead of letting the http.Transport dial its own second,
unvalidated DNS resolution of the client_id host. Closes a
DNS-rebinding/TOCTOU gap. Host header and TLS SNI still use the
original hostname since only the dial address changes.
- Reject CIMD responses whose Content-Type is not application/json
(charset and other parameters are still allowed), wrapping
ErrClientMetadataInvalid.
- NewRedisStore now panics for a *redis.ClusterClient or *redis.Ring:
RotateRefreshToken's Lua script touches two independently-hashed
keys in one atomic EVAL, which the approved key format cannot
guarantee share a Redis Cluster hash slot. This service requires a
standalone Redis client (redis.NewClient); documented in RedisStore.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9ff1e38a-b018-4cf7-a5e9-5044a2efd03c
Delegated MCP verification now prefilters bearer tokens on their
unverified "iss" claim -- parsed only to discard tokens that cannot be
ours and never trusted for authentication -- so Firebase ID tokens and
other non-MCP credentials seen by the pre-BearerAuth middleware never
reach the JWKS cache. The JWKS cache itself collapses concurrent
refreshes into one in-flight fetch, refuses a new fetch until
MinRefreshInterval (default one minute) has elapsed, and keeps serving
an already known key while throttled, mirroring the MCP Firebase
certificate cache. The 2s HTTP timeout, key rotation, and fail-open
middleware behavior are unchanged.
The MCP CIMD client cache is bounded at 1024 entries, purging expired
entries and then deterministically evicting the entry closest to
expiring under the existing mutex, preserving its 15-minute TTL.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9ff1e38a-b018-4cf7-a5e9-5044a2efd03c
⚠️ GitGuardian has uncovered 2 secrets following the scan of your pull request.
Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.
If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
following these best practices for managing and storing secrets including API keys and other credentials
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer TIP This summary will be updated as you push new changes.
The PR adds a standalone, stateless MCP service with Firebase-backed OAuth, scoped delegated JWT authentication, Redis state and rate limits, seven httpSMS tools, and a dedicated incoming-message API.
Adds OAuth metadata, authorization-code and refresh-token grants, client registration, signing keys, and JWKS publication.
Adds API-side verification for audience-, scope-, method-, and path-bound MCP delegation tokens.
Adds MCP tool handlers and a typed httpSMS API client for phones, messages, threads, and API-key operations.
Adds Cloud Run assets and expanded unit and full-stack integration coverage.
Confidence Score: 4/5
The PR is not ready to merge because the checked-in production deployment leaves API-side MCP delegation disabled, causing all hosted MCP tool calls to fail authorization.
The MCP service correctly mints delegated API tokens, but the production API deployment supplies none of the trust settings required to install their verifier, so those tokens cannot authenticate against api.httpsms.com.
Introduces optional MCP verifier configuration whose disabled-by-default behavior leaves production delegation inactive without coordinated deployment settings.
api/pkg/di/container.go
Installs delegated authentication before Firebase bearer authentication, but only when the missing production trust configuration enables it.
api/pkg/auth/mcp_token_verifier.go
Adds bounded RS256 verification with issuer, audience, scope, method, and exact request-path enforcement.
api/pkg/handlers/message_handler.go
Adds the authenticated incoming-message endpoint and forces searches to mobile-originated messages.
mcp/internal/oauth/token.go
Implements PKCE-bound authorization-code exchange and scope-narrowing refresh-token rotation with atomic Redis state transitions.
mcp/internal/oauth/clients.go
Implements bounded client metadata retrieval with public-address validation, DNS pinning, redirect rejection, and exact client-ID binding.
mcp/internal/tools/api_keys.go
Adds scoped API-key tools with one-time, user/client/operation-bound confirmation before primary-key rotation.
mcp/internal/tools/messages.go
Adds scoped message and thread tools with bounded schemas and direct mapping to operation-bound API calls.
mcp/cloudbuild.yaml
Deploys the hosted MCP service and its secrets, but cannot by itself establish the required trust configuration on the API service.
api/cloudbuild.yaml
Continues deploying the API without the MCP issuer, audience, or JWKS variables required for the newly added delegated authentication path.
Sequence Diagram
sequenceDiagram
participant Client as MCP Client
participant MCP as Hosted MCP Server
participant Firebase as Firebase
participant Redis as Redis
participant API as httpSMS API
Client->>MCP: OAuth authorization + PKCE
MCP->>Firebase: Verify identity token
MCP->>Redis: Store/consume grant state
MCP-->>Client: MCP access + refresh tokens
Client->>MCP: Authenticated tool call
MCP->>MCP: Check scope and mint operation-bound JWT
MCP->>API: HTTP request with delegated JWT
API->>MCP: User-scoped result
MCP-->>Client: Structured tool result
Filter mobile-originated messages in the MCP tool instead of adding a dedicated API route.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Configure API trust for hosted MCP delegation tokens and replace static secret-like test fixtures to prevent scanner noise.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9ff1e38a-b018-4cf7-a5e9-5044a2efd03c
Secret-scan follow-up: both GitGuardian findings were test-only fixtures, not deployable credentials. Commit c2556b3 removes the checked-in throwaway RSA private-key fixture by generating it at test runtime and replaces the high-entropy-looking API-key test value. No production secret was exposed or requires rotation.
Adds a hosted MCP service with OAuth authentication, delegated API access, Redis-backed state/rate limits, deployment assets, and integration coverage.
Changes:
Implements seven MCP tools and OAuth 2.1 flows.
Adds API-side delegated JWT authentication.
Adds Cloud Run, Docker, CI, and integration-test support.
Prevent notification scheduling from racing phone SENT events in the integration suite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 068b4956-94f1-4bbf-af3f-809a3a53d43e
A query-binding error logs OriginalURL, which includes the full query string. A malformed sort_descending can therefore cause owner phone numbers and a free-text SMS search query to be persisted in logs. Log the route/path without RawQuery.
Validation warnings leak sensitive request fields
api/pkg/handlers/message_handler.go:584
This warning serializes the full request, including query (which may contain SMS content) and owner phone numbers, into logs. Because validation failures are caller-triggerable, sensitive filter values can be deliberately persisted. Log only the validation errors or field names.
Repository error logs expose message and phone data
api/pkg/handlers/message_handler.go:590
On repository errors this logs the complete incoming-message request, including free-text message queries and phone numbers. Those values are intentionally redacted from MCP transport traces, so logging them here reintroduces the same disclosure. Keep the operation context but omit request values.
Integer overflow bypasses these bounds: a digit-only value larger than int passes the numeric rule, strconv.Atoi returns an error, and this helper adds no validation error. getInt then silently converts it to zero, so an invalid request is accepted with different pagination semantics. Treat conversion errors as invalid too.
Rounding can understate the remaining fixed-window delay (for example, 1.4 seconds becomes 1), causing a compliant client to retry while the same window is still active and receive another rate-limit error. Round up to whole seconds, as the registration limiter already does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
2026-07-28and2025-11-25compatibilityTools
list_phonessend_smslist_message_threadslist_thread_messageslist_incoming_messagescreate_phone_api_keyrotate_user_api_keyValidation