@zenrows/mcp 1.1.2 → 1.1.4

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 +29 -3
  2. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -24,25 +24,51 @@ function extractApiKey(req) {
24
24
  return new URL(req.url).searchParams.get("apikey") ?? undefined;
25
25
  }
26
26
  const AUTH_SERVER = process.env.OAUTH_AUTH_SERVER ?? "https://app.zenrows.com";
27
+ const MCP_SERVER = process.env.MCP_SERVER ?? "https://mcp.zenrows.com";
28
+ app.get("/mcp/.well-known/oauth-authorization-server", (c) => c.redirect("/.well-known/oauth-authorization-server", 301));
29
+ // RFC 9728 — OAuth Protected Resource Metadata
30
+ // MCP clients fetch this first to discover the authorization server(s) for this resource.
31
+ app.get("/.well-known/oauth-protected-resource", (c) => c.json({
32
+ resource: MCP_SERVER,
33
+ authorization_servers: [MCP_SERVER],
34
+ bearer_methods_supported: ["header", "query"],
35
+ scopes_supported: [],
36
+ }));
37
+ // RFC 8414 — OAuth Authorization Server Metadata
38
+ // Issuer must match the URL of the server serving this document (MCP_SERVER, not AUTH_SERVER),
39
+ // because the MCP server acts as an authorization server proxy for client discovery purposes.
27
40
  app.get("/.well-known/oauth-authorization-server", (c) => c.json({
28
- issuer: AUTH_SERVER,
41
+ issuer: MCP_SERVER,
29
42
  authorization_endpoint: `${AUTH_SERVER}/oauth/mcp/authorize`,
30
43
  token_endpoint: `${AUTH_SERVER}/oauth/mcp/token`,
44
+ registration_endpoint: `${MCP_SERVER}/register`,
31
45
  response_types_supported: ["code"],
32
46
  grant_types_supported: ["authorization_code"],
33
47
  code_challenge_methods_supported: ["S256"],
34
48
  token_endpoint_auth_methods_supported: ["none"],
35
49
  }));
50
+ // RFC 7591 — Dynamic Client Registration
51
+ // MCP clients (Claude.ai, Cursor, etc.) register themselves before initiating OAuth.
52
+ // Since ZenRows API keys are the real auth mechanism, client registration is stateless —
53
+ // we echo back a stable client_id derived from the request (or the one the client provides).
54
+ app.post("/register", async (c) => {
55
+ const body = await c.req.json().catch(() => ({}));
56
+ return c.json({
57
+ client_id: body.client_id ?? crypto.randomUUID(),
58
+ client_id_issued_at: Math.floor(Date.now() / 1000),
59
+ ...body,
60
+ }, 201);
61
+ });
36
62
  app.all("/mcp", async (c) => {
37
63
  const apiKey = extractApiKey(c.req.raw);
38
64
  if (!apiKey) {
39
65
  return c.json({
40
66
  error: "Missing API key. Use Authorization: Bearer <key> header or ?apikey=<key> query param.",
41
67
  }, 401, {
42
- "WWW-Authenticate": `Bearer realm="${AUTH_SERVER}", resource_metadata="https://mcp.zenrows.com/.well-known/oauth-authorization-server"`,
68
+ "WWW-Authenticate": `Bearer realm="${AUTH_SERVER}", resource_metadata="${MCP_SERVER}/.well-known/oauth-protected-resource"`,
43
69
  // CloudFront strips WWW-Authenticate — add Link header as RFC 8615 fallback
44
70
  // so MCP clients can still discover the OAuth server
45
- "Link": `<https://mcp.zenrows.com/.well-known/oauth-authorization-server>; rel="oauth-authorization-server"`,
71
+ "Link": `<${MCP_SERVER}/.well-known/oauth-protected-resource>; rel="oauth-protected-resource"`,
46
72
  });
47
73
  }
48
74
  const transport = new WebStandardStreamableHTTPServerTransport({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenrows/mcp",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "ZenRows MCP server — Universal Scraper API for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {