MCP setup#3941
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the specification and implementation blueprint for the Accounter MCP Connector, establishing a clear, multi-phase plan to expose read-only capabilities to Claude clients. The review feedback highlights key areas for improvement, including propagating the user's bearer token to the upstream GraphQL client, reusing existing shared auth utilities for token verification, enforcing strict size and TTL limits on the in-process cache to prevent memory exhaustion, and aligning Auth0 environment variables with the existing server configuration.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
🚀 Snapshot Release (
|
| Package | Version | Info |
|---|---|---|
@accounter/client |
0.1.0-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
@accounter/gmail-listener |
0.1.3-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
@accounter/israeli-vat-scraper |
0.1.13-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
@accounter/modern-poalim-scraper |
0.10.7-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
@accounter/scraper-app |
0.0.3-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
@accounter/server |
0.2.0-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
@accounter/shaam-uniform-format-generator |
0.2.7-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
@accounter/shaam6111-generator |
0.1.9-alpha-20260721160522-ec45a522bd0bb0917e824f9ba3d53c1ccf32da04 |
npm ↗︎ unpkg ↗︎ |
* feat(mcp-server): scaffold package skeleton (Prompt 01) Create packages/mcp-server with minimal TypeScript scaffolding and yarn workspace scripts, following the incremental MCP build plan in docs/mcp/implementation-blueprint.md. - package.json with build/dev/lint/test/typecheck scripts - tsconfig.json extending the monorepo base config - package-local vitest config for isolated test runs - src/index.ts no-op startup entrypoint - placeholder scaffold test under src/__tests__ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * fix(mcp-server): use fileURLToPath for direct-run detection Address review: comparing import.meta.url to a hand-built file:// string is fragile for paths with spaces/special chars (URL-encoded in import.meta.url). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo --------- Co-authored-by: Claude <noreply@anthropic.com>
* feat(mcp-server): strict environment config (Prompt 02) Add a fail-fast, schema-validated environment configuration module for the MCP server following docs/mcp/spec.md §14. - src/config/env.ts: zod schema covering MCP host/port/enabled/allowlist, Auth0 issuer/audience/JWKS, and upstream GraphQL URL/timeout, with secure defaults and least-privilege empty tool allowlist - pure, testable parseEnv() plus lazy memoized env accessor so importing the module is side-effect free while first access still fails fast - unit tests for valid config, defaults, derivations, and invalid/missing vars - env variable table documented in module comments and README Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * fix(mcp-server): pass processEnv to dotenv so custom source is honored Address review: dotenv mutates process.env by default; when loadEnv is called with a custom source, populate that source instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo --------- Co-authored-by: Claude <noreply@anthropic.com>
… Prompt 03) (#3953) * feat(mcp-server): HTTP bootstrap with health and graceful shutdown (Prompt 03) Stand up a minimal node:http server with a /health endpoint, graceful shutdown, and top-level error handling — no MCP protocol logic yet. - src/server.ts: stdlib HTTP server, GET /health returning status/service/version/uptime, deterministic 404/500 routing, and a unit-testable createShutdownHandler for SIGINT/SIGTERM with a forced-exit grace period - src/logger.ts: minimal single-line JSON structured logger - src/index.ts: entrypoint installing uncaughtException/unhandledRejection handlers and starting the server with fatal-startup guarding - tests for health, routing, version, and shutdown behavior Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * fix(mcp-server): harden health version read, shutdown, and logger Address review comments: - cache the package.json version read (avoid sync disk I/O per /health request) - close idle keep-alive connections during shutdown so it doesn't stall - wrap logger serialization in try/catch (used inside global error handlers) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo --------- Co-authored-by: Claude <noreply@anthropic.com>
…t 04) (#3954) * feat(mcp-server): MCP transport route with list-tools stub (Prompt 04) Add the Streamable HTTP MCP endpoint (POST /mcp) speaking JSON-RPC 2.0, with a request-dispatch skeleton and one internal smoke tool. Auth-agnostic and no upstream GraphQL calls yet. - src/mcp/jsonrpc.ts: minimal JSON-RPC 2.0 primitives, error codes, request validation - src/mcp/tools.ts: internal-only accounter_smoke_ping descriptor + runner - src/mcp/handler.ts: method dispatch (initialize, ping, tools/list, tools/call), deterministic method-not-found for unknown ops, bounded body reader, and the HTTP adapter (202 for notifications, 413 over cap) - src/version.ts: shared service name/version helper (avoids server↔handler import cycle) - server.ts: register POST /mcp and a deterministic 405 for GET /mcp - tests covering dispatch, malformed input, and the HTTP adapter Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * fix(mcp-server): harden MCP transport per review Address review comments: - tools/call with an unknown tool returns InvalidParams (-32602), not MethodNotFound — the method itself is supported - validate JSON-RPC params is a structured value (object/array), never a primitive - on oversized body, pause() the stream (not destroy) and set Connection:close + destroy after finish, so the 413 response is actually delivered - cache the package.json version read in version.ts (avoid sync disk I/O per /health request) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo --------- Co-authored-by: Claude <noreply@anthropic.com>
#3970) * feat(mcp-server): request context and structured request logging (Prompt 05) Add observability groundwork per docs/mcp/spec.md §11.1. - src/context.ts: per-request context with request id + correlation id (inherited from inbound X-Correlation-Id when present), method/route, and a latency timer; per-request context store via WeakMap - src/logger.ts: context-bound request logger that stamps requestId, correlationId, method, and route on every entry; completion/latency helpers - server.ts: mint context per request, echo X-Correlation-Id, and log request start/completion (status + latencyMs) and failures - query strings and auth headers are never logged - unit tests for context, logger, and correlation-id propagation Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * fix(mcp-server): robust route parsing and completion logging Address review comments: - guard new URL() in createRequestContext so a malformed req.url falls back to a path split instead of throwing out of context creation (which would hang the request) - log request completion on the response 'close' event (not 'finish') so an aborted/prematurely-closed connection still emits a completion log Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo --------- Co-authored-by: Claude <noreply@anthropic.com>
… 06) (#3971) * feat(mcp-server): OAuth protected resource metadata route (Prompt 06) Serve RFC 9728 protected-resource metadata so Claude clients can discover the Auth0 authorization server (docs/mcp/spec.md §6.2). - src/oauth/metadata.ts: config-driven buildProtectedResourceMetadata() and protectedResourceMetadataUrl() helpers; well-known path constant - GET /.well-known/oauth-protected-resource returns { resource, authorization_servers, bearer_methods_supported: ["header"] } as JSON, with resource matching MCP_PUBLIC_BASE_URL exactly - unit tests for the document shape + route-level test through requestHandler Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * test(mcp-server): use vi.stubEnv for the metadata route test Address review: stub env vars via vi.stubEnv/vi.unstubAllEnvs instead of mutating process.env directly, to avoid cross-test pollution. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo --------- Co-authored-by: Claude <noreply@anthropic.com>
… 07) (#3972) * feat(mcp-server): 401 challenge helper for auth discovery (Prompt 07) Add a standards-compliant unauthenticated response for MCP OAuth discovery (docs/mcp/spec.md §6.2, §10.1) and gate the MCP endpoint on token presence. - src/oauth/challenge.ts: buildWwwAuthenticateHeader() and sendUnauthorized() emitting 401 + WWW-Authenticate: Bearer with a resource_metadata pointer to the well-known document (transport-level, never a JSON-RPC/tool error) - handler.ts: hasBearerToken() presence check; POST /mcp without a bearer token now returns the 401 challenge (token validity verified in Prompt 08) - tests for the header builder, sendUnauthorized, the presence check, and the 401 path through mcpHttpHandler Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * fix(mcp-server): RFC-compliant WWW-Authenticate header Address review: - only emit error_description alongside error (RFC 6750 §3) - escape " and \ in quoted-string parameter values (RFC 7235) - use vi.stubEnv in the 401 handler test instead of mutating process.env Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo --------- Co-authored-by: Claude <noreply@anthropic.com>
…rompt 08) (#3973) * feat(mcp-server): bearer token extraction and Auth0 verification (Prompt 08) Verify Auth0 access tokens on the MCP endpoint (docs/mcp/spec.md §6.4, §8/§10.1), reusing the server package's jose-based JWKS approach. - src/auth/token.ts: extractBearerToken(); verifyAccessTokenWithKey() enforcing issuer/audience/signature/expiry and mapping claims to a typed AuthPrincipal (subject, scopes from scope+permissions, email); TokenVerificationError carries no token material; per-request principal store - src/auth/verifier.ts: env-backed verifyAccessToken() using a cached remote JWKS (createRemoteJWKSet) keyed by JWKS URL - handler.ts: POST /mcp now extracts + verifies the token; invalid/expired -> 401 with error="invalid_token"; missing -> 401 challenge; failures logged by reason only (never the token) - add jose dependency; unit tests for extraction, claim mapping, and valid/wrong-issuer/wrong-audience/expired/wrong-key verification Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * fix(mcp-server): don't mask JWKS/infra failures as 401; tidy principal types Address review: - verifyAccessTokenWithKey only wraps genuine token-validation errors (by jose error code) into TokenVerificationError; infrastructure failures (e.g. a JWKS fetch timeout) propagate so the request surfaces as a 5xx instead of a misleading 401 - handler.authenticate rethrows non-TokenVerificationError so those become 500 - use the AuthPrincipal type directly in the import and authenticate() return type instead of Awaited<ReturnType<...>> - tests: infra error propagation at both the verifier and handler layers Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo * prettier --------- Co-authored-by: Claude <noreply@anthropic.com>
No description provided.