@ateam-ai/mcp 0.4.92 → 0.4.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/http.js +30 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.92",
3
+ "version": "0.4.93",
4
4
  "mcpName": "io.github.ariekogan/ateam-mcp",
5
5
  "description": "A-Team MCP Server — build, validate, and deploy multi-agent solutions from any AI environment",
6
6
  "type": "module",
package/src/http.js CHANGED
@@ -180,24 +180,34 @@ export function startHttpServer(port = 3100) {
180
180
  next();
181
181
  };
182
182
 
183
- // Bearer auth middleware chains for MCP routes:
184
- // - "/" (Claude.ai): strict OAuth — Bearer token required
185
- // - "/mcp" (ChatGPT): optional OAuth — validate Bearer if present, pass through if not
186
- const mcpAuthStrict = bearerMiddleware
183
+ // Bearer auth middleware for MCP routes — STRICT ON BOTH PATHS.
184
+ //
185
+ // "/mcp" used to be optional-auth (704206e): validate a Bearer if one is
186
+ // present, otherwise let the request through so the caller could authenticate
187
+ // in-band with the ateam_auth tool. That reads as permissive, and it is —
188
+ // but permissiveness is not free, because SILENCE IS AN ANSWER TO A CLIENT.
189
+ //
190
+ // An OAuth client discovers that it must send a token by being REFUSED one
191
+ // that lacks it: 401 plus WWW-Authenticate pointing at the resource metadata
192
+ // (RFC 9728, and what the MCP authorization spec builds on). Answering 200 to
193
+ // an anonymous request tells the client the endpoint is public, so it never
194
+ // attaches the token it is holding.
195
+ //
196
+ // That is exactly what happened to ChatGPT, measured rather than guessed:
197
+ // 107 requests to /mcp, ZERO carrying an Authorization header, while the
198
+ // connector had completed OAuth and held a valid token. Every session was
199
+ // anonymous, so every tenant tool refused, and ChatGPT disabled the connector
200
+ // — a failure that looks like a broken server and is actually a server that
201
+ // never asked. The token was there the whole time.
202
+ //
203
+ // The in-band ateam_auth path is NOT lost: a client authenticates with its
204
+ // bearer and may still call ateam_auth to switch tenants or point at another
205
+ // environment. What is gone is authenticating with nothing at all, which
206
+ // never worked for an OAuth client anyway — it only looked like it did.
207
+ const mcpAuth = bearerMiddleware
187
208
  ? [autoInjectToken, bearerMiddleware]
188
209
  : [];
189
210
 
190
- // Optional auth: if Bearer token present, validate it (sets req.auth for seedCredentials).
191
- // If no token, let the request through — user can authenticate via ateam_auth tool.
192
- const optionalBearerAuth = bearerMiddleware
193
- ? (req, res, next) => {
194
- if (!req.headers.authorization) return next();
195
- bearerMiddleware(req, res, next);
196
- }
197
- : (_req, _res, next) => next();
198
-
199
- const mcpAuthOptional = [autoInjectToken, optionalBearerAuth];
200
-
201
211
  // ─── CORS — required for browser-based MCP clients ──────────────
202
212
  // Origin allowlist (round 014 security hardening).
203
213
  // ATEAM_CORS_ALLOWED_ORIGINS env = comma-separated list, or "*" / unset for
@@ -418,14 +428,12 @@ export function startHttpServer(port = 3100) {
418
428
  await transports[sessionId].handleRequest(req, res);
419
429
  };
420
430
 
421
- // Mount MCP handlers at both "/" and "/mcp"
422
- // "/" (Claude.ai): strict OAuthrequires Bearer token
423
- // "/mcp" (ChatGPT): optional auth — accepts OAuth OR ateam_auth tool
431
+ // Mount MCP handlers at both "/" (Claude.ai) and "/mcp" (ChatGPT).
432
+ // ONE auth rule for both see mcpAuth above for why the split was removed.
424
433
  for (const path of MCP_PATHS) {
425
- const auth = path === "/" ? mcpAuthStrict : mcpAuthOptional;
426
- app.post(path, ...auth, mcpPost);
427
- app.get(path, ...auth, mcpGet);
428
- app.delete(path, ...auth, mcpDelete);
434
+ app.post(path, ...mcpAuth, mcpPost);
435
+ app.get(path, ...mcpAuth, mcpGet);
436
+ app.delete(path, ...mcpAuth, mcpDelete);
429
437
  }
430
438
 
431
439
  // ─── Catch-all: log unhandled requests ──────────────────────────