@vectros-ai/mcp-server 0.5.2 → 0.6.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/CHANGELOG.md +66 -0
- package/README.md +17 -2
- package/dist/cli-http.js +388 -134
- package/dist/cli-http.js.map +1 -1
- package/dist/cli-http.mjs +388 -134
- package/dist/cli-http.mjs.map +1 -1
- package/dist/cli.js +388 -134
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +388 -134
- package/dist/cli.mjs.map +1 -1
- package/dist/index.js +388 -134
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +388 -134
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -520,10 +520,18 @@ var DocumentRequest;
|
|
|
520
520
|
Text: "TEXT",
|
|
521
521
|
None: "NONE"
|
|
522
522
|
};
|
|
523
|
+
DocumentRequest2.Status = {
|
|
524
|
+
Active: "ACTIVE",
|
|
525
|
+
Archived: "ARCHIVED"
|
|
526
|
+
};
|
|
523
527
|
})(DocumentRequest || (DocumentRequest = {}));
|
|
524
528
|
var DocumentResponse;
|
|
525
529
|
((DocumentResponse2) => {
|
|
526
530
|
DocumentResponse2.Status = {
|
|
531
|
+
Active: "ACTIVE",
|
|
532
|
+
Archived: "ARCHIVED"
|
|
533
|
+
};
|
|
534
|
+
DocumentResponse2.IndexStatus = {
|
|
527
535
|
PendingUpload: "PENDING_UPLOAD",
|
|
528
536
|
Uploaded: "UPLOADED",
|
|
529
537
|
Extracting: "EXTRACTING",
|
|
@@ -2877,7 +2885,7 @@ var AuthClient = class {
|
|
|
2877
2885
|
);
|
|
2878
2886
|
}
|
|
2879
2887
|
/**
|
|
2880
|
-
* Creates a new access profile under the given app context. This call is idempotent by `principalId`: if a profile with the same `principalId` already exists, the existing profile is returned (with status 200) instead of creating a duplicate. You must provide exactly one of `scopes` (an inline list of scopes) or `roleId` (a reference to a role); supplying both, or neither, is rejected. `identityOverrides` may set only `orgId` and `clientId`; any other key (including the account identifier or `userId`) is rejected. If you use a scoped credential, the profile's effective scopes may not exceed your own; a root API key (`sk_`) is exempt. Requires the `profiles:c` scope.
|
|
2888
|
+
* Creates a new access profile under the given app context. This call is idempotent by `principalId`: if a profile with the same `principalId` already exists, the existing profile is returned (with status 200) instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing profile was returned) tells the two apart. To overwrite an existing profile's `scopes`/`roleId`, `identityOverrides`, and `status` instead of returning it unchanged, set `?upsert=true` (this also requires the `profiles:u` scope). You must provide exactly one of `scopes` (an inline list of scopes) or `roleId` (a reference to a role); supplying both, or neither, is rejected. `identityOverrides` may set only `orgId` and `clientId`; any other key (including the account identifier or `userId`) is rejected. If you use a scoped credential, the profile's effective scopes may not exceed your own; a root API key (`sk_`) is exempt. Requires the `profiles:c` scope.
|
|
2881
2889
|
*
|
|
2882
2890
|
* @param {Vectros.CreateAccessProfileRequest} request
|
|
2883
2891
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -2899,7 +2907,10 @@ var AuthClient = class {
|
|
|
2899
2907
|
return HttpResponsePromise.fromPromise(this.__createAccessProfile(request, requestOptions));
|
|
2900
2908
|
}
|
|
2901
2909
|
async __createAccessProfile(request, requestOptions) {
|
|
2902
|
-
const { contextId, body: _body } = request;
|
|
2910
|
+
const { contextId, upsert, body: _body } = request;
|
|
2911
|
+
const _queryParams = {
|
|
2912
|
+
upsert
|
|
2913
|
+
};
|
|
2903
2914
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
2904
2915
|
const _headers = mergeHeaders(
|
|
2905
2916
|
_authRequest.headers,
|
|
@@ -2914,7 +2925,7 @@ var AuthClient = class {
|
|
|
2914
2925
|
method: "POST",
|
|
2915
2926
|
headers: _headers,
|
|
2916
2927
|
contentType: "application/json",
|
|
2917
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
2928
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
2918
2929
|
requestType: "json",
|
|
2919
2930
|
body: _body,
|
|
2920
2931
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -3009,9 +3020,9 @@ var AuthClient = class {
|
|
|
3009
3020
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/app-contexts");
|
|
3010
3021
|
}
|
|
3011
3022
|
/**
|
|
3012
|
-
* Creates a new app context. This call is idempotent by `contextId`: if an app context with the same `contextId` already exists, the existing app context is returned (with status 200) instead of creating a duplicate. The reserved `contextId` value `vectros-admin` cannot be created through this endpoint; it is provisioned automatically for your account. Requires the `app-contexts:c` scope.
|
|
3023
|
+
* Creates a new app context. This call is idempotent by `contextId`: if an app context with the same `contextId` already exists, the existing app context is returned (with status 200) instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing context was returned) tells the two apart. To overwrite an existing context's `name`/`description` instead of returning it unchanged, set `?upsert=true` (this also requires the `app-contexts:u` scope). The reserved `contextId` value `vectros-admin` cannot be created through this endpoint; it is provisioned automatically for your account. Requires the `app-contexts:c` scope.
|
|
3013
3024
|
*
|
|
3014
|
-
* @param {Vectros.
|
|
3025
|
+
* @param {Vectros.CreateAppContextRequest} request
|
|
3015
3026
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
3016
3027
|
*
|
|
3017
3028
|
* @throws {@link Vectros.BadRequestError}
|
|
@@ -3020,14 +3031,20 @@ var AuthClient = class {
|
|
|
3020
3031
|
*
|
|
3021
3032
|
* @example
|
|
3022
3033
|
* await client.auth.createAppContext({
|
|
3023
|
-
*
|
|
3024
|
-
*
|
|
3034
|
+
* body: {
|
|
3035
|
+
* contextId: "myapp",
|
|
3036
|
+
* name: "My Internal App"
|
|
3037
|
+
* }
|
|
3025
3038
|
* })
|
|
3026
3039
|
*/
|
|
3027
3040
|
createAppContext(request, requestOptions) {
|
|
3028
3041
|
return HttpResponsePromise.fromPromise(this.__createAppContext(request, requestOptions));
|
|
3029
3042
|
}
|
|
3030
3043
|
async __createAppContext(request, requestOptions) {
|
|
3044
|
+
const { upsert, body: _body } = request;
|
|
3045
|
+
const _queryParams = {
|
|
3046
|
+
upsert
|
|
3047
|
+
};
|
|
3031
3048
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
3032
3049
|
const _headers = mergeHeaders(
|
|
3033
3050
|
_authRequest.headers,
|
|
@@ -3042,9 +3059,9 @@ var AuthClient = class {
|
|
|
3042
3059
|
method: "POST",
|
|
3043
3060
|
headers: _headers,
|
|
3044
3061
|
contentType: "application/json",
|
|
3045
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
3062
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
3046
3063
|
requestType: "json",
|
|
3047
|
-
body:
|
|
3064
|
+
body: _body,
|
|
3048
3065
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
3049
3066
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
3050
3067
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -3140,7 +3157,7 @@ var AuthClient = class {
|
|
|
3140
3157
|
);
|
|
3141
3158
|
}
|
|
3142
3159
|
/**
|
|
3143
|
-
* Creates a new role under the given app context. This call is idempotent by `roleId`: if a role with the same `roleId` already exists, the existing role is returned (with status 200) instead of creating a duplicate. If you use a scoped credential, the role's scopes may not exceed your own; a root API key (`sk_`) is exempt. Requires the `profiles:c` scope.
|
|
3160
|
+
* Creates a new role under the given app context. This call is idempotent by `roleId`: if a role with the same `roleId` already exists, the existing role is returned (with status 200) instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing role was returned) tells the two apart. To overwrite an existing role's `name`/`description`/`scopes` instead of returning it unchanged, set `?upsert=true` (this also requires the `profiles:u` scope). If you use a scoped credential, the role's scopes may not exceed your own; a root API key (`sk_`) is exempt. Requires the `profiles:c` scope.
|
|
3144
3161
|
*
|
|
3145
3162
|
* @param {Vectros.CreateRoleRequest} request
|
|
3146
3163
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -3166,7 +3183,10 @@ var AuthClient = class {
|
|
|
3166
3183
|
return HttpResponsePromise.fromPromise(this.__createRole(request, requestOptions));
|
|
3167
3184
|
}
|
|
3168
3185
|
async __createRole(request, requestOptions) {
|
|
3169
|
-
const { contextId, body: _body } = request;
|
|
3186
|
+
const { contextId, upsert, body: _body } = request;
|
|
3187
|
+
const _queryParams = {
|
|
3188
|
+
upsert
|
|
3189
|
+
};
|
|
3170
3190
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
3171
3191
|
const _headers = mergeHeaders(
|
|
3172
3192
|
_authRequest.headers,
|
|
@@ -3181,7 +3201,7 @@ var AuthClient = class {
|
|
|
3181
3201
|
method: "POST",
|
|
3182
3202
|
headers: _headers,
|
|
3183
3203
|
contentType: "application/json",
|
|
3184
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
3204
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
3185
3205
|
requestType: "json",
|
|
3186
3206
|
body: _body,
|
|
3187
3207
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -4665,23 +4685,30 @@ var DocumentsClient = class {
|
|
|
4665
4685
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents");
|
|
4666
4686
|
}
|
|
4667
4687
|
/**
|
|
4668
|
-
* Creates a document from a raw text string and queues it for asynchronous indexing so it becomes searchable. Requires the `documents:c` scope.
|
|
4688
|
+
* Creates a document from a raw text string and queues it for asynchronous indexing so it becomes searchable. Optionally supply an `externalId` to make the create idempotent — if a document with the same `externalId` already exists in your context, that existing document is returned unchanged instead of a duplicate being created. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing document was returned) tells the two apart. To overwrite an existing document's content instead of returning it unchanged, set `?upsert=true` (this also requires the `documents:u` scope). Requires the `documents:c` scope.
|
|
4669
4689
|
*
|
|
4670
|
-
* @param {Vectros.
|
|
4690
|
+
* @param {Vectros.IngestDocumentRequest} request
|
|
4671
4691
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4672
4692
|
*
|
|
4673
4693
|
* @throws {@link Vectros.BadRequestError}
|
|
4694
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4674
4695
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
4675
4696
|
*
|
|
4676
4697
|
* @example
|
|
4677
4698
|
* await client.documents.ingestDocument({
|
|
4678
|
-
*
|
|
4699
|
+
* body: {
|
|
4700
|
+
* title: "Patient Intake Form \u2014 Jane Doe"
|
|
4701
|
+
* }
|
|
4679
4702
|
* })
|
|
4680
4703
|
*/
|
|
4681
4704
|
ingestDocument(request, requestOptions) {
|
|
4682
4705
|
return HttpResponsePromise.fromPromise(this.__ingestDocument(request, requestOptions));
|
|
4683
4706
|
}
|
|
4684
4707
|
async __ingestDocument(request, requestOptions) {
|
|
4708
|
+
const { upsert, body: _body } = request;
|
|
4709
|
+
const _queryParams = {
|
|
4710
|
+
upsert
|
|
4711
|
+
};
|
|
4685
4712
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4686
4713
|
const _headers = mergeHeaders(
|
|
4687
4714
|
_authRequest.headers,
|
|
@@ -4696,9 +4723,9 @@ var DocumentsClient = class {
|
|
|
4696
4723
|
method: "POST",
|
|
4697
4724
|
headers: _headers,
|
|
4698
4725
|
contentType: "application/json",
|
|
4699
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4726
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
4700
4727
|
requestType: "json",
|
|
4701
|
-
body:
|
|
4728
|
+
body: _body,
|
|
4702
4729
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4703
4730
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4704
4731
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -4712,6 +4739,8 @@ var DocumentsClient = class {
|
|
|
4712
4739
|
switch (_response.error.statusCode) {
|
|
4713
4740
|
case 400:
|
|
4714
4741
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
4742
|
+
case 403:
|
|
4743
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4715
4744
|
case 429:
|
|
4716
4745
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4717
4746
|
default:
|
|
@@ -4978,7 +5007,7 @@ var DocumentsClient = class {
|
|
|
4978
5007
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "PATCH", "/v1/documents/{id}");
|
|
4979
5008
|
}
|
|
4980
5009
|
/**
|
|
4981
|
-
* Finds documents of a given type by
|
|
5010
|
+
* Finds documents of a given type by field value. Supported fields: `externalId` (the document's first-class external identifier — no schema declaration required) and any field declared as a lookup field on the bound schema. A lookup on a sensitive field is rejected here because the value would appear in the URL query string; use POST /v1/documents/lookup (the request-body variant) for a sensitive field instead. Results are paginated: set `limit` for the page size and feed the returned `nextCursor` back as `startFrom` to fetch the next page. The response is a `{data, nextCursor}` envelope. Requires the `documents:r` scope.
|
|
4982
5011
|
*
|
|
4983
5012
|
* @param {Vectros.LookupDocumentsRequest} request
|
|
4984
5013
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -5273,12 +5302,13 @@ var DocumentsClient = class {
|
|
|
5273
5302
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/{id}/versions");
|
|
5274
5303
|
}
|
|
5275
5304
|
/**
|
|
5276
|
-
* Starts a file-based document by returning a short-lived presigned S3 PUT URL. Upload the file bytes directly to `uploadUrl`; the document is then automatically queued for text extraction and asynchronous indexing.
|
|
5305
|
+
* Starts a file-based document by returning a short-lived presigned S3 PUT URL. Upload the file bytes directly to `uploadUrl`; the document is then automatically queued for text extraction and asynchronous indexing. Supplying an `externalId` makes this idempotent — re-initiating an upload with the same `externalId` re-issues a fresh presigned URL to the SAME existing document/object (so a re-upload inherently replaces the file body) rather than creating a duplicate. The response's `created` field (and the HTTP status — 201 when a new document was minted, 200 when an existing one was matched) tells the two apart. With `?upsert=true`, the submitted `payload`/`title` are also applied to the matched document (file-body divergence cannot be diffed at upload-init — the bytes have not arrived yet — so the re-upload itself replaces the body). Creating a NEW document requires the `documents:c` scope. Re-uploading over an EXISTING document overwrites (and re-indexes) its body, so it is an update: it requires the `documents:u` scope (as does `?upsert=true` for the metadata).
|
|
5277
5306
|
*
|
|
5278
5307
|
* @param {Vectros.FileUploadRequest} request
|
|
5279
5308
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5280
5309
|
*
|
|
5281
5310
|
* @throws {@link Vectros.BadRequestError}
|
|
5311
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5282
5312
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5283
5313
|
*
|
|
5284
5314
|
* @example
|
|
@@ -5291,6 +5321,10 @@ var DocumentsClient = class {
|
|
|
5291
5321
|
return HttpResponsePromise.fromPromise(this.__uploadDocument(request, requestOptions));
|
|
5292
5322
|
}
|
|
5293
5323
|
async __uploadDocument(request, requestOptions) {
|
|
5324
|
+
const { upsert, ..._body } = request;
|
|
5325
|
+
const _queryParams = {
|
|
5326
|
+
upsert
|
|
5327
|
+
};
|
|
5294
5328
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5295
5329
|
const _headers = mergeHeaders(
|
|
5296
5330
|
_authRequest.headers,
|
|
@@ -5305,9 +5339,9 @@ var DocumentsClient = class {
|
|
|
5305
5339
|
method: "POST",
|
|
5306
5340
|
headers: _headers,
|
|
5307
5341
|
contentType: "application/json",
|
|
5308
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5342
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5309
5343
|
requestType: "json",
|
|
5310
|
-
body:
|
|
5344
|
+
body: _body,
|
|
5311
5345
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5312
5346
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5313
5347
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5321,6 +5355,8 @@ var DocumentsClient = class {
|
|
|
5321
5355
|
switch (_response.error.statusCode) {
|
|
5322
5356
|
case 400:
|
|
5323
5357
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5358
|
+
case 403:
|
|
5359
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5324
5360
|
case 429:
|
|
5325
5361
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5326
5362
|
default:
|
|
@@ -5399,23 +5435,30 @@ var FoldersClient = class {
|
|
|
5399
5435
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/folders");
|
|
5400
5436
|
}
|
|
5401
5437
|
/**
|
|
5402
|
-
* Creates a folder to organize your documents and records. If `parentFolderId` is omitted, the folder is created under your context's default root folder. Requires the `folders:c` scope.
|
|
5438
|
+
* Creates a folder to organize your documents and records. If `parentFolderId` is omitted, the folder is created under your context's default root folder. Folder creation is idempotent by (slug + parent): if a folder with the same slug already exists under the same parent, that existing folder is returned unchanged instead of a duplicate being created. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing folder was returned) tells the two apart. To overwrite an existing folder's mutable fields instead of returning it unchanged, set `?upsert=true` (this also requires the `folders:u` scope). Requires the `folders:c` scope.
|
|
5403
5439
|
*
|
|
5404
|
-
* @param {Vectros.
|
|
5440
|
+
* @param {Vectros.CreateFolderRequest} request
|
|
5405
5441
|
* @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5406
5442
|
*
|
|
5407
5443
|
* @throws {@link Vectros.BadRequestError}
|
|
5444
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5408
5445
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5409
5446
|
*
|
|
5410
5447
|
* @example
|
|
5411
5448
|
* await client.folders.createFolder({
|
|
5412
|
-
*
|
|
5449
|
+
* body: {
|
|
5450
|
+
* name: "Patient Records 2024"
|
|
5451
|
+
* }
|
|
5413
5452
|
* })
|
|
5414
5453
|
*/
|
|
5415
5454
|
createFolder(request, requestOptions) {
|
|
5416
5455
|
return HttpResponsePromise.fromPromise(this.__createFolder(request, requestOptions));
|
|
5417
5456
|
}
|
|
5418
5457
|
async __createFolder(request, requestOptions) {
|
|
5458
|
+
const { upsert, body: _body } = request;
|
|
5459
|
+
const _queryParams = {
|
|
5460
|
+
upsert
|
|
5461
|
+
};
|
|
5419
5462
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5420
5463
|
const _headers = mergeHeaders(
|
|
5421
5464
|
_authRequest.headers,
|
|
@@ -5430,9 +5473,9 @@ var FoldersClient = class {
|
|
|
5430
5473
|
method: "POST",
|
|
5431
5474
|
headers: _headers,
|
|
5432
5475
|
contentType: "application/json",
|
|
5433
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5476
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5434
5477
|
requestType: "json",
|
|
5435
|
-
body:
|
|
5478
|
+
body: _body,
|
|
5436
5479
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5437
5480
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5438
5481
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5446,6 +5489,8 @@ var FoldersClient = class {
|
|
|
5446
5489
|
switch (_response.error.statusCode) {
|
|
5447
5490
|
case 400:
|
|
5448
5491
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5492
|
+
case 403:
|
|
5493
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5449
5494
|
case 429:
|
|
5450
5495
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5451
5496
|
default:
|
|
@@ -5854,23 +5899,30 @@ var IdentityClient = class {
|
|
|
5854
5899
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/clients");
|
|
5855
5900
|
}
|
|
5856
5901
|
/**
|
|
5857
|
-
* Creates a new client identity in your account. This call is idempotent on `externalId`: if a client with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. Requires the `clients:c` scope.
|
|
5902
|
+
* Creates a new client identity in your account. This call is idempotent on `externalId`: if a client with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing client was returned) tells the two apart. To overwrite an existing client's content instead of returning it unchanged, set `?upsert=true` (this also requires the `clients:u` scope). Requires the `clients:c` scope.
|
|
5858
5903
|
*
|
|
5859
|
-
* @param {Vectros.
|
|
5904
|
+
* @param {Vectros.CreateClientRequest} request
|
|
5860
5905
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5861
5906
|
*
|
|
5862
5907
|
* @throws {@link Vectros.BadRequestError}
|
|
5908
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5863
5909
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5864
5910
|
*
|
|
5865
5911
|
* @example
|
|
5866
5912
|
* await client.identity.createClient({
|
|
5867
|
-
*
|
|
5913
|
+
* body: {
|
|
5914
|
+
* externalId: "patient_789"
|
|
5915
|
+
* }
|
|
5868
5916
|
* })
|
|
5869
5917
|
*/
|
|
5870
5918
|
createClient(request, requestOptions) {
|
|
5871
5919
|
return HttpResponsePromise.fromPromise(this.__createClient(request, requestOptions));
|
|
5872
5920
|
}
|
|
5873
5921
|
async __createClient(request, requestOptions) {
|
|
5922
|
+
const { upsert, body: _body } = request;
|
|
5923
|
+
const _queryParams = {
|
|
5924
|
+
upsert
|
|
5925
|
+
};
|
|
5874
5926
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5875
5927
|
const _headers = mergeHeaders(
|
|
5876
5928
|
_authRequest.headers,
|
|
@@ -5885,9 +5937,9 @@ var IdentityClient = class {
|
|
|
5885
5937
|
method: "POST",
|
|
5886
5938
|
headers: _headers,
|
|
5887
5939
|
contentType: "application/json",
|
|
5888
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5940
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5889
5941
|
requestType: "json",
|
|
5890
|
-
body:
|
|
5942
|
+
body: _body,
|
|
5891
5943
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5892
5944
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5893
5945
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5901,6 +5953,8 @@ var IdentityClient = class {
|
|
|
5901
5953
|
switch (_response.error.statusCode) {
|
|
5902
5954
|
case 400:
|
|
5903
5955
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5956
|
+
case 403:
|
|
5957
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5904
5958
|
case 429:
|
|
5905
5959
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5906
5960
|
default:
|
|
@@ -6289,23 +6343,30 @@ var IdentityClient = class {
|
|
|
6289
6343
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/orgs");
|
|
6290
6344
|
}
|
|
6291
6345
|
/**
|
|
6292
|
-
* Creates a new organization in your account. This call is idempotent on `externalId`: if an organization with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. Requires the `orgs:c` scope.
|
|
6346
|
+
* Creates a new organization in your account. This call is idempotent on `externalId`: if an organization with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing organization was returned) tells the two apart. To overwrite an existing organization's content instead of returning it unchanged, set `?upsert=true` (this also requires the `orgs:u` scope). Requires the `orgs:c` scope.
|
|
6293
6347
|
*
|
|
6294
|
-
* @param {Vectros.
|
|
6348
|
+
* @param {Vectros.CreateOrgRequest} request
|
|
6295
6349
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6296
6350
|
*
|
|
6297
6351
|
* @throws {@link Vectros.BadRequestError}
|
|
6352
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
6298
6353
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6299
6354
|
*
|
|
6300
6355
|
* @example
|
|
6301
6356
|
* await client.identity.createOrg({
|
|
6302
|
-
*
|
|
6357
|
+
* body: {
|
|
6358
|
+
* externalId: "clinic_001"
|
|
6359
|
+
* }
|
|
6303
6360
|
* })
|
|
6304
6361
|
*/
|
|
6305
6362
|
createOrg(request, requestOptions) {
|
|
6306
6363
|
return HttpResponsePromise.fromPromise(this.__createOrg(request, requestOptions));
|
|
6307
6364
|
}
|
|
6308
6365
|
async __createOrg(request, requestOptions) {
|
|
6366
|
+
const { upsert, body: _body } = request;
|
|
6367
|
+
const _queryParams = {
|
|
6368
|
+
upsert
|
|
6369
|
+
};
|
|
6309
6370
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
6310
6371
|
const _headers = mergeHeaders(
|
|
6311
6372
|
_authRequest.headers,
|
|
@@ -6320,9 +6381,9 @@ var IdentityClient = class {
|
|
|
6320
6381
|
method: "POST",
|
|
6321
6382
|
headers: _headers,
|
|
6322
6383
|
contentType: "application/json",
|
|
6323
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
6384
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
6324
6385
|
requestType: "json",
|
|
6325
|
-
body:
|
|
6386
|
+
body: _body,
|
|
6326
6387
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
6327
6388
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
6328
6389
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -6336,6 +6397,8 @@ var IdentityClient = class {
|
|
|
6336
6397
|
switch (_response.error.statusCode) {
|
|
6337
6398
|
case 400:
|
|
6338
6399
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6400
|
+
case 403:
|
|
6401
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
6339
6402
|
case 429:
|
|
6340
6403
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
6341
6404
|
default:
|
|
@@ -6710,23 +6773,30 @@ var IdentityClient = class {
|
|
|
6710
6773
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users");
|
|
6711
6774
|
}
|
|
6712
6775
|
/**
|
|
6713
|
-
* Creates a user identity in your account. The operation is idempotent on `externalId`: if a user with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. Requires the `users:c` scope.
|
|
6776
|
+
* Creates a user identity in your account. The operation is idempotent on `externalId`: if a user with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing user was returned) tells the two apart. To overwrite an existing user's mutable fields (email, status, payload, schema binding) instead of returning it unchanged, set `?upsert=true` (this also requires the `users:u` scope). Requires the `users:c` scope.
|
|
6714
6777
|
*
|
|
6715
|
-
* @param {Vectros.
|
|
6778
|
+
* @param {Vectros.CreateUserRequest} request
|
|
6716
6779
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6717
6780
|
*
|
|
6718
6781
|
* @throws {@link Vectros.BadRequestError}
|
|
6782
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
6719
6783
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6720
6784
|
*
|
|
6721
6785
|
* @example
|
|
6722
6786
|
* await client.identity.createUser({
|
|
6723
|
-
*
|
|
6787
|
+
* body: {
|
|
6788
|
+
* externalId: "usr_12345"
|
|
6789
|
+
* }
|
|
6724
6790
|
* })
|
|
6725
6791
|
*/
|
|
6726
6792
|
createUser(request, requestOptions) {
|
|
6727
6793
|
return HttpResponsePromise.fromPromise(this.__createUser(request, requestOptions));
|
|
6728
6794
|
}
|
|
6729
6795
|
async __createUser(request, requestOptions) {
|
|
6796
|
+
const { upsert, body: _body } = request;
|
|
6797
|
+
const _queryParams = {
|
|
6798
|
+
upsert
|
|
6799
|
+
};
|
|
6730
6800
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
6731
6801
|
const _headers = mergeHeaders(
|
|
6732
6802
|
_authRequest.headers,
|
|
@@ -6741,9 +6811,9 @@ var IdentityClient = class {
|
|
|
6741
6811
|
method: "POST",
|
|
6742
6812
|
headers: _headers,
|
|
6743
6813
|
contentType: "application/json",
|
|
6744
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
6814
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
6745
6815
|
requestType: "json",
|
|
6746
|
-
body:
|
|
6816
|
+
body: _body,
|
|
6747
6817
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
6748
6818
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
6749
6819
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -6757,6 +6827,8 @@ var IdentityClient = class {
|
|
|
6757
6827
|
switch (_response.error.statusCode) {
|
|
6758
6828
|
case 400:
|
|
6759
6829
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6830
|
+
case 403:
|
|
6831
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
6760
6832
|
case 429:
|
|
6761
6833
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
6762
6834
|
default:
|
|
@@ -7574,9 +7646,9 @@ var RecordsClient = class {
|
|
|
7574
7646
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/records");
|
|
7575
7647
|
}
|
|
7576
7648
|
/**
|
|
7577
|
-
* Creates a new record of a given type. The `payload` is validated against that type's schema before the record is stored. Identify the type by sending `typeName`, `schemaId`, or both (they must agree); if you send only `schemaId`, the type is taken from that schema. Optionally supply an `externalId` to make the create idempotent — if a record with the same `externalId` already exists in your context, that existing record is returned unchanged instead of a duplicate being created. Requires the `records:c:<type>` scope.
|
|
7649
|
+
* Creates a new record of a given type. The `payload` is validated against that type's schema before the record is stored. Identify the type by sending `typeName`, `schemaId`, or both (they must agree); if you send only `schemaId`, the type is taken from that schema. Optionally supply an `externalId` to make the create idempotent — if a record with the same `externalId` already exists in your context, that existing record is returned unchanged instead of a duplicate being created. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing record was returned) tells the two apart. To overwrite an existing record's content instead of returning it unchanged, set `?upsert=true` (this also requires the `records:u:<type>` scope). Requires the `records:c:<type>` scope.
|
|
7578
7650
|
*
|
|
7579
|
-
* @param {Vectros.
|
|
7651
|
+
* @param {Vectros.CreateRecordRequest} request
|
|
7580
7652
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7581
7653
|
*
|
|
7582
7654
|
* @throws {@link Vectros.BadRequestError}
|
|
@@ -7585,19 +7657,25 @@ var RecordsClient = class {
|
|
|
7585
7657
|
*
|
|
7586
7658
|
* @example
|
|
7587
7659
|
* await client.records.createRecord({
|
|
7588
|
-
*
|
|
7589
|
-
*
|
|
7590
|
-
*
|
|
7591
|
-
*
|
|
7592
|
-
*
|
|
7593
|
-
*
|
|
7594
|
-
*
|
|
7660
|
+
* body: {
|
|
7661
|
+
* typeName: "intake_form",
|
|
7662
|
+
* schemaId: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
7663
|
+
* payload: {
|
|
7664
|
+
* "first_name": "Jane",
|
|
7665
|
+
* "email": "jane@example.com"
|
|
7666
|
+
* },
|
|
7667
|
+
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
7668
|
+
* }
|
|
7595
7669
|
* })
|
|
7596
7670
|
*/
|
|
7597
7671
|
createRecord(request, requestOptions) {
|
|
7598
7672
|
return HttpResponsePromise.fromPromise(this.__createRecord(request, requestOptions));
|
|
7599
7673
|
}
|
|
7600
7674
|
async __createRecord(request, requestOptions) {
|
|
7675
|
+
const { upsert, body: _body } = request;
|
|
7676
|
+
const _queryParams = {
|
|
7677
|
+
upsert
|
|
7678
|
+
};
|
|
7601
7679
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
7602
7680
|
const _headers = mergeHeaders(
|
|
7603
7681
|
_authRequest.headers,
|
|
@@ -7612,9 +7690,9 @@ var RecordsClient = class {
|
|
|
7612
7690
|
method: "POST",
|
|
7613
7691
|
headers: _headers,
|
|
7614
7692
|
contentType: "application/json",
|
|
7615
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
7693
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
7616
7694
|
requestType: "json",
|
|
7617
|
-
body:
|
|
7695
|
+
body: _body,
|
|
7618
7696
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
7619
7697
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
7620
7698
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -8210,43 +8288,50 @@ var SchemasClient = class {
|
|
|
8210
8288
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/schemas");
|
|
8211
8289
|
}
|
|
8212
8290
|
/**
|
|
8213
|
-
* Defines a new record type with optional field definitions, validation rules, and lookup indexes. Idempotent by `typeName` within the same ownership scope: re-creating an existing `typeName` returns the existing schema rather than failing. Requires the `schemas:w` scope.
|
|
8291
|
+
* Defines a new record type with optional field definitions, validation rules, and lookup indexes. Idempotent by `typeName` within the same ownership scope: re-creating an existing `typeName` returns the existing schema rather than failing. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing schema was returned) tells the two apart. To reconcile an existing schema to the submitted shape instead of returning it unchanged, set `?upsert=true` (this also requires the `schemas:w` scope; only legal schema changes are applied — migration-locked changes are rejected). Requires the `schemas:w` scope.
|
|
8214
8292
|
*
|
|
8215
|
-
* @param {Vectros.
|
|
8293
|
+
* @param {Vectros.CreateSchemaRequest} request
|
|
8216
8294
|
* @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
8217
8295
|
*
|
|
8218
8296
|
* @throws {@link Vectros.BadRequestError}
|
|
8297
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
8219
8298
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
8220
8299
|
*
|
|
8221
8300
|
* @example
|
|
8222
8301
|
* await client.schemas.createSchema({
|
|
8223
|
-
*
|
|
8224
|
-
*
|
|
8225
|
-
*
|
|
8226
|
-
*
|
|
8227
|
-
*
|
|
8228
|
-
*
|
|
8229
|
-
*
|
|
8230
|
-
*
|
|
8231
|
-
*
|
|
8232
|
-
*
|
|
8233
|
-
*
|
|
8234
|
-
*
|
|
8235
|
-
*
|
|
8236
|
-
*
|
|
8237
|
-
*
|
|
8238
|
-
*
|
|
8239
|
-
*
|
|
8240
|
-
*
|
|
8241
|
-
*
|
|
8242
|
-
*
|
|
8243
|
-
*
|
|
8302
|
+
* body: {
|
|
8303
|
+
* typeName: "intake_form",
|
|
8304
|
+
* displayName: "Client Intake Form",
|
|
8305
|
+
* description: "Captures initial client information",
|
|
8306
|
+
* fields: [{
|
|
8307
|
+
* fieldId: "first_name",
|
|
8308
|
+
* fieldType: "string",
|
|
8309
|
+
* required: true,
|
|
8310
|
+
* searchable: true
|
|
8311
|
+
* }, {
|
|
8312
|
+
* fieldId: "email",
|
|
8313
|
+
* fieldType: "string",
|
|
8314
|
+
* required: true
|
|
8315
|
+
* }],
|
|
8316
|
+
* lookupFields: [{
|
|
8317
|
+
* fieldName: "email",
|
|
8318
|
+
* unique: true
|
|
8319
|
+
* }],
|
|
8320
|
+
* capabilities: {
|
|
8321
|
+
* "auditHistory": true
|
|
8322
|
+
* },
|
|
8323
|
+
* allowedSurfaces: ["record"]
|
|
8324
|
+
* }
|
|
8244
8325
|
* })
|
|
8245
8326
|
*/
|
|
8246
8327
|
createSchema(request, requestOptions) {
|
|
8247
8328
|
return HttpResponsePromise.fromPromise(this.__createSchema(request, requestOptions));
|
|
8248
8329
|
}
|
|
8249
8330
|
async __createSchema(request, requestOptions) {
|
|
8331
|
+
const { upsert, body: _body } = request;
|
|
8332
|
+
const _queryParams = {
|
|
8333
|
+
upsert
|
|
8334
|
+
};
|
|
8250
8335
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
8251
8336
|
const _headers = mergeHeaders(
|
|
8252
8337
|
_authRequest.headers,
|
|
@@ -8261,9 +8346,9 @@ var SchemasClient = class {
|
|
|
8261
8346
|
method: "POST",
|
|
8262
8347
|
headers: _headers,
|
|
8263
8348
|
contentType: "application/json",
|
|
8264
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
8349
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
8265
8350
|
requestType: "json",
|
|
8266
|
-
body:
|
|
8351
|
+
body: _body,
|
|
8267
8352
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
8268
8353
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
8269
8354
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -8277,6 +8362,8 @@ var SchemasClient = class {
|
|
|
8277
8362
|
switch (_response.error.statusCode) {
|
|
8278
8363
|
case 400:
|
|
8279
8364
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8365
|
+
case 403:
|
|
8366
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
8280
8367
|
case 429:
|
|
8281
8368
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
8282
8369
|
default:
|
|
@@ -8711,8 +8798,8 @@ function warnOnSuboptimalKey(key, log) {
|
|
|
8711
8798
|
|
|
8712
8799
|
// src/build-info.ts
|
|
8713
8800
|
var BUILD_INFO = {
|
|
8714
|
-
mcpServer: true ? "0.
|
|
8715
|
-
sdk: true ? "0.
|
|
8801
|
+
mcpServer: true ? "0.6.0" : "dev",
|
|
8802
|
+
sdk: true ? "0.32.0" : "dev"
|
|
8716
8803
|
};
|
|
8717
8804
|
|
|
8718
8805
|
// src/log.ts
|
|
@@ -8949,6 +9036,32 @@ ${detail}${pointer}`
|
|
|
8949
9036
|
// src/tools/hybrid_search.ts
|
|
8950
9037
|
var MCP_DEFAULT_LIMIT = 3;
|
|
8951
9038
|
var MCP_MAX_LIMIT = 10;
|
|
9039
|
+
var MCP_RESPONSE_CHAR_BUDGET = 24e3;
|
|
9040
|
+
var SNIPPET_MAX_CHARS = 160;
|
|
9041
|
+
var INTERNAL_METADATA_KEYS = /* @__PURE__ */ new Set(["tenantId", "owner_id", "model_type", "rootFolderId", "folderId"]);
|
|
9042
|
+
function trimMetadata(md) {
|
|
9043
|
+
if (!md || typeof md !== "object" || Array.isArray(md)) return md;
|
|
9044
|
+
const out = {};
|
|
9045
|
+
for (const [k, v] of Object.entries(md)) {
|
|
9046
|
+
if (!INTERNAL_METADATA_KEYS.has(k)) out[k] = v;
|
|
9047
|
+
}
|
|
9048
|
+
return out;
|
|
9049
|
+
}
|
|
9050
|
+
function reshapeHit(hit, includeContext) {
|
|
9051
|
+
const out = { ...hit };
|
|
9052
|
+
if ("metadata" in out) out.metadata = trimMetadata(out.metadata);
|
|
9053
|
+
const chunk = typeof hit.chunkText === "string" ? hit.chunkText : void 0;
|
|
9054
|
+
const ctx = typeof hit.contextText === "string" ? hit.contextText : void 0;
|
|
9055
|
+
if (includeContext) {
|
|
9056
|
+
if (chunk && ctx && ctx.includes(chunk)) delete out.chunkText;
|
|
9057
|
+
} else {
|
|
9058
|
+
delete out.contextText;
|
|
9059
|
+
}
|
|
9060
|
+
if ((out.snippet == null || out.snippet === "") && chunk) {
|
|
9061
|
+
out.snippet = chunk.length > SNIPPET_MAX_CHARS ? chunk.slice(0, SNIPPET_MAX_CHARS) + "\u2026" : chunk;
|
|
9062
|
+
}
|
|
9063
|
+
return out;
|
|
9064
|
+
}
|
|
8952
9065
|
var inputSchema = {
|
|
8953
9066
|
query: import_zod.z.string().min(1, "query must be non-empty").describe("Natural-language or keyword query."),
|
|
8954
9067
|
mode: import_zod.z.enum(["HYBRID", "TEXT", "SEMANTIC"]).optional().describe("HYBRID (BM25 + dense, default), TEXT (BM25 only), or SEMANTIC (dense only)."),
|
|
@@ -8963,7 +9076,9 @@ var inputSchema = {
|
|
|
8963
9076
|
rootFolderId: import_zod.z.string().optional().describe("Scope to content under this folder AND all its descendants (subtree-root folder id)."),
|
|
8964
9077
|
// Content narrowing.
|
|
8965
9078
|
contentTypes: import_zod.z.array(import_zod.z.enum(["documents", "records"])).optional().describe('Narrow to content types. ["documents"] or ["records"]; omit for unified (both).'),
|
|
8966
|
-
typeName: import_zod.z.string().optional().describe(
|
|
9079
|
+
typeName: import_zod.z.string().optional().describe(
|
|
9080
|
+
'Restrict hits to this schema type (e.g. "patient", "runbook"). Applies to BOTH documents and records \u2014 combine with contentTypes to scope within one content type. Untyped content never matches.'
|
|
9081
|
+
),
|
|
8967
9082
|
filters: import_zod.z.record(import_zod.z.unknown()).optional().describe(
|
|
8968
9083
|
'Field-level metadata filters (AND-combined). Value = scalar (equality), array (OR-set), or operator map: $eq/$ne/$gt/$gte/$lt/$lte (scalar) or $in/$nin (array). e.g. {"status":"open"} or {"price":{"$gte":100,"$lte":500}}.'
|
|
8969
9084
|
),
|
|
@@ -8978,6 +9093,9 @@ var inputSchema = {
|
|
|
8978
9093
|
minSimilarity: import_zod.z.number().min(0).max(1).optional().describe("Minimum semantic similarity (0.0\u20131.0); results below are excluded."),
|
|
8979
9094
|
minTextRelevance: import_zod.z.number().min(0).max(1).optional().describe("Minimum relative keyword (BM25) relevance (0.0\u20131.0); the keyword-leg analogue of minSimilarity."),
|
|
8980
9095
|
uniqueDocuments: import_zod.z.boolean().optional().describe("When true, return at most one chunk per source document."),
|
|
9096
|
+
includeContext: import_zod.z.boolean().optional().describe(
|
|
9097
|
+
"Include the broader passage (contextText) around each matched chunk. Off by default to keep the result compact \u2014 each hit returns its matched chunkText plus a short snippet. Turn this on only when you need more surrounding context inline; for a full deep read, fetch the source with document_get."
|
|
9098
|
+
),
|
|
8981
9099
|
requireComplete: import_zod.z.boolean().optional().describe(
|
|
8982
9100
|
"When true, fail closed (HTTP 503) if a search backend is unavailable rather than silently returning partial/degraded results. Default false (degrade to the surviving engine; the result still flags degraded)."
|
|
8983
9101
|
)
|
|
@@ -8985,7 +9103,7 @@ var inputSchema = {
|
|
|
8985
9103
|
var hybridSearch = ({ client, log }) => ({
|
|
8986
9104
|
name: "hybrid_search",
|
|
8987
9105
|
title: "Hybrid search",
|
|
8988
|
-
description:
|
|
9106
|
+
description: `Search the partner tenant's indexed content (documents + structured records) using hybrid BM25 + dense ranking. Returns up to 10 results (default 3) with citations and surrounding context for grounding follow-up reasoning. Narrow with contentTypes/typeName/filters, ownership (userId/orgId/clientId), folder scope, a created date window, keyword precision (textMode OR/AND/PHRASE), relevance floors (minSimilarity/minTextRelevance), uniqueDocuments, and requireComplete (fail closed on a degraded backend). Tenant-isolated; the caller's scoped key fully constrains which content is visible. ARCHIVED (soft-retracted) documents never appear in results \u2014 fetch them by id via document_get, or restore them via document_update. To stay within the agent context window each hit returns its matched chunkText + a short snippet by default; set includeContext:true for the broader surrounding passage. If the whole result would be too large it is truncated to the top hits (truncated:true). textLegEmpty:true flags that the keyword leg matched nothing (all textScores 0) \u2014 usually a too-long PHRASE query; retry with textMode:"OR".`,
|
|
8989
9107
|
inputSchema,
|
|
8990
9108
|
handler: async (args) => {
|
|
8991
9109
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT;
|
|
@@ -9012,13 +9130,30 @@ var hybridSearch = ({ client, log }) => ({
|
|
|
9012
9130
|
uniqueDocuments: args.uniqueDocuments,
|
|
9013
9131
|
requireComplete: args.requireComplete
|
|
9014
9132
|
});
|
|
9133
|
+
const hits = Array.isArray(
|
|
9134
|
+
result.results
|
|
9135
|
+
) ? result.results : [];
|
|
9136
|
+
const includeContext = args.includeContext ?? false;
|
|
9137
|
+
let shaped = hits.map((h) => reshapeHit(h, includeContext));
|
|
9138
|
+
const textLegEmpty = mode !== "SEMANTIC" && hits.length > 0 && hits.every((h) => !(Number(h.textScore) > 0));
|
|
9139
|
+
const envelope = {
|
|
9140
|
+
...result,
|
|
9141
|
+
results: shaped
|
|
9142
|
+
};
|
|
9143
|
+
if (textLegEmpty) envelope.textLegEmpty = true;
|
|
9144
|
+
let text = JSON.stringify(envelope, null, 2);
|
|
9145
|
+
while (shaped.length > 1 && text.length > MCP_RESPONSE_CHAR_BUDGET) {
|
|
9146
|
+
shaped = shaped.slice(0, -1);
|
|
9147
|
+
envelope.results = shaped;
|
|
9148
|
+
envelope.truncated = true;
|
|
9149
|
+
envelope.returnedResults = shaped.length;
|
|
9150
|
+
text = JSON.stringify(envelope, null, 2);
|
|
9151
|
+
}
|
|
9015
9152
|
log.debug(
|
|
9016
|
-
{ tool: "hybrid_search", mode, limit, returned:
|
|
9153
|
+
{ tool: "hybrid_search", mode, limit, returned: shaped.length, textLegEmpty },
|
|
9017
9154
|
"hybrid_search ok"
|
|
9018
9155
|
);
|
|
9019
|
-
return {
|
|
9020
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
9021
|
-
};
|
|
9156
|
+
return { content: [{ type: "text", text }] };
|
|
9022
9157
|
} catch (err) {
|
|
9023
9158
|
log.warn({ tool: "hybrid_search", err: String(err) }, "hybrid_search failed");
|
|
9024
9159
|
return toolError("hybrid_search", err);
|
|
@@ -9053,7 +9188,9 @@ var MCP_MAX_LIMIT2 = 10;
|
|
|
9053
9188
|
var inputSchema2 = {
|
|
9054
9189
|
type: import_zod2.z.string().min(1, "type (record type) is required").describe('Record type / schema name (e.g. "patient", "clinical_note").'),
|
|
9055
9190
|
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | from+to | prefix.
|
|
9056
|
-
field: import_zod2.z.string().optional().describe(
|
|
9191
|
+
field: import_zod2.z.string().optional().describe(
|
|
9192
|
+
'Lookup mode: name of the lookup-indexed field to query by. `externalId` is always queryable \u2014 e.g. `{type:"control", field:"externalId", value:"ctrl-scoped-key"}` finds the record you created under that externalId. (record_get / record_update also accept externalId directly.)'
|
|
9193
|
+
),
|
|
9057
9194
|
value: import_zod2.z.string().optional().describe("Lookup mode (equality): exact-match value for `field`."),
|
|
9058
9195
|
from: import_zod2.z.string().optional().describe("Lookup mode (range): inclusive lower bound; requires `to`. Non-sensitive fields only."),
|
|
9059
9196
|
to: import_zod2.z.string().optional().describe("Lookup mode (range): inclusive upper bound; requires `from`."),
|
|
@@ -9148,19 +9285,77 @@ var record_query_default = recordQuery;
|
|
|
9148
9285
|
|
|
9149
9286
|
// src/tools/record_get.ts
|
|
9150
9287
|
var import_zod3 = require("zod");
|
|
9288
|
+
|
|
9289
|
+
// src/tools/resolve-external-id.ts
|
|
9290
|
+
function validateSelector(sel, entity) {
|
|
9291
|
+
const hasId = sel.id !== void 0 && sel.id !== "";
|
|
9292
|
+
const hasExt = sel.externalId !== void 0 && sel.externalId !== "";
|
|
9293
|
+
if (hasId && hasExt) {
|
|
9294
|
+
return `Provide either id or externalId (not both) to identify the ${entity}.`;
|
|
9295
|
+
}
|
|
9296
|
+
if (!hasId && !hasExt) {
|
|
9297
|
+
return `Provide id, or externalId + type, to identify the ${entity}.`;
|
|
9298
|
+
}
|
|
9299
|
+
if (hasExt && (sel.type === void 0 || sel.type === "")) {
|
|
9300
|
+
return "type is required when selecting by externalId (externalId is unique within a type).";
|
|
9301
|
+
}
|
|
9302
|
+
return void 0;
|
|
9303
|
+
}
|
|
9304
|
+
async function resolveRecordIdByExternalId(client, sel) {
|
|
9305
|
+
const err = validateSelector(sel, "record");
|
|
9306
|
+
if (err) return { error: err };
|
|
9307
|
+
if (sel.id) return { id: sel.id };
|
|
9308
|
+
const page = await client.records.lookupRecordsByBody({
|
|
9309
|
+
type: sel.type,
|
|
9310
|
+
field: "externalId",
|
|
9311
|
+
value: sel.externalId,
|
|
9312
|
+
limit: 1
|
|
9313
|
+
});
|
|
9314
|
+
const items = pageItems(page);
|
|
9315
|
+
if (items.length === 0) {
|
|
9316
|
+
return { error: `No record of type '${sel.type}' with externalId '${sel.externalId}'.` };
|
|
9317
|
+
}
|
|
9318
|
+
return { id: items[0].id };
|
|
9319
|
+
}
|
|
9320
|
+
async function resolveDocumentIdByExternalId(client, sel) {
|
|
9321
|
+
const err = validateSelector(sel, "document");
|
|
9322
|
+
if (err) return { error: err };
|
|
9323
|
+
if (sel.id) return { id: sel.id };
|
|
9324
|
+
const page = await client.documents.lookupDocumentsByBody({
|
|
9325
|
+
type: sel.type,
|
|
9326
|
+
field: "externalId",
|
|
9327
|
+
value: sel.externalId,
|
|
9328
|
+
limit: 1
|
|
9329
|
+
});
|
|
9330
|
+
const items = pageItems(page);
|
|
9331
|
+
if (items.length === 0) {
|
|
9332
|
+
return { error: `No document of type '${sel.type}' with externalId '${sel.externalId}'.` };
|
|
9333
|
+
}
|
|
9334
|
+
return { id: items[0].id };
|
|
9335
|
+
}
|
|
9336
|
+
|
|
9337
|
+
// src/tools/record_get.ts
|
|
9151
9338
|
var MAX_PAYLOAD_CHARS = 32e3;
|
|
9152
9339
|
var inputSchema3 = {
|
|
9153
|
-
id: import_zod3.z.string().
|
|
9340
|
+
id: import_zod3.z.string().optional().describe("The Vectros record id (e.g. from record_query or hybrid_search). Provide this OR externalId+type."),
|
|
9341
|
+
externalId: import_zod3.z.string().optional().describe(
|
|
9342
|
+
"Your caller-owned externalId \u2014 an alternative selector to `id`. Requires `type` (externalId is unique within a type). Resolves to the record without a manual record_query lookup first."
|
|
9343
|
+
),
|
|
9344
|
+
type: import_zod3.z.string().optional().describe("Record type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type).")
|
|
9154
9345
|
};
|
|
9155
9346
|
var recordGet = ({ client, log }) => ({
|
|
9156
9347
|
name: "record_get",
|
|
9157
|
-
title: "Get a record by id",
|
|
9158
|
-
description: "Fetch a single structured record
|
|
9348
|
+
title: "Get a record by id or externalId",
|
|
9349
|
+
description: "Fetch a single structured record, including the full payload. Select it EITHER by its Vectros `id` (e.g. from record_query / hybrid_search) OR by your own `externalId` + `type` \u2014 the same key you passed to record_create, resolved for you (no manual record_query lookup needed). Very large payloads are truncated to protect the agent context window.",
|
|
9159
9350
|
inputSchema: inputSchema3,
|
|
9160
9351
|
handler: async (args) => {
|
|
9161
9352
|
const id = args.id;
|
|
9353
|
+
const externalId = args.externalId;
|
|
9354
|
+
const type = args.type;
|
|
9162
9355
|
try {
|
|
9163
|
-
const
|
|
9356
|
+
const resolved = await resolveRecordIdByExternalId(client, { id, externalId, type });
|
|
9357
|
+
if ("error" in resolved) return toolError("record_get", new Error(resolved.error));
|
|
9358
|
+
const record = await client.records.getRecord({ id: resolved.id });
|
|
9164
9359
|
const out = { ...record };
|
|
9165
9360
|
if (record.payload !== void 0) {
|
|
9166
9361
|
const json = JSON.stringify(record.payload);
|
|
@@ -9172,12 +9367,12 @@ var recordGet = ({ client, log }) => ({
|
|
|
9172
9367
|
}
|
|
9173
9368
|
}
|
|
9174
9369
|
log.debug(
|
|
9175
|
-
{ tool: "record_get", id, truncated: out.payloadTruncated === true },
|
|
9370
|
+
{ tool: "record_get", id: resolved.id, externalId, truncated: out.payloadTruncated === true },
|
|
9176
9371
|
"record_get ok"
|
|
9177
9372
|
);
|
|
9178
9373
|
return { content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
|
|
9179
9374
|
} catch (err) {
|
|
9180
|
-
log.warn({ tool: "record_get", id, err: String(err) }, "record_get failed");
|
|
9375
|
+
log.warn({ tool: "record_get", id, externalId, type, err: String(err) }, "record_get failed");
|
|
9181
9376
|
return toolError("record_get", err);
|
|
9182
9377
|
}
|
|
9183
9378
|
}
|
|
@@ -9212,15 +9407,17 @@ var recordCreate = ({ client, log }) => ({
|
|
|
9212
9407
|
const type = args.type;
|
|
9213
9408
|
try {
|
|
9214
9409
|
const created = await client.records.createRecord({
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9410
|
+
body: {
|
|
9411
|
+
typeName: type,
|
|
9412
|
+
payload: args.fields,
|
|
9413
|
+
externalId: args.externalId,
|
|
9414
|
+
indexMode: args.indexMode,
|
|
9415
|
+
status: args.status,
|
|
9416
|
+
folderId: args.folderId,
|
|
9417
|
+
userId: args.userId,
|
|
9418
|
+
orgId: args.orgId,
|
|
9419
|
+
clientId: args.clientId
|
|
9420
|
+
}
|
|
9224
9421
|
});
|
|
9225
9422
|
log.debug({ tool: "record_create", type, id: created.id }, "record_create ok");
|
|
9226
9423
|
return { content: [{ type: "text", text: JSON.stringify(created, null, 2) }] };
|
|
@@ -9235,7 +9432,11 @@ var record_create_default = recordCreate;
|
|
|
9235
9432
|
// src/tools/record_update.ts
|
|
9236
9433
|
var import_zod5 = require("zod");
|
|
9237
9434
|
var inputSchema5 = {
|
|
9238
|
-
id: import_zod5.z.string().
|
|
9435
|
+
id: import_zod5.z.string().optional().describe("The Vectros record id to update. Provide this OR externalId+type."),
|
|
9436
|
+
externalId: import_zod5.z.string().optional().describe(
|
|
9437
|
+
"Your caller-owned externalId \u2014 an alternative selector to `id` (requires `type`). Updates the record you created under that externalId without a manual record_query lookup first."
|
|
9438
|
+
),
|
|
9439
|
+
type: import_zod5.z.string().optional().describe("Record type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9239
9440
|
fields: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.unknown()).describe(
|
|
9240
9441
|
"Field\u2192value changes DEEP-MERGED into the existing payload: keys you send overwrite (recursing into nested objects), a key set to `null` is deleted, and unspecified fields are preserved."
|
|
9241
9442
|
),
|
|
@@ -9246,23 +9447,27 @@ var inputSchema5 = {
|
|
|
9246
9447
|
};
|
|
9247
9448
|
var recordUpdate = ({ client, log }) => ({
|
|
9248
9449
|
name: "record_update",
|
|
9249
|
-
title: "Update a record",
|
|
9250
|
-
description: "Update a record by id. The provided `fields` are DEEP-MERGED into the existing payload (unspecified fields are preserved; a field set to `null` is deleted). Pass `expectedVersion` (the version you last read) for safe concurrent edits \u2014 a stale update is refused (409). Use `status` to archive without deleting. Requires the key to allow records:u.",
|
|
9450
|
+
title: "Update a record by id or externalId",
|
|
9451
|
+
description: "Update a record \u2014 select it by its Vectros `id` OR by your own `externalId` + `type` (the same key you passed to record_create, resolved for you). The provided `fields` are DEEP-MERGED into the existing payload (unspecified fields are preserved; a field set to `null` is deleted). Pass `expectedVersion` (the version you last read) for safe concurrent edits \u2014 a stale update is refused (409). Use `status` to archive without deleting. Requires the key to allow records:u.",
|
|
9251
9452
|
inputSchema: inputSchema5,
|
|
9252
9453
|
handler: async (args) => {
|
|
9253
9454
|
const id = args.id;
|
|
9455
|
+
const externalId = args.externalId;
|
|
9456
|
+
const type = args.type;
|
|
9254
9457
|
const fields = args.fields;
|
|
9255
9458
|
const status = args.status;
|
|
9256
9459
|
const expectedVersion = args.expectedVersion;
|
|
9257
9460
|
try {
|
|
9461
|
+
const resolved = await resolveRecordIdByExternalId(client, { id, externalId, type });
|
|
9462
|
+
if ("error" in resolved) return toolError("record_update", new Error(resolved.error));
|
|
9258
9463
|
const body = { payload: fields };
|
|
9259
9464
|
if (status !== void 0) body.status = status;
|
|
9260
9465
|
if (expectedVersion !== void 0) body.expectedVersion = expectedVersion;
|
|
9261
|
-
const updated = await client.records.patchRecord({ id, body });
|
|
9262
|
-
log.debug({ tool: "record_update", id }, "record_update ok");
|
|
9466
|
+
const updated = await client.records.patchRecord({ id: resolved.id, body });
|
|
9467
|
+
log.debug({ tool: "record_update", id: resolved.id, externalId }, "record_update ok");
|
|
9263
9468
|
return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
|
|
9264
9469
|
} catch (err) {
|
|
9265
|
-
log.warn({ tool: "record_update", id, err: String(err) }, "record_update failed");
|
|
9470
|
+
log.warn({ tool: "record_update", id, externalId, type, err: String(err) }, "record_update failed");
|
|
9266
9471
|
return toolError("record_update", err);
|
|
9267
9472
|
}
|
|
9268
9473
|
}
|
|
@@ -9529,7 +9734,11 @@ var list_schemas_default = listSchemas;
|
|
|
9529
9734
|
var import_zod10 = require("zod");
|
|
9530
9735
|
var MAX_TEXT_CHARS = 32e3;
|
|
9531
9736
|
var inputSchema10 = {
|
|
9532
|
-
documentId: import_zod10.z.string().
|
|
9737
|
+
documentId: import_zod10.z.string().optional().describe("The document ID returned by document_ingest or hybrid_search. Provide this OR externalId+type."),
|
|
9738
|
+
externalId: import_zod10.z.string().optional().describe(
|
|
9739
|
+
"Your caller-owned externalId \u2014 an alternative selector to `documentId` (requires `type`). Fetches the document you ingested under that externalId without a manual lookup first."
|
|
9740
|
+
),
|
|
9741
|
+
type: import_zod10.z.string().optional().describe("Document type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9533
9742
|
includeText: import_zod10.z.boolean().optional().describe(
|
|
9534
9743
|
"If true, fetch and include the document text (capped at ~8K tokens, truncated: true flag if cut). Default false \u2014 metadata only. For larger documents, prefer `document_ask` over dumping text into context."
|
|
9535
9744
|
),
|
|
@@ -9549,13 +9758,18 @@ function isNotAvailable(err) {
|
|
|
9549
9758
|
var documentGet = ({ client, log }) => ({
|
|
9550
9759
|
name: "document_get",
|
|
9551
9760
|
title: "Get document metadata (and optionally text)",
|
|
9552
|
-
description: "Fetch metadata for a single document by
|
|
9761
|
+
description: "Fetch metadata for a single document \u2014 select it by its Vectros `documentId` OR by your own `externalId` + `type` (resolved for you). Pass `includeText: true` to also fetch the text body (capped at ~8K tokens; `truncated: true` flag if cut). If the document was ingested without `storeText: true`, text is unavailable \u2014 `textAvailable: false` flag is set and the agent should use `document_ask` for question-driven extraction instead. Pass `includeDownloadUrl: true` to also get a short-lived presigned `downloadUrl` for the original file (file-backed documents only). Returns the full document metadata, including its lifecycle `status` (ACTIVE, or ARCHIVED when soft-retracted from search \u2014 restorable via document_update) and its processing `indexStatus`.",
|
|
9553
9762
|
inputSchema: inputSchema10,
|
|
9554
9763
|
handler: async (args) => {
|
|
9555
|
-
const
|
|
9764
|
+
const documentId = args.documentId;
|
|
9765
|
+
const externalId = args.externalId;
|
|
9766
|
+
const type = args.type;
|
|
9556
9767
|
const includeText = args.includeText ?? false;
|
|
9557
9768
|
const includeDownloadUrl = args.includeDownloadUrl ?? false;
|
|
9558
9769
|
try {
|
|
9770
|
+
const resolved = await resolveDocumentIdByExternalId(client, { id: documentId, externalId, type });
|
|
9771
|
+
if ("error" in resolved) return toolError("document_get", new Error(resolved.error));
|
|
9772
|
+
const id = resolved.id;
|
|
9559
9773
|
const doc = await client.documents.getDocument({ id });
|
|
9560
9774
|
let extra = {};
|
|
9561
9775
|
if (includeText) {
|
|
@@ -9602,7 +9816,7 @@ var documentGet = ({ client, log }) => ({
|
|
|
9602
9816
|
]
|
|
9603
9817
|
};
|
|
9604
9818
|
} catch (err) {
|
|
9605
|
-
log.warn({ tool: "document_get",
|
|
9819
|
+
log.warn({ tool: "document_get", documentId, externalId, type, err: String(err) }, "document_get failed");
|
|
9606
9820
|
return toolError("document_get", err);
|
|
9607
9821
|
}
|
|
9608
9822
|
}
|
|
@@ -9717,13 +9931,23 @@ var document_query_default = documentQuery;
|
|
|
9717
9931
|
// src/tools/document_update.ts
|
|
9718
9932
|
var import_zod12 = require("zod");
|
|
9719
9933
|
var inputSchema12 = {
|
|
9720
|
-
documentId: import_zod12.z.string().
|
|
9934
|
+
documentId: import_zod12.z.string().optional().describe("The Vectros document id to update. Provide this OR externalId+type."),
|
|
9935
|
+
externalId: import_zod12.z.string().optional().describe(
|
|
9936
|
+
"Your caller-owned externalId \u2014 an alternative selector to `documentId` (requires `type`). Updates the document you ingested under that externalId without a manual lookup first."
|
|
9937
|
+
),
|
|
9938
|
+
type: import_zod12.z.string().optional().describe("Document type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9721
9939
|
title: import_zod12.z.string().optional().describe("New title. Omit to keep the current title."),
|
|
9722
9940
|
fields: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown()).optional().describe(
|
|
9723
9941
|
"Typed-payload field\u2192value changes DEEP-MERGED into the existing payload (a field set to `null` is deleted; unspecified fields preserved). Omit to leave the payload unchanged."
|
|
9724
9942
|
),
|
|
9943
|
+
text: import_zod12.z.string().optional().describe(
|
|
9944
|
+
"New raw text body. Supplying it re-ingests the document body and re-queues it for indexing, so the search index reflects the edit (text-ingested documents only \u2014 not file-backed ones). Omit to leave the stored text unchanged. This is the in-place alternative to re-ingesting with upsert:true."
|
|
9945
|
+
),
|
|
9725
9946
|
folderId: import_zod12.z.string().optional().describe("Move the document into this folder (cannot be cleared once set)."),
|
|
9726
9947
|
storeText: import_zod12.z.boolean().optional().describe("Whether the raw text is stored + retrievable."),
|
|
9948
|
+
status: import_zod12.z.enum(["ACTIVE", "ARCHIVED"]).optional().describe(
|
|
9949
|
+
"Lifecycle status. `ARCHIVED` soft-retracts the document \u2014 it is pulled from search and recall but kept and recoverable; set it back to `ACTIVE` to re-index and restore it. The way to retire superseded content when the credential has no delete authority. Omit to leave unchanged."
|
|
9950
|
+
),
|
|
9727
9951
|
userId: import_zod12.z.string().optional().describe("Reassign the owning user (Vectros UUID)."),
|
|
9728
9952
|
orgId: import_zod12.z.string().optional().describe("Reassign the owning org (Vectros UUID)."),
|
|
9729
9953
|
clientId: import_zod12.z.string().optional().describe("Reassign the associated client (Vectros UUID)."),
|
|
@@ -9734,33 +9958,41 @@ var inputSchema12 = {
|
|
|
9734
9958
|
var documentUpdate = ({ client, log }) => ({
|
|
9735
9959
|
name: "document_update",
|
|
9736
9960
|
title: "Update a document",
|
|
9737
|
-
description:
|
|
9961
|
+
description: 'Update a document \u2014 select it by its Vectros `documentId` OR by your own `externalId` + `type` (resolved for you). `fields` are DEEP-MERGED into the existing typed payload (unspecified fields preserved; a field set to `null` is deleted); title/folderId/status/ownership are updated when provided and preserved otherwise. Supply `text` to re-ingest and re-index the document body in place (text documents only). Set `status: "ARCHIVED"` to soft-retract a document (pulled from search, kept and recoverable) and `status: "ACTIVE"` to restore it. Pass `expectedVersion` (the version you last read) for safe concurrent edits \u2014 a stale update is refused (409). Requires the key to allow documents:u.',
|
|
9738
9962
|
inputSchema: inputSchema12,
|
|
9739
9963
|
handler: async (args) => {
|
|
9740
9964
|
const documentId = args.documentId;
|
|
9965
|
+
const externalId = args.externalId;
|
|
9966
|
+
const type = args.type;
|
|
9741
9967
|
const title = args.title;
|
|
9742
9968
|
const fields = args.fields;
|
|
9969
|
+
const text = args.text;
|
|
9743
9970
|
const folderId = args.folderId;
|
|
9744
9971
|
const storeText = args.storeText;
|
|
9972
|
+
const status = args.status;
|
|
9745
9973
|
const userId = args.userId;
|
|
9746
9974
|
const orgId = args.orgId;
|
|
9747
9975
|
const clientId = args.clientId;
|
|
9748
9976
|
const expectedVersion = args.expectedVersion;
|
|
9749
9977
|
try {
|
|
9978
|
+
const resolved = await resolveDocumentIdByExternalId(client, { id: documentId, externalId, type });
|
|
9979
|
+
if ("error" in resolved) return toolError("document_update", new Error(resolved.error));
|
|
9750
9980
|
const body = {};
|
|
9751
9981
|
if (title !== void 0) body.title = title;
|
|
9752
9982
|
if (fields !== void 0) body.payload = fields;
|
|
9983
|
+
if (text !== void 0) body.text = text;
|
|
9753
9984
|
if (folderId !== void 0) body.folderId = folderId;
|
|
9754
9985
|
if (storeText !== void 0) body.storeText = storeText;
|
|
9986
|
+
if (status !== void 0) body.status = status;
|
|
9755
9987
|
if (userId !== void 0) body.userId = userId;
|
|
9756
9988
|
if (orgId !== void 0) body.orgId = orgId;
|
|
9757
9989
|
if (clientId !== void 0) body.clientId = clientId;
|
|
9758
9990
|
if (expectedVersion !== void 0) body.expectedVersion = expectedVersion;
|
|
9759
9991
|
const updated = await client.documents.patchDocument({
|
|
9760
|
-
id:
|
|
9992
|
+
id: resolved.id,
|
|
9761
9993
|
body
|
|
9762
9994
|
});
|
|
9763
|
-
log.debug({ tool: "document_update", documentId }, "document_update ok");
|
|
9995
|
+
log.debug({ tool: "document_update", documentId: resolved.id, externalId }, "document_update ok");
|
|
9764
9996
|
return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
|
|
9765
9997
|
} catch (err) {
|
|
9766
9998
|
log.warn({ tool: "document_update", documentId, err: String(err) }, "document_update failed");
|
|
@@ -9778,7 +10010,7 @@ var inputSchema13 = {
|
|
|
9778
10010
|
var documentDelete = ({ client, log }) => ({
|
|
9779
10011
|
name: "document_delete",
|
|
9780
10012
|
title: "Delete a document",
|
|
9781
|
-
description:
|
|
10013
|
+
description: 'Permanently delete a document by id (removes it and its indexed content). Requires the key to allow documents:d \u2014 a key without it gets a permission error. To archive without deleting, use document_update to set status: "ARCHIVED" instead (recoverable, and needs no delete authority).',
|
|
9782
10014
|
inputSchema: inputSchema13,
|
|
9783
10015
|
handler: async (args) => {
|
|
9784
10016
|
const documentId = args.documentId;
|
|
@@ -9862,13 +10094,15 @@ var folderCreate = ({ client, log }) => ({
|
|
|
9862
10094
|
handler: async (args) => {
|
|
9863
10095
|
try {
|
|
9864
10096
|
const folder = await client.folders.createFolder({
|
|
9865
|
-
|
|
9866
|
-
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
10097
|
+
body: {
|
|
10098
|
+
name: args.name,
|
|
10099
|
+
description: args.description,
|
|
10100
|
+
parentFolderId: args.parentId,
|
|
10101
|
+
slug: args.slug,
|
|
10102
|
+
userId: args.userId,
|
|
10103
|
+
orgId: args.orgId,
|
|
10104
|
+
clientId: args.clientId
|
|
10105
|
+
}
|
|
9872
10106
|
});
|
|
9873
10107
|
log.debug({ tool: "folder_create", id: folder.id, name: folder.name }, "folder_create ok");
|
|
9874
10108
|
return { content: [{ type: "text", text: JSON.stringify(folder, null, 2) }] };
|
|
@@ -10056,6 +10290,9 @@ var inputSchema19 = {
|
|
|
10056
10290
|
externalId: import_zod18.z.string().optional().describe(
|
|
10057
10291
|
"Stable caller-supplied id. Immutable; unique per type within your context. Re-ingesting with the same externalId returns the existing document (idempotent) instead of creating a duplicate \u2014 use it to make ingests safely retryable and as the key other records reference. Mirrors record_create."
|
|
10058
10292
|
),
|
|
10293
|
+
upsert: import_zod18.z.boolean().optional().describe(
|
|
10294
|
+
"When true, re-ingesting an existing externalId OVERWRITES that document and re-indexes the new body (text mode) / re-uploads and re-indexes the new file (file mode), instead of returning the existing one unchanged. This is the curation/re-sync primitive: edit a source, re-ingest with upsert:true, and the search index reflects the new content. Requires the documents:u scope. IMPORTANT: pass the SAME schemaId (and type) you used originally \u2014 externalId is unique WITHIN a type, so omitting schemaId resolves in the untyped namespace and mints a duplicate instead of updating. The response `created` flag confirms which happened (created:true = a new document was minted)."
|
|
10295
|
+
),
|
|
10059
10296
|
schemaId: import_zod18.z.string().optional().describe(
|
|
10060
10297
|
"Bind this document to a record schema. When set, `payload` is validated against the schema and its lookup fields become directly queryable via document_query (records parity). Resolve a schema id from its type via list_schemas. Omit for an untyped document."
|
|
10061
10298
|
),
|
|
@@ -10081,13 +10318,14 @@ var inputSchema19 = {
|
|
|
10081
10318
|
var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
10082
10319
|
name: "document_ingest",
|
|
10083
10320
|
title: "Ingest a new document (text body or file upload)",
|
|
10084
|
-
description: "Create a new document in
|
|
10321
|
+
description: "Create a new document in your Vectros tenant. Two modes:\n \u2022 Text mode: pass `text` (string body). Single-call. Use for crawled content, notes, generated text.\n \u2022 File mode: pass `filePath` (local path on the MCP server's host machine). STDIO-TRANSPORT ONLY \u2014 rejected on HTTP transport. MCP server reads the bytes, requests a presigned upload URL, and PUTs them. Returns when the upload is accepted (indexStatus: PENDING_INDEX); poll with `document_get` until indexStatus is INDEXED.\nEither `text` or `filePath` must be present; both is an error. Idempotent by `externalId` (re-ingest returns the existing document, not a duplicate). To UPDATE an existing document instead \u2014 re-index an edited body \u2014 pass `upsert:true` with the same `externalId` (and the same `schemaId`); this is the re-sync primitive for keeping a knowledge base current. Pass `schemaId` + `payload` for a typed, lookup-queryable document (records parity). indexMode defaults to HYBRID for untyped documents (omit to inherit a bound schema's default). storeText defaults to true (set false to skip storing the text body).",
|
|
10085
10322
|
inputSchema: inputSchema19,
|
|
10086
10323
|
handler: async (args) => {
|
|
10087
10324
|
const title = args.title;
|
|
10088
10325
|
const text = args.text;
|
|
10089
10326
|
const filePath = args.filePath;
|
|
10090
10327
|
const schemaId = args.schemaId;
|
|
10328
|
+
const upsert = args.upsert;
|
|
10091
10329
|
const indexMode = args.indexMode ?? (schemaId ? void 0 : "HYBRID");
|
|
10092
10330
|
if (!text && !filePath) {
|
|
10093
10331
|
return toolError(
|
|
@@ -10122,11 +10360,14 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10122
10360
|
if (text) {
|
|
10123
10361
|
const storeText = args.storeText ?? true;
|
|
10124
10362
|
const result = await client.documents.ingestDocument({
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10363
|
+
upsert,
|
|
10364
|
+
body: {
|
|
10365
|
+
title,
|
|
10366
|
+
text,
|
|
10367
|
+
indexMode,
|
|
10368
|
+
storeText,
|
|
10369
|
+
...common
|
|
10370
|
+
}
|
|
10130
10371
|
});
|
|
10131
10372
|
log.debug(
|
|
10132
10373
|
{ tool: "document_ingest", mode: "text", id: result?.id, indexMode },
|
|
@@ -10156,6 +10397,7 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10156
10397
|
const fileName = (0, import_node_path.basename)(safePath);
|
|
10157
10398
|
const fileType = args.fileType ?? inferMimeType(safePath);
|
|
10158
10399
|
const upload = await client.documents.uploadDocument({
|
|
10400
|
+
upsert,
|
|
10159
10401
|
fileName,
|
|
10160
10402
|
fileType,
|
|
10161
10403
|
indexMode,
|
|
@@ -10194,8 +10436,8 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10194
10436
|
text: JSON.stringify(
|
|
10195
10437
|
{
|
|
10196
10438
|
...upload,
|
|
10197
|
-
|
|
10198
|
-
_note: "File uploaded; indexing is asynchronous. Poll document_get(id) until
|
|
10439
|
+
indexStatus: "PENDING_INDEX",
|
|
10440
|
+
_note: "File uploaded; indexing is asynchronous. Poll document_get(id) until indexStatus is INDEXED."
|
|
10199
10441
|
},
|
|
10200
10442
|
null,
|
|
10201
10443
|
2
|
|
@@ -10492,6 +10734,14 @@ function zodTypeToJsonSchema(schema) {
|
|
|
10492
10734
|
|
|
10493
10735
|
// src/server.ts
|
|
10494
10736
|
var DEFAULT_ENVIRONMENT = "https://api.vectros.ai";
|
|
10737
|
+
function formatArgError(tool, error) {
|
|
10738
|
+
const unknownKeys = error.issues.filter((i) => i.code === "unrecognized_keys").flatMap((i) => i.keys);
|
|
10739
|
+
if (unknownKeys.length > 0) {
|
|
10740
|
+
const valid = Object.keys(tool.inputSchema).join(", ");
|
|
10741
|
+
return `Unknown argument(s): ${unknownKeys.join(", ")}. Valid arguments for ${tool.name}: ${valid}. Pass only these \u2014 an unrecognized argument is rejected, not ignored.`;
|
|
10742
|
+
}
|
|
10743
|
+
return `Invalid arguments: ${error.message}`;
|
|
10744
|
+
}
|
|
10495
10745
|
var VectrosMCPServer = class {
|
|
10496
10746
|
server;
|
|
10497
10747
|
log;
|
|
@@ -10581,7 +10831,11 @@ var VectrosMCPServer = class {
|
|
|
10581
10831
|
name: t.name,
|
|
10582
10832
|
title: t.title,
|
|
10583
10833
|
description: t.description,
|
|
10584
|
-
|
|
10834
|
+
// additionalProperties:false advertises strict argument validation to the
|
|
10835
|
+
// MCP client (a well-behaved client rejects an unknown key before the call).
|
|
10836
|
+
// The server enforces it too (z.object(...).strict() below) so a raw JSON-RPC
|
|
10837
|
+
// call that skips client validation is still rejected — belt and suspenders.
|
|
10838
|
+
inputSchema: { ...zodShapeToJsonSchema(t.inputSchema), additionalProperties: false }
|
|
10585
10839
|
}))
|
|
10586
10840
|
})
|
|
10587
10841
|
);
|
|
@@ -10591,9 +10845,9 @@ var VectrosMCPServer = class {
|
|
|
10591
10845
|
if (!tool) {
|
|
10592
10846
|
result = toolError(req.params.name ?? "unknown", new Error("No such tool."));
|
|
10593
10847
|
} else {
|
|
10594
|
-
const parsed = import_zod22.z.object(tool.inputSchema).safeParse(req.params.arguments ?? {});
|
|
10848
|
+
const parsed = import_zod22.z.object(tool.inputSchema).strict().safeParse(req.params.arguments ?? {});
|
|
10595
10849
|
if (!parsed.success) {
|
|
10596
|
-
result = toolError(tool.name, new Error(
|
|
10850
|
+
result = toolError(tool.name, new Error(formatArgError(tool, parsed.error)));
|
|
10597
10851
|
} else {
|
|
10598
10852
|
try {
|
|
10599
10853
|
result = await tool.handler(
|