@protobase/server 0.40.3 → 0.40.5

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.
@@ -55,10 +55,12 @@ export type AdminOptions = {
55
55
  /**
56
56
  * The MCP endpoint, on with `createAuth({ mcp })`. `sql: true` also offers admins and the `ai` role
57
57
  * `run_read_only_query`, which reads the whole database as the app's database role, outside the access rules.
58
+ * `false`: the host serves its own MCP endpoint at `auth.mcp.path`, in front of this app. This app then answers 404
59
+ * there and needs no `forAudience`, while the OAuth provider's discovery stays.
58
60
  */
59
61
  mcp?: {
60
62
  sql?: boolean;
61
- };
63
+ } | false;
62
64
  /**
63
65
  * The websites whose browser code may call the API (`/api/*` but `/api/auth/*`) besides the app's own origins (see
64
66
  * `createAuth`'s `origins`): a list of origins, or `*` for any. Defaults to the one the platform passes in
@@ -26,7 +26,7 @@ import { mcpDiscovery } from "./better-auth/mcp/discovery-routes.js";
26
26
  import { mcpAuthenticator } from "./mcp/mcp-authenticator.js";
27
27
  import { mcpToolContext } from "./mcp/mcp-context.js";
28
28
  import { mcpHandler } from "./mcp/mcp-handler.js";
29
- import { mcpRoutes } from "./mcp/mcp-routes.js";
29
+ import { closedMcpRoutes, mcpRoutes } from "./mcp/mcp-routes.js";
30
30
  import { mcpServer } from "./mcp/mcp-server.js";
31
31
  import { mcpTools } from "./mcp/mcp-tools.js";
32
32
  import { withoutSessionTokens } from "./better-auth/without-session-tokens.js";
@@ -294,10 +294,11 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
294
294
  }));
295
295
  }
296
296
  const report = options.onUnhandledError ?? ((error) => console.error(error));
297
- if (auth?.mcp && mcpAuthenticate) {
297
+ if (auth?.mcp && options.mcp === false) closedMcpRoutes(app, auth.mcp.path);
298
+ else if (auth?.mcp && mcpAuthenticate) {
298
299
  const tools = mcpTools({
299
300
  db,
300
- sql: options.mcp?.sql === true
301
+ sql: options.mcp !== false && options.mcp?.sql === true
301
302
  });
302
303
  const server = (session) => mcpServer({
303
304
  info: {
@@ -1,10 +1,14 @@
1
1
  //#region src/mcp/mcp-authenticator.ts
2
2
  const hasAudiences = (authenticate) => typeof authenticate.forAudience === "function";
3
+ const isMcpOptions = (options) => options === void 0 || options === false || typeof options === "object" && options !== null && !Array.isArray(options) && Object.entries(options).every(([name, value]) => name === "sql" && (value === void 0 || typeof value === "boolean"));
3
4
  /**
4
- * The authenticator of the MCP endpoint's tokens, when MCP is on (`createAuth({ mcp })`). Stops the server at startup
5
- * when `options.mcp` is set without MCP, or when `authenticate` cannot verify tokens for another audience.
5
+ * The authenticator of the MCP endpoint's tokens, when MCP is on (`createAuth({ mcp })`); none when the host serves its
6
+ * own (`options.mcp: false`). Stops the server at startup when `options.mcp` is neither `false` nor `{ sql?: boolean }`,
7
+ * when it is set without MCP, or when `authenticate` cannot verify tokens for another audience.
6
8
  */
7
9
  const mcpAuthenticator = (authenticate, mcp, options) => {
10
+ if (!isMcpOptions(options)) throw new Error("options.mcp takes false or { sql?: boolean }");
11
+ if (options === false) return void 0;
8
12
  if (options && !mcp) throw new Error("options.mcp needs createAuth({ mcp }) passed as auth");
9
13
  if (!mcp) return void 0;
10
14
  if (!hasAudiences(authenticate)) throw new Error("MCP needs authenticate from betterAuthAuthenticator, whose forAudience verifies the MCP tokens");
@@ -11,5 +11,14 @@ const mcpRoutes = (app, { path, handler }) => {
11
11
  }));
12
12
  app.all(path, (c) => handler(c.req.raw));
13
13
  };
14
+ /**
15
+ * Answers 404 at `path` and under it, to every method and before any token check, where the host serves its own MCP
16
+ * endpoint in front of this app. It answers itself rather than through `c.notFound()`, which a host mounting this app
17
+ * would answer with its own page.
18
+ */
19
+ const closedMcpRoutes = (app, path) => {
20
+ app.all(path, (c) => c.text("404 Not Found", 404));
21
+ app.all(`${path}/*`, (c) => c.text("404 Not Found", 404));
22
+ };
14
23
  //#endregion
15
- export { mcpRoutes };
24
+ export { closedMcpRoutes, mcpRoutes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.40.3",
3
+ "version": "0.40.5",
4
4
  "description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -36,9 +36,9 @@
36
36
  "@better-auth/passkey": "^1.7.12",
37
37
  "@better-auth/sso": "^1.7.12",
38
38
  "@modelcontextprotocol/server": "^2.3.1",
39
- "@protobase/layout": "0.40.3",
40
- "@protobase/query": "0.40.3",
41
- "@protobase/schema": "0.40.3",
39
+ "@protobase/layout": "0.40.5",
40
+ "@protobase/query": "0.40.5",
41
+ "@protobase/schema": "0.40.5",
42
42
  "@react-email/render": "^2.1.0",
43
43
  "@scalar/hono-api-reference": "^0.12.10",
44
44
  "@sentry/core": "^11.7.0",