@zenrows/mcp 2.2.2 → 2.2.3

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/dist/http.js +27 -2
  2. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -28,6 +28,27 @@ function extractApiKey(req) {
28
28
  }
29
29
  const AUTH_SERVER = process.env.OAUTH_AUTH_SERVER ?? "https://app.zenrows.com";
30
30
  const MCP_SERVER = process.env.MCP_SERVER ?? "https://mcp.zenrows.com";
31
+ /**
32
+ * The scope this resource issues, named after what it actually grants.
33
+ *
34
+ * The access token IS the account's Zenrows API key: the authorization server hands
35
+ * the key back at /oauth/mcp/token, and every tool here calls the API with it. So an
36
+ * approved client can do anything the key can do, and one scope named `api` is the
37
+ * whole truth.
38
+ *
39
+ * It used to be declared as `[]`, which is worse than saying nothing: an empty list
40
+ * reads to a least-privilege client as "this resource has no scopes", when what we
41
+ * meant was "we never wrote them down".
42
+ *
43
+ * Splitting this — reading a page under one scope, spending credits on a
44
+ * 100,000-URL batch under another — is not an edit to this array. The token would
45
+ * have to carry the grant, and today it cannot: it is an opaque API key, minted by
46
+ * app.zenrows.com, and a raw key pasted straight into the Authorization header is a
47
+ * supported way to connect. Until the token can say what it was granted, this list
48
+ * must not claim more than one, because a scope we do not enforce is a lie told to
49
+ * exactly the clients careful enough to read it.
50
+ */
51
+ const SCOPES_SUPPORTED = ["api"];
31
52
  app.get("/mcp/.well-known/oauth-authorization-server", (c) => c.redirect("/.well-known/oauth-authorization-server", 301));
32
53
  // RFC 9728 — OAuth Protected Resource Metadata
33
54
  // MCP clients fetch this first to discover the authorization server(s) for this resource.
@@ -35,7 +56,8 @@ app.get("/.well-known/oauth-protected-resource", (c) => c.json({
35
56
  resource: MCP_SERVER,
36
57
  authorization_servers: [MCP_SERVER],
37
58
  bearer_methods_supported: ["header", "query"],
38
- scopes_supported: [],
59
+ scopes_supported: SCOPES_SUPPORTED,
60
+ resource_documentation: "https://docs.zenrows.com",
39
61
  }));
40
62
  // RFC 8414 — OAuth Authorization Server Metadata
41
63
  // Issuer must match the URL of the server serving this document (MCP_SERVER, not AUTH_SERVER),
@@ -49,6 +71,7 @@ app.get("/.well-known/oauth-authorization-server", (c) => c.json({
49
71
  grant_types_supported: ["authorization_code"],
50
72
  code_challenge_methods_supported: ["S256"],
51
73
  token_endpoint_auth_methods_supported: ["none"],
74
+ scopes_supported: SCOPES_SUPPORTED,
52
75
  }));
53
76
  // MCP Server Card (SEP-2127 canonical + SEP-1649 legacy paths).
54
77
  // Lets agents discover this remote MCP before connecting.
@@ -135,7 +158,9 @@ app.all("/mcp", async (c) => {
135
158
  return c.json({
136
159
  error: "Missing API key. Use Authorization: Bearer <key> header or ?apikey=<key> query param.",
137
160
  }, 401, {
138
- "WWW-Authenticate": `Bearer realm="${AUTH_SERVER}", resource_metadata="${MCP_SERVER}/.well-known/oauth-protected-resource"`,
161
+ // RFC 6750: name the scope in the challenge too, so a client learns what it is
162
+ // being asked for without a second fetch of the metadata document.
163
+ "WWW-Authenticate": `Bearer realm="${AUTH_SERVER}", scope="${SCOPES_SUPPORTED.join(" ")}", resource_metadata="${MCP_SERVER}/.well-known/oauth-protected-resource"`,
139
164
  // CloudFront strips WWW-Authenticate — add Link header as RFC 8615 fallback
140
165
  // so MCP clients can still discover the OAuth server
141
166
  Link: `<${MCP_SERVER}/.well-known/oauth-protected-resource>; rel="oauth-protected-resource"`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenrows/mcp",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
4
4
  "description": "Zenrows MCP server — Fetch, Extract, Batch, and Browser Sessions for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {