@protobase/server 0.36.0 → 0.37.0
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.
- package/dist/admin-options.d.ts +7 -0
- package/dist/aggregate-groups.js +1 -1
- package/dist/aggregate-service.js +3 -3
- package/dist/aggregate-splits.js +1 -1
- package/dist/assistant/built-in-assistant.js +3 -11
- package/dist/assistant/checked-tools.js +14 -0
- package/dist/assistant/query-tools.js +9 -0
- package/dist/assistant/readable-resources.d.ts +7 -0
- package/dist/assistant/readable-resources.js +13 -0
- package/dist/assistant/record-tools.d.ts +11 -0
- package/dist/assistant/record-tools.js +140 -0
- package/dist/assistant/records.d.ts +27 -0
- package/dist/assistant/records.js +4 -0
- package/dist/assistant/tools.d.ts +19 -2
- package/dist/assistant/turn.d.ts +3 -1
- package/dist/assistant/turn.js +6 -1
- package/dist/comments/mention-job.d.ts +15 -2
- package/dist/comments/mentionable.js +1 -1
- package/dist/comments/read-comments.js +1 -1
- package/dist/create-admin.js +36 -1
- package/dist/deps.d.ts +79 -10
- package/dist/encryption/apply.js +1 -1
- package/dist/encryption/binding.d.ts +1 -1
- package/dist/encryption/keyring.d.ts +12 -0
- package/dist/encryption/runtime.d.ts +8 -1
- package/dist/encryption/scan.d.ts +1 -1
- package/dist/encryption/status.d.ts +1 -1
- package/dist/encryption/status.js +1 -1
- package/dist/files/cleanup-runner.d.ts +5 -0
- package/dist/files/runtime.d.ts +28 -3
- package/dist/files/signer.d.ts +7 -0
- package/dist/functions/records.d.ts +2 -29
- package/dist/functions/records.js +11 -20
- package/dist/history/read-history.js +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.js +9 -1
- package/dist/list-service.js +3 -3
- package/dist/map-service.js +1 -1
- package/dist/mcp/mcp-authenticator.js +14 -0
- package/dist/mcp/mcp-context.d.ts +11 -0
- package/dist/mcp/mcp-context.js +16 -0
- package/dist/mcp/mcp-gate.d.ts +19 -0
- package/dist/mcp/mcp-gate.js +52 -0
- package/dist/mcp/mcp-handler.d.ts +15 -0
- package/dist/mcp/mcp-handler.js +22 -0
- package/dist/mcp/mcp-routes.d.ts +12 -0
- package/dist/mcp/mcp-routes.js +15 -0
- package/dist/mcp/mcp-server.d.ts +19 -0
- package/dist/mcp/mcp-server.js +35 -0
- package/dist/mcp/mcp-tools.d.ts +12 -0
- package/dist/mcp/mcp-tools.js +8 -0
- package/dist/meta.d.ts +76 -0
- package/dist/records.js +1 -1
- package/dist/registry.d.ts +22 -2
- package/dist/request-access.d.ts +2 -2
- package/dist/routes/collection.js +1 -1
- package/dist/routes/record.js +1 -1
- package/dist/row-permissions.js +1 -1
- package/dist/scan-guard.d.ts +21 -3
- package/dist/sql-parts.js +1 -1
- package/dist/write-shared.js +1 -1
- package/package.json +5 -4
package/dist/encryption/apply.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { columnId, tableId } from "../sql-parts.js";
|
|
1
2
|
import { bindingOf, movedBinding } from "./binding.js";
|
|
2
3
|
import { Sealed, sealText } from "./envelope-seal.js";
|
|
3
|
-
import { columnId, tableId } from "../sql-parts.js";
|
|
4
4
|
import { cascadingKeys } from "./cascading-keys.js";
|
|
5
5
|
import { captureOff } from "./capture-off.js";
|
|
6
6
|
import { scrubHistory, scrubOutbox } from "./remnants.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import "../types.js";
|
|
2
|
-
import { ResourceModel } from "@protobase/schema";
|
|
2
|
+
import { FieldModel, ResourceModel } from "@protobase/schema";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/encryption/keyring.d.ts
|
|
2
|
+
/** One root key, as the AES key derived from it and the id envelopes name it by. */
|
|
3
|
+
export type EncryptionKey = {
|
|
4
|
+
id: string;
|
|
5
|
+
aes: Buffer;
|
|
6
|
+
};
|
|
7
|
+
/** The key new values are sealed with, and every key a stored value may name, by id. */
|
|
8
|
+
export type Keyring = {
|
|
9
|
+
current: EncryptionKey;
|
|
10
|
+
byId: ReadonlyMap<string, EncryptionKey>;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Keyring } from "./keyring.js";
|
|
2
|
+
import { ResourceModel } from "@protobase/schema";
|
|
3
|
+
//#region src/encryption/runtime.d.ts
|
|
4
|
+
/** The keys encrypted fields are sealed and opened with, when a resource has one. */
|
|
5
|
+
export type EncryptionRuntime = {
|
|
6
|
+
keyring: Keyring;
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
@@ -3,7 +3,7 @@ import "./binding.js";
|
|
|
3
3
|
import { CascadingKey } from "./cascading-keys.js";
|
|
4
4
|
import { UnreadableKind } from "./envelope-open.js";
|
|
5
5
|
import "./scan.js";
|
|
6
|
-
import "@protobase/schema";
|
|
6
|
+
import { FieldModel } from "@protobase/schema";
|
|
7
7
|
import { Db } from "@protobase/query";
|
|
8
8
|
//#region src/encryption/status.d.ts
|
|
9
9
|
/** A stored value that does not open, by its record's key: never the value. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { columnId, tableId } from "../sql-parts.js";
|
|
1
2
|
import { bindingOf } from "./binding.js";
|
|
2
3
|
import { envelopePrefix } from "./envelope-seal.js";
|
|
3
|
-
import { columnId, tableId } from "../sql-parts.js";
|
|
4
4
|
import { UnreadableValue, openText } from "./envelope-open.js";
|
|
5
5
|
import { cascadingKeys } from "./cascading-keys.js";
|
|
6
6
|
import { historyRemnants, outboxRemnants } from "./remnants.js";
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ResourceModel } from "@protobase/schema";
|
|
2
2
|
import { Db } from "@protobase/query";
|
|
3
3
|
//#region src/files/cleanup-runner.d.ts
|
|
4
|
+
/** A column that holds file values, read without any resource's filters: soft-deleted rows still reference their files. */
|
|
5
|
+
export type FileColumn = {
|
|
6
|
+
table: ResourceModel['table'];
|
|
7
|
+
column: string;
|
|
8
|
+
};
|
|
4
9
|
export type CleanupReport = {
|
|
5
10
|
deleted: string[];
|
|
6
11
|
kept: string[];
|
package/dist/files/runtime.d.ts
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
|
-
import "./images.js";
|
|
1
|
+
import { Sharp } from "./images.js";
|
|
2
|
+
import { FileProvider } from "./store.js";
|
|
2
3
|
import "./options.js";
|
|
3
|
-
import "./cleanup-
|
|
4
|
+
import { CleanupSchedule } from "./cleanup-schedule.js";
|
|
5
|
+
import { FileColumn } from "./cleanup-runner.js";
|
|
6
|
+
import { Signer } from "./signer.js";
|
|
4
7
|
import { ResourceModel } from "@protobase/schema";
|
|
5
|
-
import { Db } from "@protobase/query";
|
|
8
|
+
import { Db } from "@protobase/query";
|
|
9
|
+
//#region src/files/runtime.d.ts
|
|
10
|
+
/** Everything the API needs to handle files, built once at startup. */
|
|
11
|
+
export type FilesRuntime = {
|
|
12
|
+
providers: Record<string, FileProvider>;
|
|
13
|
+
signer: Signer;
|
|
14
|
+
schedule: CleanupSchedule;
|
|
15
|
+
/** Milliseconds a provider keeps bytes after their last reference. */
|
|
16
|
+
retention: (provider: string) => number;
|
|
17
|
+
/** The path downloads are served under: `<systemPath>/files`. */
|
|
18
|
+
path: string;
|
|
19
|
+
columns: FileColumn[];
|
|
20
|
+
/** Makes image variants and placeholders; set when a field declares them. */
|
|
21
|
+
sharp?: Sharp;
|
|
22
|
+
/** The hosts whose images are drawn with the page's referrer, besides the app's own (see `trustedImageHosts`). */
|
|
23
|
+
trustedHosts: string[];
|
|
24
|
+
/** The provider `/api/sb/storage/v1` keeps object bytes in and the largest object it takes, when the app serves it. */
|
|
25
|
+
storage?: {
|
|
26
|
+
provider: string;
|
|
27
|
+
maxBytes: number;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/files/signer.d.ts
|
|
2
|
+
/** HMAC-SHA256 signatures over JSON values, under a key derived from the files secret by HKDF; one purpose never verifies as another. */
|
|
3
|
+
export type Signer = {
|
|
4
|
+
sign(purpose: string, parts: unknown[]): Promise<string>;
|
|
5
|
+
verify(purpose: string, parts: unknown[], signature: string): Promise<boolean>;
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
@@ -1,40 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../types.js";
|
|
2
2
|
import "../deps.js";
|
|
3
|
-
import { RecordKeyInput, ToolRecord, ToolRecords } from "../assistant/records.js";
|
|
3
|
+
import { ListParams, RecordKeyInput, RecordPage, ToolRecord, ToolRecords } from "../assistant/records.js";
|
|
4
4
|
//#region src/functions/records.d.ts
|
|
5
|
-
/** The list parameters of the REST API (AIP-132), as values rather than query text. */
|
|
6
|
-
export type ListParams = {
|
|
7
|
-
filter?: string;
|
|
8
|
-
order_by?: string;
|
|
9
|
-
page_size?: number;
|
|
10
|
-
page_token?: string;
|
|
11
|
-
fields?: string[];
|
|
12
|
-
count?: 'exact';
|
|
13
|
-
show_deleted?: boolean;
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* A page of records as the REST API lists it: each item with its `etag` and, unless the resource opts out, whether the
|
|
17
|
-
* caller may update and delete it; and the token of the next page, empty on the last.
|
|
18
|
-
*/
|
|
19
|
-
export type RecordPage = {
|
|
20
|
-
items: Array<Row & {
|
|
21
|
-
etag?: string;
|
|
22
|
-
permissions?: {
|
|
23
|
-
update: boolean;
|
|
24
|
-
delete: boolean;
|
|
25
|
-
};
|
|
26
|
-
}>;
|
|
27
|
-
next_page_token: string;
|
|
28
|
-
total_size_estimate: number;
|
|
29
|
-
total_size?: number;
|
|
30
|
-
};
|
|
31
5
|
/**
|
|
32
6
|
* The app's resources as the caller: their access rules, row filters, tenant scope, validation and write hooks apply as
|
|
33
7
|
* in the REST API. A refusal or a missing record rejects with an `HttpProblem`, which becomes the function's response
|
|
34
8
|
* when it is not caught.
|
|
35
9
|
*/
|
|
36
10
|
export type FunctionRecords = ToolRecords & {
|
|
37
|
-
list: (resource: string, params?: ListParams) => Promise<RecordPage>;
|
|
38
11
|
/** With `etag`, fails with 412 when the record changed since it was read. Resolves to the record as it was. */
|
|
39
12
|
delete: (resource: string, key: RecordKeyInput, options?: {
|
|
40
13
|
etag?: string;
|
|
@@ -2,30 +2,21 @@ import { notFound } from "../problem.js";
|
|
|
2
2
|
import { decodeKeyText } from "../key.js";
|
|
3
3
|
import { runWrite } from "../write-pipeline.js";
|
|
4
4
|
import { assistantRecords } from "../assistant/records.js";
|
|
5
|
-
import { listRecords } from "../list-service.js";
|
|
6
5
|
import { encodeKey } from "@protobase/schema/internal";
|
|
7
6
|
//#region src/functions/records.ts
|
|
8
|
-
const filterLength = 2e5;
|
|
9
7
|
/** `FunctionRecords` over the admin's resources for `session`. */
|
|
10
|
-
const callerRecords = (deps, session) => {
|
|
11
|
-
|
|
8
|
+
const callerRecords = (deps, session) => ({
|
|
9
|
+
...assistantRecords(deps, session),
|
|
10
|
+
delete: async (resource, input, { etag } = {}) => {
|
|
12
11
|
const entry = deps.registry.find(resource);
|
|
13
12
|
if (!entry) throw notFound(`There is no resource "${resource}"`);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return runWrite(deps, entry, session, {
|
|
23
|
-
operation: "delete",
|
|
24
|
-
key,
|
|
25
|
-
ifMatch: etag ?? "*"
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
};
|
|
13
|
+
const key = decodeKeyText(entry, Array.isArray(input) ? encodeKey(input) : String(input));
|
|
14
|
+
return runWrite(deps, entry, session, {
|
|
15
|
+
operation: "delete",
|
|
16
|
+
key,
|
|
17
|
+
ifMatch: etag ?? "*"
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
30
21
|
//#endregion
|
|
31
22
|
export { callerRecords };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { notFound } from "../problem.js";
|
|
2
2
|
import { tenantScope } from "../tenant.js";
|
|
3
3
|
import { requestAccess, requireOperation } from "../request-access.js";
|
|
4
|
+
import { parseParams } from "../params.js";
|
|
4
5
|
import { fetchReadable } from "../fetch-readable.js";
|
|
5
6
|
import { readTransaction } from "../transactions.js";
|
|
6
7
|
import { quoteIdent } from "../changes/capture-sql.js";
|
|
7
|
-
import { parseParams } from "../params.js";
|
|
8
8
|
import { encodeKey } from "@protobase/schema/internal";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { sql } from "kysely";
|
package/dist/index.d.ts
CHANGED
|
@@ -34,14 +34,14 @@ import { MapOptions, MapSettings, mapSettings, mapStyleUrl, mapStyleVariable } f
|
|
|
34
34
|
import { PluginOption, PluginRef, beforeSignInPluginsVariable, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable } from "./plugins/plugin-settings.js";
|
|
35
35
|
import { ResourceSource, configExports } from "./resource-source.js";
|
|
36
36
|
import { SourceOption, SourceRef, checkSourceNames, sourceOptions, sourcesFor, sourcesVariable } from "./sources/source-settings.js";
|
|
37
|
-
import { RecordKeyInput, ToolRecord, ToolRecords } from "./assistant/records.js";
|
|
38
|
-
import { FunctionRecords
|
|
37
|
+
import { ListParams, RecordKeyInput, RecordPage, ToolRecord, ToolRecords } from "./assistant/records.js";
|
|
38
|
+
import { FunctionRecords } from "./functions/records.js";
|
|
39
39
|
import { ApiFunction, CorsOptions, FunctionApp, FunctionCaller, FunctionContext, FunctionHandler, FunctionOptions, FunctionSource, KeyFunctionContext, ProtectedFunctionOptions, PublicFunctionContext, PublicFunctionHandler, PublicFunctionOptions, defineFunction } from "./functions/define-function.js";
|
|
40
40
|
import { CorsOrigins } from "./api-cors.js";
|
|
41
41
|
import { ConversationRecord, ConversationStore } from "./assistant/conversation-store.js";
|
|
42
42
|
import { Conversation, ConversationsOptions, conversationKey, createConversations } from "./assistant/conversations.js";
|
|
43
43
|
import { ApprovalAnswer, ApprovalRequest, requestApproval } from "./assistant/approval.js";
|
|
44
|
-
import { AssistantTool, ToolContext, defineTool } from "./assistant/tools.js";
|
|
44
|
+
import { AssistantTool, ReadableResources, ToolAnnotations, ToolContext, defineTool } from "./assistant/tools.js";
|
|
45
45
|
import { AssistantOptions, AssistantSettings, assistantRoles, assistantSettings, assistantVariables, seesAssistant } from "./assistant/assistant-settings.js";
|
|
46
46
|
import { RuntimeOptions, runtimeUrl, runtimeVariable, seesRuntime } from "./runtime/runtime-settings.js";
|
|
47
47
|
import { AdminOptions } from "./admin-options.js";
|
|
@@ -83,9 +83,17 @@ import { AssistantBackend, assistantProtocolRoutes } from "./assistant/protocol-
|
|
|
83
83
|
import { fileConversationStore } from "./assistant/file-conversation-store.js";
|
|
84
84
|
import { withCacheBreakpoints } from "./assistant/cache-breakpoints.js";
|
|
85
85
|
import { TurnOptions, runTurn } from "./assistant/turn.js";
|
|
86
|
+
import { readableResources } from "./assistant/readable-resources.js";
|
|
86
87
|
import { WidgetOptions, maxWidgetPropsBytes, widget } from "./assistant/widget.js";
|
|
87
88
|
import { QueryOptions, QueryResult, runReadOnlyQuery, runReadWriteQuery } from "./assistant/run-query.js";
|
|
88
89
|
import { readOnlyQueryTool, readWriteQueryTool } from "./assistant/query-tools.js";
|
|
90
|
+
import { getRecordTool, listRecordsTool, listResourcesTool, readRecordTools } from "./assistant/record-tools.js";
|
|
91
|
+
import { McpServerInput, mcpServer } from "./mcp/mcp-server.js";
|
|
92
|
+
import { McpToolsInput, mcpTools } from "./mcp/mcp-tools.js";
|
|
93
|
+
import { McpGateInput, mcpGate, sessionOf } from "./mcp/mcp-gate.js";
|
|
94
|
+
import { McpHandlerInput, mcpHandler } from "./mcp/mcp-handler.js";
|
|
95
|
+
import { McpRoutesInput, mcpRoutes } from "./mcp/mcp-routes.js";
|
|
96
|
+
import { mcpToolContext } from "./mcp/mcp-context.js";
|
|
89
97
|
import { ErrorReporter } from "./error-reporting/sentry-reporter.js";
|
|
90
98
|
import { startErrorReporting } from "./error-reporting/error-reporter.js";
|
|
91
99
|
import { FunctionEnv, PublicFunctionEnv, functionApp } from "./functions/function-app.js";
|
|
@@ -112,4 +120,4 @@ import { isSchedule } from "./jobs/schedule.js";
|
|
|
112
120
|
import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/runtime.js";
|
|
113
121
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
114
122
|
import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
|
|
115
|
-
export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApiKeys, type ApiKeysOptions, type AppIcons, type AppIdentity, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type Caller, type CallerOptions, type CapturedRow, type CascadingKey, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentUsers, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryOptions, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, type MemberInput, MissingCredentials, type MobileConfig, ModelError, type ModelSettings, type NewOrganization, type NewUser, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProjectConfig, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type QueryOptions, type QueryResult, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordKeyInput, type RecordPage, type RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoreFileInput, type StoredMember, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type User, type UserCreatedHook, type ViewSource, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, backgroundSettled, badRequest, beforeSignInPluginsVariable, betterAuthAuthenticator, betterAuthTokens, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createUser, defaultAppName, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, goTruePath, handleDroppedConnections, hasUsers, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, realtimeLimits, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, waitUntil, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
|
|
123
|
+
export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApiKeys, type ApiKeysOptions, type AppIcons, type AppIdentity, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type Caller, type CallerOptions, type CapturedRow, type CascadingKey, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentUsers, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryOptions, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, type McpGateInput, type McpHandlerInput, type McpRoutesInput, type McpServerInput, type McpToolsInput, type MemberInput, MissingCredentials, type MobileConfig, ModelError, type ModelSettings, type NewOrganization, type NewUser, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProjectConfig, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type QueryOptions, type QueryResult, type ReadableResources, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordKeyInput, type RecordPage, type RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoreFileInput, type StoredMember, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolAnnotations, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type User, type UserCreatedHook, type ViewSource, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, backgroundSettled, badRequest, beforeSignInPluginsVariable, betterAuthAuthenticator, betterAuthTokens, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createUser, defaultAppName, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mcpGate, mcpHandler, mcpRoutes, mcpServer, mcpToolContext, mcpTools, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readWriteQueryTool, readableResources, realtimeLimits, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, sessionOf, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, waitUntil, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { assistantProtocolRoutes } from "./assistant/protocol-routes.js";
|
|
|
13
13
|
import { runReadOnlyQuery, runReadWriteQuery } from "./assistant/run-query.js";
|
|
14
14
|
import { defineTool } from "./assistant/tools.js";
|
|
15
15
|
import { readOnlyQueryTool, readWriteQueryTool } from "./assistant/query-tools.js";
|
|
16
|
+
import { readableResources } from "./assistant/readable-resources.js";
|
|
16
17
|
import { requestApproval } from "./assistant/approval.js";
|
|
17
18
|
import { withCacheBreakpoints } from "./assistant/cache-breakpoints.js";
|
|
18
19
|
import { runTurn } from "./assistant/turn.js";
|
|
@@ -32,6 +33,13 @@ import { passwordLength } from "./better-auth/new-account-password.js";
|
|
|
32
33
|
import { readOperatorSettings } from "./better-auth/operator-provider.js";
|
|
33
34
|
import { readPlatformSignIn } from "./better-auth/platform-sign-in.js";
|
|
34
35
|
import { createAuth, normalizeRoles } from "./better-auth/create-auth.js";
|
|
36
|
+
import { mcpToolContext } from "./mcp/mcp-context.js";
|
|
37
|
+
import { mcpGate, sessionOf } from "./mcp/mcp-gate.js";
|
|
38
|
+
import { mcpHandler } from "./mcp/mcp-handler.js";
|
|
39
|
+
import { mcpRoutes } from "./mcp/mcp-routes.js";
|
|
40
|
+
import { mcpServer } from "./mcp/mcp-server.js";
|
|
41
|
+
import { getRecordTool, listRecordsTool, listResourcesTool, readRecordTools } from "./assistant/record-tools.js";
|
|
42
|
+
import { mcpTools } from "./mcp/mcp-tools.js";
|
|
35
43
|
import { addAppRoleToOwners, addMember, createOrganization, listOrganizations, removeMember, setMemberRoles } from "./better-auth/organizations/host.js";
|
|
36
44
|
import { createUser, deleteUser, hasUsers, listUsers, roleChoices, setUserBanned, setUserRole } from "./better-auth/users.js";
|
|
37
45
|
import { changesMigration, checkChanges, migrationCommand } from "./changes/capture-schema.js";
|
|
@@ -83,4 +91,4 @@ import { aspectRatio, fileSize, fileType, imageSize, processor } from "./files/p
|
|
|
83
91
|
import { defineEmail } from "./mail/define-email.js";
|
|
84
92
|
import { startJobs } from "./jobs/runtime.js";
|
|
85
93
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
86
|
-
export { FatalJobError, HttpProblem, MissingCredentials, ModelError, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, backgroundSettled, badRequest, beforeSignInPluginsVariable, betterAuthAuthenticator, betterAuthTokens, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createUser, defaultAppName, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, goTruePath, handleDroppedConnections, hasUsers, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, realtimeLimits, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, waitUntil, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
|
|
94
|
+
export { FatalJobError, HttpProblem, MissingCredentials, ModelError, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, backgroundSettled, badRequest, beforeSignInPluginsVariable, betterAuthAuthenticator, betterAuthTokens, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createUser, defaultAppName, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mcpGate, mcpHandler, mcpRoutes, mcpServer, mcpToolContext, mcpTools, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readWriteQueryTool, readableResources, realtimeLimits, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, sessionOf, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, waitUntil, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
|
package/dist/list-service.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { checkedFilter, checkedSort } from "./filter-input.js";
|
|
2
2
|
import { readScope, requestAccess, requireOperation } from "./request-access.js";
|
|
3
|
-
import {
|
|
3
|
+
import { deletedRows, listParams, pageSizeOf, parseParams, seekParams, selectedFields } from "./params.js";
|
|
4
4
|
import { etagAlias } from "./sql-parts.js";
|
|
5
5
|
import { etagOf } from "./etag.js";
|
|
6
|
+
import { presentFiles } from "./files/present.js";
|
|
6
7
|
import { exposeRow, pickFields } from "./rows.js";
|
|
7
8
|
import { rowPermissions } from "./row-permissions.js";
|
|
8
|
-
import { readTransaction } from "./transactions.js";
|
|
9
|
-
import { deletedRows, listParams, pageSizeOf, parseParams, seekParams, selectedFields } from "./params.js";
|
|
10
9
|
import { labelRequests, relatedLabels } from "./related-labels.js";
|
|
10
|
+
import { readTransaction } from "./transactions.js";
|
|
11
11
|
import { photosRequest, recordPhotos } from "./list-photos.js";
|
|
12
12
|
import { countUpTo, estimateCount, listQuery, seekToPosition } from "@protobase/query";
|
|
13
13
|
//#region src/list-service.ts
|
package/dist/map-service.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { checkedFilter } from "./filter-input.js";
|
|
2
2
|
import { readScope, requestAccess, requireOperation } from "./request-access.js";
|
|
3
|
-
import { readTransaction } from "./transactions.js";
|
|
4
3
|
import { parseParams, selectedFields } from "./params.js";
|
|
5
4
|
import { labelRequests } from "./related-labels.js";
|
|
5
|
+
import { readTransaction } from "./transactions.js";
|
|
6
6
|
import { photosRequest } from "./list-photos.js";
|
|
7
7
|
import { listRecords } from "./list-service.js";
|
|
8
8
|
import { z } from "zod";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/mcp/mcp-authenticator.ts
|
|
2
|
+
const hasAudiences = (authenticate) => typeof authenticate.forAudience === "function";
|
|
3
|
+
/**
|
|
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.
|
|
6
|
+
*/
|
|
7
|
+
const mcpAuthenticator = (authenticate, mcp, options) => {
|
|
8
|
+
if (options && !mcp) throw new Error("options.mcp needs createAuth({ mcp }) passed as auth");
|
|
9
|
+
if (!mcp) return void 0;
|
|
10
|
+
if (!hasAudiences(authenticate)) throw new Error("MCP needs authenticate from betterAuthAuthenticator, whose forAudience verifies the MCP tokens");
|
|
11
|
+
return authenticate.forAudience(mcp.resource);
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { mcpAuthenticator };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Session } from "../types.js";
|
|
2
|
+
import { Deps } from "../deps.js";
|
|
3
|
+
import { ToolContext } from "../assistant/tools.js";
|
|
4
|
+
import { Meta } from "../meta.js";
|
|
5
|
+
//#region src/mcp/mcp-context.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* What tools get over MCP for `session`: the records and resources it may read, under its access rules. Nothing shows
|
|
8
|
+
* beside a tool's result, and asking for approval fails: no read tool asks, and approval over MCP comes with writes.
|
|
9
|
+
*/
|
|
10
|
+
export declare const mcpToolContext: (deps: Deps, meta: Pick<Meta, "forCaller">, session: Session) => ToolContext;
|
|
11
|
+
//#endregion
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { assistantRecords } from "../assistant/records.js";
|
|
2
|
+
import { readableResources } from "../assistant/readable-resources.js";
|
|
3
|
+
//#region src/mcp/mcp-context.ts
|
|
4
|
+
/**
|
|
5
|
+
* What tools get over MCP for `session`: the records and resources it may read, under its access rules. Nothing shows
|
|
6
|
+
* beside a tool's result, and asking for approval fails: no read tool asks, and approval over MCP comes with writes.
|
|
7
|
+
*/
|
|
8
|
+
const mcpToolContext = (deps, meta, session) => ({
|
|
9
|
+
session,
|
|
10
|
+
records: assistantRecords(deps, session),
|
|
11
|
+
resources: () => readableResources(meta, session),
|
|
12
|
+
show: () => {},
|
|
13
|
+
approve: () => Promise.reject(/* @__PURE__ */ new Error("Not implemented: MCP tools cannot ask for approval yet"))
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { mcpToolContext };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Authenticator, Session } from "../types.js";
|
|
2
|
+
import { AuthInfo } from "@modelcontextprotocol/server";
|
|
3
|
+
//#region src/mcp/mcp-gate.d.ts
|
|
4
|
+
export type McpGateInput = {
|
|
5
|
+
/** Verifies the request's MCP access token, its audience and any DPoP proof, such as `betterAuthAuthenticator(...).forAudience(resource)`. */
|
|
6
|
+
authenticate: Authenticator;
|
|
7
|
+
/** The endpoint's URL, the audience its tokens carry. */
|
|
8
|
+
resource: string;
|
|
9
|
+
/** The scope a token needs. */
|
|
10
|
+
scope: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Admits a request whose MCP access token `authenticate` verifies, with `scope`: resolves to its `AuthInfo`, carrying
|
|
14
|
+
* the session (see `sessionOf`), or to the 401 or 403 answer whose challenge names the resource's metadata document.
|
|
15
|
+
*/
|
|
16
|
+
export declare const mcpGate: ({ authenticate, resource, scope }: McpGateInput) => (request: Request) => Promise<AuthInfo | Response>;
|
|
17
|
+
/** The session `mcpGate` admitted the request with. */
|
|
18
|
+
export declare const sessionOf: (authInfo: AuthInfo | undefined) => Session;
|
|
19
|
+
//#endregion
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { HttpProblem } from "../problem.js";
|
|
2
|
+
import { decodeJwt } from "jose";
|
|
3
|
+
import { OAuthError, OAuthErrorCode, getOAuthProtectedResourceMetadataUrl, requireBearerAuth } from "@modelcontextprotocol/server";
|
|
4
|
+
//#region src/mcp/mcp-gate.ts
|
|
5
|
+
const bearerOnly = (request) => {
|
|
6
|
+
const authorization = request.headers.get("authorization");
|
|
7
|
+
const headers = new Headers();
|
|
8
|
+
if (authorization) headers.set("authorization", authorization.replace(/^DPoP /i, "Bearer "));
|
|
9
|
+
return new Request(request.url, { headers });
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Admits a request whose MCP access token `authenticate` verifies, with `scope`: resolves to its `AuthInfo`, carrying
|
|
13
|
+
* the session (see `sessionOf`), or to the 401 or 403 answer whose challenge names the resource's metadata document.
|
|
14
|
+
*/
|
|
15
|
+
const mcpGate = ({ authenticate, resource, scope }) => {
|
|
16
|
+
const resourceUrl = new URL(resource);
|
|
17
|
+
const resourceMetadataUrl = getOAuthProtectedResourceMetadataUrl(resourceUrl);
|
|
18
|
+
return async (request) => {
|
|
19
|
+
let unexpected;
|
|
20
|
+
const answer = await requireBearerAuth({
|
|
21
|
+
verifier: { verifyAccessToken: async (token) => {
|
|
22
|
+
const session = await Promise.resolve(authenticate(request)).catch((error) => {
|
|
23
|
+
if (error instanceof HttpProblem && error.status === 401) throw new OAuthError(OAuthErrorCode.InvalidToken, error.detail);
|
|
24
|
+
unexpected = { error };
|
|
25
|
+
throw error;
|
|
26
|
+
});
|
|
27
|
+
if (!session.client) throw new OAuthError(OAuthErrorCode.InvalidToken, "The token was not issued to an MCP client");
|
|
28
|
+
return {
|
|
29
|
+
token,
|
|
30
|
+
clientId: session.client.id,
|
|
31
|
+
scopes: session.client.scopes,
|
|
32
|
+
expiresAt: decodeJwt(token).exp,
|
|
33
|
+
resource: resourceUrl,
|
|
34
|
+
extra: { session }
|
|
35
|
+
};
|
|
36
|
+
} },
|
|
37
|
+
requiredScopes: [scope],
|
|
38
|
+
resourceMetadataUrl,
|
|
39
|
+
expectedResource: resourceUrl
|
|
40
|
+
})(bearerOnly(request));
|
|
41
|
+
if (unexpected) throw unexpected.error;
|
|
42
|
+
return answer;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** The session `mcpGate` admitted the request with. */
|
|
46
|
+
const sessionOf = (authInfo) => {
|
|
47
|
+
const session = authInfo?.extra?.session;
|
|
48
|
+
if (!session) throw new Error("The MCP request carries no session");
|
|
49
|
+
return session;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { mcpGate, sessionOf };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Session } from "../types.js";
|
|
2
|
+
import { McpGateInput } from "./mcp-gate.js";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
4
|
+
//#region src/mcp/mcp-handler.d.ts
|
|
5
|
+
export type McpHandlerInput = McpGateInput & {
|
|
6
|
+
/** Builds the server for the caller of one request, such as `mcpServer(...)` with tools of your own registered on it. */
|
|
7
|
+
server: (session: Session) => McpServer | Promise<McpServer>;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The MCP endpoint as a fetch handler: refuses a request addressed to another host than the resource's, then one
|
|
11
|
+
* without a valid token (see `mcpGate`), and serves the rest with the server `server` builds for its caller. Each
|
|
12
|
+
* request is served on its own, without a session: a GET or DELETE answers 405.
|
|
13
|
+
*/
|
|
14
|
+
export declare const mcpHandler: ({ server, ...gate }: McpHandlerInput) => (request: Request) => Promise<Response>;
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { mcpGate, sessionOf } from "./mcp-gate.js";
|
|
2
|
+
import { createMcpHandler, hostHeaderValidationResponse } from "@modelcontextprotocol/server";
|
|
3
|
+
//#region src/mcp/mcp-handler.ts
|
|
4
|
+
/**
|
|
5
|
+
* The MCP endpoint as a fetch handler: refuses a request addressed to another host than the resource's, then one
|
|
6
|
+
* without a valid token (see `mcpGate`), and serves the rest with the server `server` builds for its caller. Each
|
|
7
|
+
* request is served on its own, without a session: a GET or DELETE answers 405.
|
|
8
|
+
*/
|
|
9
|
+
const mcpHandler = ({ server, ...gate }) => {
|
|
10
|
+
const hostname = new URL(gate.resource).hostname;
|
|
11
|
+
const admit = mcpGate(gate);
|
|
12
|
+
const handler = createMcpHandler((context) => server(sessionOf(context.authInfo)), { legacy: "stateless" });
|
|
13
|
+
return async (request) => {
|
|
14
|
+
const wrongHost = hostHeaderValidationResponse(request, [hostname]);
|
|
15
|
+
if (wrongHost) return wrongHost;
|
|
16
|
+
const authInfo = await admit(request);
|
|
17
|
+
if (authInfo instanceof Response) return authInfo;
|
|
18
|
+
return handler.fetch(request, { authInfo });
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { mcpHandler };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Env, Hono } from "hono";
|
|
2
|
+
//#region src/mcp/mcp-routes.d.ts
|
|
3
|
+
export type McpRoutesInput = {
|
|
4
|
+
path: string;
|
|
5
|
+
handler: (request: Request) => Promise<Response>;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Serves the MCP endpoint at `path`, callable from any origin: a client in a browser sends its token, never cookies.
|
|
9
|
+
* A preflight gets back the headers it asks for, such as `authorization`, `dpop` and `mcp-protocol-version`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const mcpRoutes: <E extends Env>(app: Hono<E>, { path, handler }: McpRoutesInput) => void;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cors } from "hono/cors";
|
|
2
|
+
//#region src/mcp/mcp-routes.ts
|
|
3
|
+
/**
|
|
4
|
+
* Serves the MCP endpoint at `path`, callable from any origin: a client in a browser sends its token, never cookies.
|
|
5
|
+
* A preflight gets back the headers it asks for, such as `authorization`, `dpop` and `mcp-protocol-version`.
|
|
6
|
+
*/
|
|
7
|
+
const mcpRoutes = (app, { path, handler }) => {
|
|
8
|
+
app.use(path, cors({
|
|
9
|
+
origin: "*",
|
|
10
|
+
exposeHeaders: ["www-authenticate", "mcp-session-id"]
|
|
11
|
+
}));
|
|
12
|
+
app.all(path, (c) => handler(c.req.raw));
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { mcpRoutes };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AssistantTool, ToolContext } from "../assistant/tools.js";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
3
|
+
//#region src/mcp/mcp-server.d.ts
|
|
4
|
+
export type McpServerInput = {
|
|
5
|
+
/** The name, version and title the server tells clients when they connect. */
|
|
6
|
+
info: {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
};
|
|
11
|
+
tools: AssistantTool[];
|
|
12
|
+
/** What each tool gets as its context, for the caller of the request. */
|
|
13
|
+
context: ToolContext;
|
|
14
|
+
/** Gets the errors a tool throws, which the client only sees as a failure. */
|
|
15
|
+
report: (error: unknown) => void;
|
|
16
|
+
};
|
|
17
|
+
/** An MCP server offering `tools` as MCP tools, each with its JSON Schema, its hints, and the text it returns. */
|
|
18
|
+
export declare const mcpServer: ({ info, tools, context, report }: McpServerInput) => McpServer;
|
|
19
|
+
//#endregion
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { checkedTools } from "../assistant/checked-tools.js";
|
|
2
|
+
import { McpServer, fromJsonSchema } from "@modelcontextprotocol/server";
|
|
3
|
+
//#region src/mcp/mcp-server.ts
|
|
4
|
+
const failed = {
|
|
5
|
+
content: [{
|
|
6
|
+
type: "text",
|
|
7
|
+
text: "The server failed to answer."
|
|
8
|
+
}],
|
|
9
|
+
isError: true
|
|
10
|
+
};
|
|
11
|
+
/** An MCP server offering `tools` as MCP tools, each with its JSON Schema, its hints, and the text it returns. */
|
|
12
|
+
const mcpServer = ({ info, tools, context, report }) => {
|
|
13
|
+
const server = new McpServer(info);
|
|
14
|
+
for (const tool of checkedTools(tools)) {
|
|
15
|
+
const config = {
|
|
16
|
+
description: tool.description,
|
|
17
|
+
inputSchema: fromJsonSchema(tool.parameters),
|
|
18
|
+
...tool.annotations && { annotations: tool.annotations }
|
|
19
|
+
};
|
|
20
|
+
server.registerTool(tool.name, config, async (args) => {
|
|
21
|
+
try {
|
|
22
|
+
return { content: [{
|
|
23
|
+
type: "text",
|
|
24
|
+
text: await tool.run(args, context)
|
|
25
|
+
}] };
|
|
26
|
+
} catch (error) {
|
|
27
|
+
report(error);
|
|
28
|
+
return failed;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return server;
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { mcpServer };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Session } from "../types.js";
|
|
2
|
+
import { AssistantTool } from "../assistant/tools.js";
|
|
3
|
+
import { Db } from "@protobase/query";
|
|
4
|
+
//#region src/mcp/mcp-tools.d.ts
|
|
5
|
+
export type McpToolsInput = {
|
|
6
|
+
db: Db;
|
|
7
|
+
/** Offers `run_read_only_query` to callers who see the assistant (`admin` or `ai`); it reads outside the access rules. */
|
|
8
|
+
sql: boolean;
|
|
9
|
+
};
|
|
10
|
+
/** The default MCP tools for a caller: the record tools, and read-only SQL when `sql` is on and the caller sees the assistant. */
|
|
11
|
+
export declare const mcpTools: ({ db, sql }: McpToolsInput) => (session: Session) => AssistantTool[];
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { seesAssistant } from "../assistant/assistant-settings.js";
|
|
2
|
+
import { readOnlyQueryTool } from "../assistant/query-tools.js";
|
|
3
|
+
import { readRecordTools } from "../assistant/record-tools.js";
|
|
4
|
+
//#region src/mcp/mcp-tools.ts
|
|
5
|
+
/** The default MCP tools for a caller: the record tools, and read-only SQL when `sql` is on and the caller sees the assistant. */
|
|
6
|
+
const mcpTools = ({ db, sql }) => (session) => [...readRecordTools(), ...sql && seesAssistant(session.user.roles) ? [readOnlyQueryTool(db)] : []];
|
|
7
|
+
//#endregion
|
|
8
|
+
export { mcpTools };
|