@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.mjs
CHANGED
|
@@ -479,10 +479,18 @@ var DocumentRequest;
|
|
|
479
479
|
Text: "TEXT",
|
|
480
480
|
None: "NONE"
|
|
481
481
|
};
|
|
482
|
+
DocumentRequest2.Status = {
|
|
483
|
+
Active: "ACTIVE",
|
|
484
|
+
Archived: "ARCHIVED"
|
|
485
|
+
};
|
|
482
486
|
})(DocumentRequest || (DocumentRequest = {}));
|
|
483
487
|
var DocumentResponse;
|
|
484
488
|
((DocumentResponse2) => {
|
|
485
489
|
DocumentResponse2.Status = {
|
|
490
|
+
Active: "ACTIVE",
|
|
491
|
+
Archived: "ARCHIVED"
|
|
492
|
+
};
|
|
493
|
+
DocumentResponse2.IndexStatus = {
|
|
486
494
|
PendingUpload: "PENDING_UPLOAD",
|
|
487
495
|
Uploaded: "UPLOADED",
|
|
488
496
|
Extracting: "EXTRACTING",
|
|
@@ -2836,7 +2844,7 @@ var AuthClient = class {
|
|
|
2836
2844
|
);
|
|
2837
2845
|
}
|
|
2838
2846
|
/**
|
|
2839
|
-
* 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.
|
|
2847
|
+
* 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.
|
|
2840
2848
|
*
|
|
2841
2849
|
* @param {Vectros.CreateAccessProfileRequest} request
|
|
2842
2850
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -2858,7 +2866,10 @@ var AuthClient = class {
|
|
|
2858
2866
|
return HttpResponsePromise.fromPromise(this.__createAccessProfile(request, requestOptions));
|
|
2859
2867
|
}
|
|
2860
2868
|
async __createAccessProfile(request, requestOptions) {
|
|
2861
|
-
const { contextId, body: _body } = request;
|
|
2869
|
+
const { contextId, upsert, body: _body } = request;
|
|
2870
|
+
const _queryParams = {
|
|
2871
|
+
upsert
|
|
2872
|
+
};
|
|
2862
2873
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
2863
2874
|
const _headers = mergeHeaders(
|
|
2864
2875
|
_authRequest.headers,
|
|
@@ -2873,7 +2884,7 @@ var AuthClient = class {
|
|
|
2873
2884
|
method: "POST",
|
|
2874
2885
|
headers: _headers,
|
|
2875
2886
|
contentType: "application/json",
|
|
2876
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
2887
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
2877
2888
|
requestType: "json",
|
|
2878
2889
|
body: _body,
|
|
2879
2890
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -2968,9 +2979,9 @@ var AuthClient = class {
|
|
|
2968
2979
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/app-contexts");
|
|
2969
2980
|
}
|
|
2970
2981
|
/**
|
|
2971
|
-
* 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.
|
|
2982
|
+
* 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.
|
|
2972
2983
|
*
|
|
2973
|
-
* @param {Vectros.
|
|
2984
|
+
* @param {Vectros.CreateAppContextRequest} request
|
|
2974
2985
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
2975
2986
|
*
|
|
2976
2987
|
* @throws {@link Vectros.BadRequestError}
|
|
@@ -2979,14 +2990,20 @@ var AuthClient = class {
|
|
|
2979
2990
|
*
|
|
2980
2991
|
* @example
|
|
2981
2992
|
* await client.auth.createAppContext({
|
|
2982
|
-
*
|
|
2983
|
-
*
|
|
2993
|
+
* body: {
|
|
2994
|
+
* contextId: "myapp",
|
|
2995
|
+
* name: "My Internal App"
|
|
2996
|
+
* }
|
|
2984
2997
|
* })
|
|
2985
2998
|
*/
|
|
2986
2999
|
createAppContext(request, requestOptions) {
|
|
2987
3000
|
return HttpResponsePromise.fromPromise(this.__createAppContext(request, requestOptions));
|
|
2988
3001
|
}
|
|
2989
3002
|
async __createAppContext(request, requestOptions) {
|
|
3003
|
+
const { upsert, body: _body } = request;
|
|
3004
|
+
const _queryParams = {
|
|
3005
|
+
upsert
|
|
3006
|
+
};
|
|
2990
3007
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
2991
3008
|
const _headers = mergeHeaders(
|
|
2992
3009
|
_authRequest.headers,
|
|
@@ -3001,9 +3018,9 @@ var AuthClient = class {
|
|
|
3001
3018
|
method: "POST",
|
|
3002
3019
|
headers: _headers,
|
|
3003
3020
|
contentType: "application/json",
|
|
3004
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
3021
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
3005
3022
|
requestType: "json",
|
|
3006
|
-
body:
|
|
3023
|
+
body: _body,
|
|
3007
3024
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
3008
3025
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
3009
3026
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -3099,7 +3116,7 @@ var AuthClient = class {
|
|
|
3099
3116
|
);
|
|
3100
3117
|
}
|
|
3101
3118
|
/**
|
|
3102
|
-
* 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.
|
|
3119
|
+
* 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.
|
|
3103
3120
|
*
|
|
3104
3121
|
* @param {Vectros.CreateRoleRequest} request
|
|
3105
3122
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -3125,7 +3142,10 @@ var AuthClient = class {
|
|
|
3125
3142
|
return HttpResponsePromise.fromPromise(this.__createRole(request, requestOptions));
|
|
3126
3143
|
}
|
|
3127
3144
|
async __createRole(request, requestOptions) {
|
|
3128
|
-
const { contextId, body: _body } = request;
|
|
3145
|
+
const { contextId, upsert, body: _body } = request;
|
|
3146
|
+
const _queryParams = {
|
|
3147
|
+
upsert
|
|
3148
|
+
};
|
|
3129
3149
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
3130
3150
|
const _headers = mergeHeaders(
|
|
3131
3151
|
_authRequest.headers,
|
|
@@ -3140,7 +3160,7 @@ var AuthClient = class {
|
|
|
3140
3160
|
method: "POST",
|
|
3141
3161
|
headers: _headers,
|
|
3142
3162
|
contentType: "application/json",
|
|
3143
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
3163
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
3144
3164
|
requestType: "json",
|
|
3145
3165
|
body: _body,
|
|
3146
3166
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -4624,23 +4644,30 @@ var DocumentsClient = class {
|
|
|
4624
4644
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents");
|
|
4625
4645
|
}
|
|
4626
4646
|
/**
|
|
4627
|
-
* Creates a document from a raw text string and queues it for asynchronous indexing so it becomes searchable. Requires the `documents:c` scope.
|
|
4647
|
+
* 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.
|
|
4628
4648
|
*
|
|
4629
|
-
* @param {Vectros.
|
|
4649
|
+
* @param {Vectros.IngestDocumentRequest} request
|
|
4630
4650
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4631
4651
|
*
|
|
4632
4652
|
* @throws {@link Vectros.BadRequestError}
|
|
4653
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4633
4654
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
4634
4655
|
*
|
|
4635
4656
|
* @example
|
|
4636
4657
|
* await client.documents.ingestDocument({
|
|
4637
|
-
*
|
|
4658
|
+
* body: {
|
|
4659
|
+
* title: "Patient Intake Form \u2014 Jane Doe"
|
|
4660
|
+
* }
|
|
4638
4661
|
* })
|
|
4639
4662
|
*/
|
|
4640
4663
|
ingestDocument(request, requestOptions) {
|
|
4641
4664
|
return HttpResponsePromise.fromPromise(this.__ingestDocument(request, requestOptions));
|
|
4642
4665
|
}
|
|
4643
4666
|
async __ingestDocument(request, requestOptions) {
|
|
4667
|
+
const { upsert, body: _body } = request;
|
|
4668
|
+
const _queryParams = {
|
|
4669
|
+
upsert
|
|
4670
|
+
};
|
|
4644
4671
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4645
4672
|
const _headers = mergeHeaders(
|
|
4646
4673
|
_authRequest.headers,
|
|
@@ -4655,9 +4682,9 @@ var DocumentsClient = class {
|
|
|
4655
4682
|
method: "POST",
|
|
4656
4683
|
headers: _headers,
|
|
4657
4684
|
contentType: "application/json",
|
|
4658
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4685
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
4659
4686
|
requestType: "json",
|
|
4660
|
-
body:
|
|
4687
|
+
body: _body,
|
|
4661
4688
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4662
4689
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4663
4690
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -4671,6 +4698,8 @@ var DocumentsClient = class {
|
|
|
4671
4698
|
switch (_response.error.statusCode) {
|
|
4672
4699
|
case 400:
|
|
4673
4700
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
4701
|
+
case 403:
|
|
4702
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4674
4703
|
case 429:
|
|
4675
4704
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4676
4705
|
default:
|
|
@@ -4937,7 +4966,7 @@ var DocumentsClient = class {
|
|
|
4937
4966
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "PATCH", "/v1/documents/{id}");
|
|
4938
4967
|
}
|
|
4939
4968
|
/**
|
|
4940
|
-
* Finds documents of a given type by
|
|
4969
|
+
* 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.
|
|
4941
4970
|
*
|
|
4942
4971
|
* @param {Vectros.LookupDocumentsRequest} request
|
|
4943
4972
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -5232,12 +5261,13 @@ var DocumentsClient = class {
|
|
|
5232
5261
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/{id}/versions");
|
|
5233
5262
|
}
|
|
5234
5263
|
/**
|
|
5235
|
-
* 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.
|
|
5264
|
+
* 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).
|
|
5236
5265
|
*
|
|
5237
5266
|
* @param {Vectros.FileUploadRequest} request
|
|
5238
5267
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5239
5268
|
*
|
|
5240
5269
|
* @throws {@link Vectros.BadRequestError}
|
|
5270
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5241
5271
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5242
5272
|
*
|
|
5243
5273
|
* @example
|
|
@@ -5250,6 +5280,10 @@ var DocumentsClient = class {
|
|
|
5250
5280
|
return HttpResponsePromise.fromPromise(this.__uploadDocument(request, requestOptions));
|
|
5251
5281
|
}
|
|
5252
5282
|
async __uploadDocument(request, requestOptions) {
|
|
5283
|
+
const { upsert, ..._body } = request;
|
|
5284
|
+
const _queryParams = {
|
|
5285
|
+
upsert
|
|
5286
|
+
};
|
|
5253
5287
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5254
5288
|
const _headers = mergeHeaders(
|
|
5255
5289
|
_authRequest.headers,
|
|
@@ -5264,9 +5298,9 @@ var DocumentsClient = class {
|
|
|
5264
5298
|
method: "POST",
|
|
5265
5299
|
headers: _headers,
|
|
5266
5300
|
contentType: "application/json",
|
|
5267
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5301
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5268
5302
|
requestType: "json",
|
|
5269
|
-
body:
|
|
5303
|
+
body: _body,
|
|
5270
5304
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5271
5305
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5272
5306
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5280,6 +5314,8 @@ var DocumentsClient = class {
|
|
|
5280
5314
|
switch (_response.error.statusCode) {
|
|
5281
5315
|
case 400:
|
|
5282
5316
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5317
|
+
case 403:
|
|
5318
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5283
5319
|
case 429:
|
|
5284
5320
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5285
5321
|
default:
|
|
@@ -5358,23 +5394,30 @@ var FoldersClient = class {
|
|
|
5358
5394
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/folders");
|
|
5359
5395
|
}
|
|
5360
5396
|
/**
|
|
5361
|
-
* 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.
|
|
5397
|
+
* 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.
|
|
5362
5398
|
*
|
|
5363
|
-
* @param {Vectros.
|
|
5399
|
+
* @param {Vectros.CreateFolderRequest} request
|
|
5364
5400
|
* @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5365
5401
|
*
|
|
5366
5402
|
* @throws {@link Vectros.BadRequestError}
|
|
5403
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5367
5404
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5368
5405
|
*
|
|
5369
5406
|
* @example
|
|
5370
5407
|
* await client.folders.createFolder({
|
|
5371
|
-
*
|
|
5408
|
+
* body: {
|
|
5409
|
+
* name: "Patient Records 2024"
|
|
5410
|
+
* }
|
|
5372
5411
|
* })
|
|
5373
5412
|
*/
|
|
5374
5413
|
createFolder(request, requestOptions) {
|
|
5375
5414
|
return HttpResponsePromise.fromPromise(this.__createFolder(request, requestOptions));
|
|
5376
5415
|
}
|
|
5377
5416
|
async __createFolder(request, requestOptions) {
|
|
5417
|
+
const { upsert, body: _body } = request;
|
|
5418
|
+
const _queryParams = {
|
|
5419
|
+
upsert
|
|
5420
|
+
};
|
|
5378
5421
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5379
5422
|
const _headers = mergeHeaders(
|
|
5380
5423
|
_authRequest.headers,
|
|
@@ -5389,9 +5432,9 @@ var FoldersClient = class {
|
|
|
5389
5432
|
method: "POST",
|
|
5390
5433
|
headers: _headers,
|
|
5391
5434
|
contentType: "application/json",
|
|
5392
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5435
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5393
5436
|
requestType: "json",
|
|
5394
|
-
body:
|
|
5437
|
+
body: _body,
|
|
5395
5438
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5396
5439
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5397
5440
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5405,6 +5448,8 @@ var FoldersClient = class {
|
|
|
5405
5448
|
switch (_response.error.statusCode) {
|
|
5406
5449
|
case 400:
|
|
5407
5450
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5451
|
+
case 403:
|
|
5452
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5408
5453
|
case 429:
|
|
5409
5454
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5410
5455
|
default:
|
|
@@ -5813,23 +5858,30 @@ var IdentityClient = class {
|
|
|
5813
5858
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/clients");
|
|
5814
5859
|
}
|
|
5815
5860
|
/**
|
|
5816
|
-
* 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.
|
|
5861
|
+
* 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.
|
|
5817
5862
|
*
|
|
5818
|
-
* @param {Vectros.
|
|
5863
|
+
* @param {Vectros.CreateClientRequest} request
|
|
5819
5864
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5820
5865
|
*
|
|
5821
5866
|
* @throws {@link Vectros.BadRequestError}
|
|
5867
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5822
5868
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5823
5869
|
*
|
|
5824
5870
|
* @example
|
|
5825
5871
|
* await client.identity.createClient({
|
|
5826
|
-
*
|
|
5872
|
+
* body: {
|
|
5873
|
+
* externalId: "patient_789"
|
|
5874
|
+
* }
|
|
5827
5875
|
* })
|
|
5828
5876
|
*/
|
|
5829
5877
|
createClient(request, requestOptions) {
|
|
5830
5878
|
return HttpResponsePromise.fromPromise(this.__createClient(request, requestOptions));
|
|
5831
5879
|
}
|
|
5832
5880
|
async __createClient(request, requestOptions) {
|
|
5881
|
+
const { upsert, body: _body } = request;
|
|
5882
|
+
const _queryParams = {
|
|
5883
|
+
upsert
|
|
5884
|
+
};
|
|
5833
5885
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5834
5886
|
const _headers = mergeHeaders(
|
|
5835
5887
|
_authRequest.headers,
|
|
@@ -5844,9 +5896,9 @@ var IdentityClient = class {
|
|
|
5844
5896
|
method: "POST",
|
|
5845
5897
|
headers: _headers,
|
|
5846
5898
|
contentType: "application/json",
|
|
5847
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5899
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5848
5900
|
requestType: "json",
|
|
5849
|
-
body:
|
|
5901
|
+
body: _body,
|
|
5850
5902
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5851
5903
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5852
5904
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5860,6 +5912,8 @@ var IdentityClient = class {
|
|
|
5860
5912
|
switch (_response.error.statusCode) {
|
|
5861
5913
|
case 400:
|
|
5862
5914
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5915
|
+
case 403:
|
|
5916
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5863
5917
|
case 429:
|
|
5864
5918
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5865
5919
|
default:
|
|
@@ -6248,23 +6302,30 @@ var IdentityClient = class {
|
|
|
6248
6302
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/orgs");
|
|
6249
6303
|
}
|
|
6250
6304
|
/**
|
|
6251
|
-
* 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.
|
|
6305
|
+
* 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.
|
|
6252
6306
|
*
|
|
6253
|
-
* @param {Vectros.
|
|
6307
|
+
* @param {Vectros.CreateOrgRequest} request
|
|
6254
6308
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6255
6309
|
*
|
|
6256
6310
|
* @throws {@link Vectros.BadRequestError}
|
|
6311
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
6257
6312
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6258
6313
|
*
|
|
6259
6314
|
* @example
|
|
6260
6315
|
* await client.identity.createOrg({
|
|
6261
|
-
*
|
|
6316
|
+
* body: {
|
|
6317
|
+
* externalId: "clinic_001"
|
|
6318
|
+
* }
|
|
6262
6319
|
* })
|
|
6263
6320
|
*/
|
|
6264
6321
|
createOrg(request, requestOptions) {
|
|
6265
6322
|
return HttpResponsePromise.fromPromise(this.__createOrg(request, requestOptions));
|
|
6266
6323
|
}
|
|
6267
6324
|
async __createOrg(request, requestOptions) {
|
|
6325
|
+
const { upsert, body: _body } = request;
|
|
6326
|
+
const _queryParams = {
|
|
6327
|
+
upsert
|
|
6328
|
+
};
|
|
6268
6329
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
6269
6330
|
const _headers = mergeHeaders(
|
|
6270
6331
|
_authRequest.headers,
|
|
@@ -6279,9 +6340,9 @@ var IdentityClient = class {
|
|
|
6279
6340
|
method: "POST",
|
|
6280
6341
|
headers: _headers,
|
|
6281
6342
|
contentType: "application/json",
|
|
6282
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
6343
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
6283
6344
|
requestType: "json",
|
|
6284
|
-
body:
|
|
6345
|
+
body: _body,
|
|
6285
6346
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
6286
6347
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
6287
6348
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -6295,6 +6356,8 @@ var IdentityClient = class {
|
|
|
6295
6356
|
switch (_response.error.statusCode) {
|
|
6296
6357
|
case 400:
|
|
6297
6358
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6359
|
+
case 403:
|
|
6360
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
6298
6361
|
case 429:
|
|
6299
6362
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
6300
6363
|
default:
|
|
@@ -6669,23 +6732,30 @@ var IdentityClient = class {
|
|
|
6669
6732
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users");
|
|
6670
6733
|
}
|
|
6671
6734
|
/**
|
|
6672
|
-
* 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.
|
|
6735
|
+
* 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.
|
|
6673
6736
|
*
|
|
6674
|
-
* @param {Vectros.
|
|
6737
|
+
* @param {Vectros.CreateUserRequest} request
|
|
6675
6738
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6676
6739
|
*
|
|
6677
6740
|
* @throws {@link Vectros.BadRequestError}
|
|
6741
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
6678
6742
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6679
6743
|
*
|
|
6680
6744
|
* @example
|
|
6681
6745
|
* await client.identity.createUser({
|
|
6682
|
-
*
|
|
6746
|
+
* body: {
|
|
6747
|
+
* externalId: "usr_12345"
|
|
6748
|
+
* }
|
|
6683
6749
|
* })
|
|
6684
6750
|
*/
|
|
6685
6751
|
createUser(request, requestOptions) {
|
|
6686
6752
|
return HttpResponsePromise.fromPromise(this.__createUser(request, requestOptions));
|
|
6687
6753
|
}
|
|
6688
6754
|
async __createUser(request, requestOptions) {
|
|
6755
|
+
const { upsert, body: _body } = request;
|
|
6756
|
+
const _queryParams = {
|
|
6757
|
+
upsert
|
|
6758
|
+
};
|
|
6689
6759
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
6690
6760
|
const _headers = mergeHeaders(
|
|
6691
6761
|
_authRequest.headers,
|
|
@@ -6700,9 +6770,9 @@ var IdentityClient = class {
|
|
|
6700
6770
|
method: "POST",
|
|
6701
6771
|
headers: _headers,
|
|
6702
6772
|
contentType: "application/json",
|
|
6703
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
6773
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
6704
6774
|
requestType: "json",
|
|
6705
|
-
body:
|
|
6775
|
+
body: _body,
|
|
6706
6776
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
6707
6777
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
6708
6778
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -6716,6 +6786,8 @@ var IdentityClient = class {
|
|
|
6716
6786
|
switch (_response.error.statusCode) {
|
|
6717
6787
|
case 400:
|
|
6718
6788
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6789
|
+
case 403:
|
|
6790
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
6719
6791
|
case 429:
|
|
6720
6792
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
6721
6793
|
default:
|
|
@@ -7533,9 +7605,9 @@ var RecordsClient = class {
|
|
|
7533
7605
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/records");
|
|
7534
7606
|
}
|
|
7535
7607
|
/**
|
|
7536
|
-
* 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.
|
|
7608
|
+
* 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.
|
|
7537
7609
|
*
|
|
7538
|
-
* @param {Vectros.
|
|
7610
|
+
* @param {Vectros.CreateRecordRequest} request
|
|
7539
7611
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7540
7612
|
*
|
|
7541
7613
|
* @throws {@link Vectros.BadRequestError}
|
|
@@ -7544,19 +7616,25 @@ var RecordsClient = class {
|
|
|
7544
7616
|
*
|
|
7545
7617
|
* @example
|
|
7546
7618
|
* await client.records.createRecord({
|
|
7547
|
-
*
|
|
7548
|
-
*
|
|
7549
|
-
*
|
|
7550
|
-
*
|
|
7551
|
-
*
|
|
7552
|
-
*
|
|
7553
|
-
*
|
|
7619
|
+
* body: {
|
|
7620
|
+
* typeName: "intake_form",
|
|
7621
|
+
* schemaId: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
7622
|
+
* payload: {
|
|
7623
|
+
* "first_name": "Jane",
|
|
7624
|
+
* "email": "jane@example.com"
|
|
7625
|
+
* },
|
|
7626
|
+
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
7627
|
+
* }
|
|
7554
7628
|
* })
|
|
7555
7629
|
*/
|
|
7556
7630
|
createRecord(request, requestOptions) {
|
|
7557
7631
|
return HttpResponsePromise.fromPromise(this.__createRecord(request, requestOptions));
|
|
7558
7632
|
}
|
|
7559
7633
|
async __createRecord(request, requestOptions) {
|
|
7634
|
+
const { upsert, body: _body } = request;
|
|
7635
|
+
const _queryParams = {
|
|
7636
|
+
upsert
|
|
7637
|
+
};
|
|
7560
7638
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
7561
7639
|
const _headers = mergeHeaders(
|
|
7562
7640
|
_authRequest.headers,
|
|
@@ -7571,9 +7649,9 @@ var RecordsClient = class {
|
|
|
7571
7649
|
method: "POST",
|
|
7572
7650
|
headers: _headers,
|
|
7573
7651
|
contentType: "application/json",
|
|
7574
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
7652
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
7575
7653
|
requestType: "json",
|
|
7576
|
-
body:
|
|
7654
|
+
body: _body,
|
|
7577
7655
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
7578
7656
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
7579
7657
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -8169,43 +8247,50 @@ var SchemasClient = class {
|
|
|
8169
8247
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/schemas");
|
|
8170
8248
|
}
|
|
8171
8249
|
/**
|
|
8172
|
-
* 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.
|
|
8250
|
+
* 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.
|
|
8173
8251
|
*
|
|
8174
|
-
* @param {Vectros.
|
|
8252
|
+
* @param {Vectros.CreateSchemaRequest} request
|
|
8175
8253
|
* @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
8176
8254
|
*
|
|
8177
8255
|
* @throws {@link Vectros.BadRequestError}
|
|
8256
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
8178
8257
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
8179
8258
|
*
|
|
8180
8259
|
* @example
|
|
8181
8260
|
* await client.schemas.createSchema({
|
|
8182
|
-
*
|
|
8183
|
-
*
|
|
8184
|
-
*
|
|
8185
|
-
*
|
|
8186
|
-
*
|
|
8187
|
-
*
|
|
8188
|
-
*
|
|
8189
|
-
*
|
|
8190
|
-
*
|
|
8191
|
-
*
|
|
8192
|
-
*
|
|
8193
|
-
*
|
|
8194
|
-
*
|
|
8195
|
-
*
|
|
8196
|
-
*
|
|
8197
|
-
*
|
|
8198
|
-
*
|
|
8199
|
-
*
|
|
8200
|
-
*
|
|
8201
|
-
*
|
|
8202
|
-
*
|
|
8261
|
+
* body: {
|
|
8262
|
+
* typeName: "intake_form",
|
|
8263
|
+
* displayName: "Client Intake Form",
|
|
8264
|
+
* description: "Captures initial client information",
|
|
8265
|
+
* fields: [{
|
|
8266
|
+
* fieldId: "first_name",
|
|
8267
|
+
* fieldType: "string",
|
|
8268
|
+
* required: true,
|
|
8269
|
+
* searchable: true
|
|
8270
|
+
* }, {
|
|
8271
|
+
* fieldId: "email",
|
|
8272
|
+
* fieldType: "string",
|
|
8273
|
+
* required: true
|
|
8274
|
+
* }],
|
|
8275
|
+
* lookupFields: [{
|
|
8276
|
+
* fieldName: "email",
|
|
8277
|
+
* unique: true
|
|
8278
|
+
* }],
|
|
8279
|
+
* capabilities: {
|
|
8280
|
+
* "auditHistory": true
|
|
8281
|
+
* },
|
|
8282
|
+
* allowedSurfaces: ["record"]
|
|
8283
|
+
* }
|
|
8203
8284
|
* })
|
|
8204
8285
|
*/
|
|
8205
8286
|
createSchema(request, requestOptions) {
|
|
8206
8287
|
return HttpResponsePromise.fromPromise(this.__createSchema(request, requestOptions));
|
|
8207
8288
|
}
|
|
8208
8289
|
async __createSchema(request, requestOptions) {
|
|
8290
|
+
const { upsert, body: _body } = request;
|
|
8291
|
+
const _queryParams = {
|
|
8292
|
+
upsert
|
|
8293
|
+
};
|
|
8209
8294
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
8210
8295
|
const _headers = mergeHeaders(
|
|
8211
8296
|
_authRequest.headers,
|
|
@@ -8220,9 +8305,9 @@ var SchemasClient = class {
|
|
|
8220
8305
|
method: "POST",
|
|
8221
8306
|
headers: _headers,
|
|
8222
8307
|
contentType: "application/json",
|
|
8223
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
8308
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
8224
8309
|
requestType: "json",
|
|
8225
|
-
body:
|
|
8310
|
+
body: _body,
|
|
8226
8311
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
8227
8312
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
8228
8313
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -8236,6 +8321,8 @@ var SchemasClient = class {
|
|
|
8236
8321
|
switch (_response.error.statusCode) {
|
|
8237
8322
|
case 400:
|
|
8238
8323
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8324
|
+
case 403:
|
|
8325
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
8239
8326
|
case 429:
|
|
8240
8327
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
8241
8328
|
default:
|
|
@@ -8675,8 +8762,8 @@ function warnOnSuboptimalKey(key, log) {
|
|
|
8675
8762
|
|
|
8676
8763
|
// src/build-info.ts
|
|
8677
8764
|
var BUILD_INFO = {
|
|
8678
|
-
mcpServer: true ? "0.
|
|
8679
|
-
sdk: true ? "0.
|
|
8765
|
+
mcpServer: true ? "0.6.0" : "dev",
|
|
8766
|
+
sdk: true ? "0.32.0" : "dev"
|
|
8680
8767
|
};
|
|
8681
8768
|
|
|
8682
8769
|
// src/log.ts
|
|
@@ -8913,6 +9000,32 @@ ${detail}${pointer}`
|
|
|
8913
9000
|
// src/tools/hybrid_search.ts
|
|
8914
9001
|
var MCP_DEFAULT_LIMIT = 3;
|
|
8915
9002
|
var MCP_MAX_LIMIT = 10;
|
|
9003
|
+
var MCP_RESPONSE_CHAR_BUDGET = 24e3;
|
|
9004
|
+
var SNIPPET_MAX_CHARS = 160;
|
|
9005
|
+
var INTERNAL_METADATA_KEYS = /* @__PURE__ */ new Set(["tenantId", "owner_id", "model_type", "rootFolderId", "folderId"]);
|
|
9006
|
+
function trimMetadata(md) {
|
|
9007
|
+
if (!md || typeof md !== "object" || Array.isArray(md)) return md;
|
|
9008
|
+
const out = {};
|
|
9009
|
+
for (const [k, v] of Object.entries(md)) {
|
|
9010
|
+
if (!INTERNAL_METADATA_KEYS.has(k)) out[k] = v;
|
|
9011
|
+
}
|
|
9012
|
+
return out;
|
|
9013
|
+
}
|
|
9014
|
+
function reshapeHit(hit, includeContext) {
|
|
9015
|
+
const out = { ...hit };
|
|
9016
|
+
if ("metadata" in out) out.metadata = trimMetadata(out.metadata);
|
|
9017
|
+
const chunk = typeof hit.chunkText === "string" ? hit.chunkText : void 0;
|
|
9018
|
+
const ctx = typeof hit.contextText === "string" ? hit.contextText : void 0;
|
|
9019
|
+
if (includeContext) {
|
|
9020
|
+
if (chunk && ctx && ctx.includes(chunk)) delete out.chunkText;
|
|
9021
|
+
} else {
|
|
9022
|
+
delete out.contextText;
|
|
9023
|
+
}
|
|
9024
|
+
if ((out.snippet == null || out.snippet === "") && chunk) {
|
|
9025
|
+
out.snippet = chunk.length > SNIPPET_MAX_CHARS ? chunk.slice(0, SNIPPET_MAX_CHARS) + "\u2026" : chunk;
|
|
9026
|
+
}
|
|
9027
|
+
return out;
|
|
9028
|
+
}
|
|
8916
9029
|
var inputSchema = {
|
|
8917
9030
|
query: z.string().min(1, "query must be non-empty").describe("Natural-language or keyword query."),
|
|
8918
9031
|
mode: z.enum(["HYBRID", "TEXT", "SEMANTIC"]).optional().describe("HYBRID (BM25 + dense, default), TEXT (BM25 only), or SEMANTIC (dense only)."),
|
|
@@ -8927,7 +9040,9 @@ var inputSchema = {
|
|
|
8927
9040
|
rootFolderId: z.string().optional().describe("Scope to content under this folder AND all its descendants (subtree-root folder id)."),
|
|
8928
9041
|
// Content narrowing.
|
|
8929
9042
|
contentTypes: z.array(z.enum(["documents", "records"])).optional().describe('Narrow to content types. ["documents"] or ["records"]; omit for unified (both).'),
|
|
8930
|
-
typeName: z.string().optional().describe(
|
|
9043
|
+
typeName: z.string().optional().describe(
|
|
9044
|
+
'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.'
|
|
9045
|
+
),
|
|
8931
9046
|
filters: z.record(z.unknown()).optional().describe(
|
|
8932
9047
|
'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}}.'
|
|
8933
9048
|
),
|
|
@@ -8942,6 +9057,9 @@ var inputSchema = {
|
|
|
8942
9057
|
minSimilarity: z.number().min(0).max(1).optional().describe("Minimum semantic similarity (0.0\u20131.0); results below are excluded."),
|
|
8943
9058
|
minTextRelevance: z.number().min(0).max(1).optional().describe("Minimum relative keyword (BM25) relevance (0.0\u20131.0); the keyword-leg analogue of minSimilarity."),
|
|
8944
9059
|
uniqueDocuments: z.boolean().optional().describe("When true, return at most one chunk per source document."),
|
|
9060
|
+
includeContext: z.boolean().optional().describe(
|
|
9061
|
+
"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."
|
|
9062
|
+
),
|
|
8945
9063
|
requireComplete: z.boolean().optional().describe(
|
|
8946
9064
|
"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)."
|
|
8947
9065
|
)
|
|
@@ -8949,7 +9067,7 @@ var inputSchema = {
|
|
|
8949
9067
|
var hybridSearch = ({ client, log }) => ({
|
|
8950
9068
|
name: "hybrid_search",
|
|
8951
9069
|
title: "Hybrid search",
|
|
8952
|
-
description:
|
|
9070
|
+
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".`,
|
|
8953
9071
|
inputSchema,
|
|
8954
9072
|
handler: async (args) => {
|
|
8955
9073
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT;
|
|
@@ -8976,13 +9094,30 @@ var hybridSearch = ({ client, log }) => ({
|
|
|
8976
9094
|
uniqueDocuments: args.uniqueDocuments,
|
|
8977
9095
|
requireComplete: args.requireComplete
|
|
8978
9096
|
});
|
|
9097
|
+
const hits = Array.isArray(
|
|
9098
|
+
result.results
|
|
9099
|
+
) ? result.results : [];
|
|
9100
|
+
const includeContext = args.includeContext ?? false;
|
|
9101
|
+
let shaped = hits.map((h) => reshapeHit(h, includeContext));
|
|
9102
|
+
const textLegEmpty = mode !== "SEMANTIC" && hits.length > 0 && hits.every((h) => !(Number(h.textScore) > 0));
|
|
9103
|
+
const envelope = {
|
|
9104
|
+
...result,
|
|
9105
|
+
results: shaped
|
|
9106
|
+
};
|
|
9107
|
+
if (textLegEmpty) envelope.textLegEmpty = true;
|
|
9108
|
+
let text = JSON.stringify(envelope, null, 2);
|
|
9109
|
+
while (shaped.length > 1 && text.length > MCP_RESPONSE_CHAR_BUDGET) {
|
|
9110
|
+
shaped = shaped.slice(0, -1);
|
|
9111
|
+
envelope.results = shaped;
|
|
9112
|
+
envelope.truncated = true;
|
|
9113
|
+
envelope.returnedResults = shaped.length;
|
|
9114
|
+
text = JSON.stringify(envelope, null, 2);
|
|
9115
|
+
}
|
|
8979
9116
|
log.debug(
|
|
8980
|
-
{ tool: "hybrid_search", mode, limit, returned:
|
|
9117
|
+
{ tool: "hybrid_search", mode, limit, returned: shaped.length, textLegEmpty },
|
|
8981
9118
|
"hybrid_search ok"
|
|
8982
9119
|
);
|
|
8983
|
-
return {
|
|
8984
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
8985
|
-
};
|
|
9120
|
+
return { content: [{ type: "text", text }] };
|
|
8986
9121
|
} catch (err) {
|
|
8987
9122
|
log.warn({ tool: "hybrid_search", err: String(err) }, "hybrid_search failed");
|
|
8988
9123
|
return toolError("hybrid_search", err);
|
|
@@ -9017,7 +9152,9 @@ var MCP_MAX_LIMIT2 = 10;
|
|
|
9017
9152
|
var inputSchema2 = {
|
|
9018
9153
|
type: z2.string().min(1, "type (record type) is required").describe('Record type / schema name (e.g. "patient", "clinical_note").'),
|
|
9019
9154
|
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | from+to | prefix.
|
|
9020
|
-
field: z2.string().optional().describe(
|
|
9155
|
+
field: z2.string().optional().describe(
|
|
9156
|
+
'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.)'
|
|
9157
|
+
),
|
|
9021
9158
|
value: z2.string().optional().describe("Lookup mode (equality): exact-match value for `field`."),
|
|
9022
9159
|
from: z2.string().optional().describe("Lookup mode (range): inclusive lower bound; requires `to`. Non-sensitive fields only."),
|
|
9023
9160
|
to: z2.string().optional().describe("Lookup mode (range): inclusive upper bound; requires `from`."),
|
|
@@ -9112,19 +9249,77 @@ var record_query_default = recordQuery;
|
|
|
9112
9249
|
|
|
9113
9250
|
// src/tools/record_get.ts
|
|
9114
9251
|
import { z as z3 } from "zod";
|
|
9252
|
+
|
|
9253
|
+
// src/tools/resolve-external-id.ts
|
|
9254
|
+
function validateSelector(sel, entity) {
|
|
9255
|
+
const hasId = sel.id !== void 0 && sel.id !== "";
|
|
9256
|
+
const hasExt = sel.externalId !== void 0 && sel.externalId !== "";
|
|
9257
|
+
if (hasId && hasExt) {
|
|
9258
|
+
return `Provide either id or externalId (not both) to identify the ${entity}.`;
|
|
9259
|
+
}
|
|
9260
|
+
if (!hasId && !hasExt) {
|
|
9261
|
+
return `Provide id, or externalId + type, to identify the ${entity}.`;
|
|
9262
|
+
}
|
|
9263
|
+
if (hasExt && (sel.type === void 0 || sel.type === "")) {
|
|
9264
|
+
return "type is required when selecting by externalId (externalId is unique within a type).";
|
|
9265
|
+
}
|
|
9266
|
+
return void 0;
|
|
9267
|
+
}
|
|
9268
|
+
async function resolveRecordIdByExternalId(client, sel) {
|
|
9269
|
+
const err = validateSelector(sel, "record");
|
|
9270
|
+
if (err) return { error: err };
|
|
9271
|
+
if (sel.id) return { id: sel.id };
|
|
9272
|
+
const page = await client.records.lookupRecordsByBody({
|
|
9273
|
+
type: sel.type,
|
|
9274
|
+
field: "externalId",
|
|
9275
|
+
value: sel.externalId,
|
|
9276
|
+
limit: 1
|
|
9277
|
+
});
|
|
9278
|
+
const items = pageItems(page);
|
|
9279
|
+
if (items.length === 0) {
|
|
9280
|
+
return { error: `No record of type '${sel.type}' with externalId '${sel.externalId}'.` };
|
|
9281
|
+
}
|
|
9282
|
+
return { id: items[0].id };
|
|
9283
|
+
}
|
|
9284
|
+
async function resolveDocumentIdByExternalId(client, sel) {
|
|
9285
|
+
const err = validateSelector(sel, "document");
|
|
9286
|
+
if (err) return { error: err };
|
|
9287
|
+
if (sel.id) return { id: sel.id };
|
|
9288
|
+
const page = await client.documents.lookupDocumentsByBody({
|
|
9289
|
+
type: sel.type,
|
|
9290
|
+
field: "externalId",
|
|
9291
|
+
value: sel.externalId,
|
|
9292
|
+
limit: 1
|
|
9293
|
+
});
|
|
9294
|
+
const items = pageItems(page);
|
|
9295
|
+
if (items.length === 0) {
|
|
9296
|
+
return { error: `No document of type '${sel.type}' with externalId '${sel.externalId}'.` };
|
|
9297
|
+
}
|
|
9298
|
+
return { id: items[0].id };
|
|
9299
|
+
}
|
|
9300
|
+
|
|
9301
|
+
// src/tools/record_get.ts
|
|
9115
9302
|
var MAX_PAYLOAD_CHARS = 32e3;
|
|
9116
9303
|
var inputSchema3 = {
|
|
9117
|
-
id: z3.string().
|
|
9304
|
+
id: z3.string().optional().describe("The Vectros record id (e.g. from record_query or hybrid_search). Provide this OR externalId+type."),
|
|
9305
|
+
externalId: z3.string().optional().describe(
|
|
9306
|
+
"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."
|
|
9307
|
+
),
|
|
9308
|
+
type: z3.string().optional().describe("Record type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type).")
|
|
9118
9309
|
};
|
|
9119
9310
|
var recordGet = ({ client, log }) => ({
|
|
9120
9311
|
name: "record_get",
|
|
9121
|
-
title: "Get a record by id",
|
|
9122
|
-
description: "Fetch a single structured record
|
|
9312
|
+
title: "Get a record by id or externalId",
|
|
9313
|
+
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.",
|
|
9123
9314
|
inputSchema: inputSchema3,
|
|
9124
9315
|
handler: async (args) => {
|
|
9125
9316
|
const id = args.id;
|
|
9317
|
+
const externalId = args.externalId;
|
|
9318
|
+
const type = args.type;
|
|
9126
9319
|
try {
|
|
9127
|
-
const
|
|
9320
|
+
const resolved = await resolveRecordIdByExternalId(client, { id, externalId, type });
|
|
9321
|
+
if ("error" in resolved) return toolError("record_get", new Error(resolved.error));
|
|
9322
|
+
const record = await client.records.getRecord({ id: resolved.id });
|
|
9128
9323
|
const out = { ...record };
|
|
9129
9324
|
if (record.payload !== void 0) {
|
|
9130
9325
|
const json = JSON.stringify(record.payload);
|
|
@@ -9136,12 +9331,12 @@ var recordGet = ({ client, log }) => ({
|
|
|
9136
9331
|
}
|
|
9137
9332
|
}
|
|
9138
9333
|
log.debug(
|
|
9139
|
-
{ tool: "record_get", id, truncated: out.payloadTruncated === true },
|
|
9334
|
+
{ tool: "record_get", id: resolved.id, externalId, truncated: out.payloadTruncated === true },
|
|
9140
9335
|
"record_get ok"
|
|
9141
9336
|
);
|
|
9142
9337
|
return { content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
|
|
9143
9338
|
} catch (err) {
|
|
9144
|
-
log.warn({ tool: "record_get", id, err: String(err) }, "record_get failed");
|
|
9339
|
+
log.warn({ tool: "record_get", id, externalId, type, err: String(err) }, "record_get failed");
|
|
9145
9340
|
return toolError("record_get", err);
|
|
9146
9341
|
}
|
|
9147
9342
|
}
|
|
@@ -9176,15 +9371,17 @@ var recordCreate = ({ client, log }) => ({
|
|
|
9176
9371
|
const type = args.type;
|
|
9177
9372
|
try {
|
|
9178
9373
|
const created = await client.records.createRecord({
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9374
|
+
body: {
|
|
9375
|
+
typeName: type,
|
|
9376
|
+
payload: args.fields,
|
|
9377
|
+
externalId: args.externalId,
|
|
9378
|
+
indexMode: args.indexMode,
|
|
9379
|
+
status: args.status,
|
|
9380
|
+
folderId: args.folderId,
|
|
9381
|
+
userId: args.userId,
|
|
9382
|
+
orgId: args.orgId,
|
|
9383
|
+
clientId: args.clientId
|
|
9384
|
+
}
|
|
9188
9385
|
});
|
|
9189
9386
|
log.debug({ tool: "record_create", type, id: created.id }, "record_create ok");
|
|
9190
9387
|
return { content: [{ type: "text", text: JSON.stringify(created, null, 2) }] };
|
|
@@ -9199,7 +9396,11 @@ var record_create_default = recordCreate;
|
|
|
9199
9396
|
// src/tools/record_update.ts
|
|
9200
9397
|
import { z as z5 } from "zod";
|
|
9201
9398
|
var inputSchema5 = {
|
|
9202
|
-
id: z5.string().
|
|
9399
|
+
id: z5.string().optional().describe("The Vectros record id to update. Provide this OR externalId+type."),
|
|
9400
|
+
externalId: z5.string().optional().describe(
|
|
9401
|
+
"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."
|
|
9402
|
+
),
|
|
9403
|
+
type: z5.string().optional().describe("Record type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9203
9404
|
fields: z5.record(z5.string(), z5.unknown()).describe(
|
|
9204
9405
|
"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."
|
|
9205
9406
|
),
|
|
@@ -9210,23 +9411,27 @@ var inputSchema5 = {
|
|
|
9210
9411
|
};
|
|
9211
9412
|
var recordUpdate = ({ client, log }) => ({
|
|
9212
9413
|
name: "record_update",
|
|
9213
|
-
title: "Update a record",
|
|
9214
|
-
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.",
|
|
9414
|
+
title: "Update a record by id or externalId",
|
|
9415
|
+
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.",
|
|
9215
9416
|
inputSchema: inputSchema5,
|
|
9216
9417
|
handler: async (args) => {
|
|
9217
9418
|
const id = args.id;
|
|
9419
|
+
const externalId = args.externalId;
|
|
9420
|
+
const type = args.type;
|
|
9218
9421
|
const fields = args.fields;
|
|
9219
9422
|
const status = args.status;
|
|
9220
9423
|
const expectedVersion = args.expectedVersion;
|
|
9221
9424
|
try {
|
|
9425
|
+
const resolved = await resolveRecordIdByExternalId(client, { id, externalId, type });
|
|
9426
|
+
if ("error" in resolved) return toolError("record_update", new Error(resolved.error));
|
|
9222
9427
|
const body = { payload: fields };
|
|
9223
9428
|
if (status !== void 0) body.status = status;
|
|
9224
9429
|
if (expectedVersion !== void 0) body.expectedVersion = expectedVersion;
|
|
9225
|
-
const updated = await client.records.patchRecord({ id, body });
|
|
9226
|
-
log.debug({ tool: "record_update", id }, "record_update ok");
|
|
9430
|
+
const updated = await client.records.patchRecord({ id: resolved.id, body });
|
|
9431
|
+
log.debug({ tool: "record_update", id: resolved.id, externalId }, "record_update ok");
|
|
9227
9432
|
return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
|
|
9228
9433
|
} catch (err) {
|
|
9229
|
-
log.warn({ tool: "record_update", id, err: String(err) }, "record_update failed");
|
|
9434
|
+
log.warn({ tool: "record_update", id, externalId, type, err: String(err) }, "record_update failed");
|
|
9230
9435
|
return toolError("record_update", err);
|
|
9231
9436
|
}
|
|
9232
9437
|
}
|
|
@@ -9493,7 +9698,11 @@ var list_schemas_default = listSchemas;
|
|
|
9493
9698
|
import { z as z10 } from "zod";
|
|
9494
9699
|
var MAX_TEXT_CHARS = 32e3;
|
|
9495
9700
|
var inputSchema10 = {
|
|
9496
|
-
documentId: z10.string().
|
|
9701
|
+
documentId: z10.string().optional().describe("The document ID returned by document_ingest or hybrid_search. Provide this OR externalId+type."),
|
|
9702
|
+
externalId: z10.string().optional().describe(
|
|
9703
|
+
"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."
|
|
9704
|
+
),
|
|
9705
|
+
type: z10.string().optional().describe("Document type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9497
9706
|
includeText: z10.boolean().optional().describe(
|
|
9498
9707
|
"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."
|
|
9499
9708
|
),
|
|
@@ -9513,13 +9722,18 @@ function isNotAvailable(err) {
|
|
|
9513
9722
|
var documentGet = ({ client, log }) => ({
|
|
9514
9723
|
name: "document_get",
|
|
9515
9724
|
title: "Get document metadata (and optionally text)",
|
|
9516
|
-
description: "Fetch metadata for a single document by
|
|
9725
|
+
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`.",
|
|
9517
9726
|
inputSchema: inputSchema10,
|
|
9518
9727
|
handler: async (args) => {
|
|
9519
|
-
const
|
|
9728
|
+
const documentId = args.documentId;
|
|
9729
|
+
const externalId = args.externalId;
|
|
9730
|
+
const type = args.type;
|
|
9520
9731
|
const includeText = args.includeText ?? false;
|
|
9521
9732
|
const includeDownloadUrl = args.includeDownloadUrl ?? false;
|
|
9522
9733
|
try {
|
|
9734
|
+
const resolved = await resolveDocumentIdByExternalId(client, { id: documentId, externalId, type });
|
|
9735
|
+
if ("error" in resolved) return toolError("document_get", new Error(resolved.error));
|
|
9736
|
+
const id = resolved.id;
|
|
9523
9737
|
const doc = await client.documents.getDocument({ id });
|
|
9524
9738
|
let extra = {};
|
|
9525
9739
|
if (includeText) {
|
|
@@ -9566,7 +9780,7 @@ var documentGet = ({ client, log }) => ({
|
|
|
9566
9780
|
]
|
|
9567
9781
|
};
|
|
9568
9782
|
} catch (err) {
|
|
9569
|
-
log.warn({ tool: "document_get",
|
|
9783
|
+
log.warn({ tool: "document_get", documentId, externalId, type, err: String(err) }, "document_get failed");
|
|
9570
9784
|
return toolError("document_get", err);
|
|
9571
9785
|
}
|
|
9572
9786
|
}
|
|
@@ -9681,13 +9895,23 @@ var document_query_default = documentQuery;
|
|
|
9681
9895
|
// src/tools/document_update.ts
|
|
9682
9896
|
import { z as z12 } from "zod";
|
|
9683
9897
|
var inputSchema12 = {
|
|
9684
|
-
documentId: z12.string().
|
|
9898
|
+
documentId: z12.string().optional().describe("The Vectros document id to update. Provide this OR externalId+type."),
|
|
9899
|
+
externalId: z12.string().optional().describe(
|
|
9900
|
+
"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."
|
|
9901
|
+
),
|
|
9902
|
+
type: z12.string().optional().describe("Document type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9685
9903
|
title: z12.string().optional().describe("New title. Omit to keep the current title."),
|
|
9686
9904
|
fields: z12.record(z12.string(), z12.unknown()).optional().describe(
|
|
9687
9905
|
"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."
|
|
9688
9906
|
),
|
|
9907
|
+
text: z12.string().optional().describe(
|
|
9908
|
+
"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."
|
|
9909
|
+
),
|
|
9689
9910
|
folderId: z12.string().optional().describe("Move the document into this folder (cannot be cleared once set)."),
|
|
9690
9911
|
storeText: z12.boolean().optional().describe("Whether the raw text is stored + retrievable."),
|
|
9912
|
+
status: z12.enum(["ACTIVE", "ARCHIVED"]).optional().describe(
|
|
9913
|
+
"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."
|
|
9914
|
+
),
|
|
9691
9915
|
userId: z12.string().optional().describe("Reassign the owning user (Vectros UUID)."),
|
|
9692
9916
|
orgId: z12.string().optional().describe("Reassign the owning org (Vectros UUID)."),
|
|
9693
9917
|
clientId: z12.string().optional().describe("Reassign the associated client (Vectros UUID)."),
|
|
@@ -9698,33 +9922,41 @@ var inputSchema12 = {
|
|
|
9698
9922
|
var documentUpdate = ({ client, log }) => ({
|
|
9699
9923
|
name: "document_update",
|
|
9700
9924
|
title: "Update a document",
|
|
9701
|
-
description:
|
|
9925
|
+
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.',
|
|
9702
9926
|
inputSchema: inputSchema12,
|
|
9703
9927
|
handler: async (args) => {
|
|
9704
9928
|
const documentId = args.documentId;
|
|
9929
|
+
const externalId = args.externalId;
|
|
9930
|
+
const type = args.type;
|
|
9705
9931
|
const title = args.title;
|
|
9706
9932
|
const fields = args.fields;
|
|
9933
|
+
const text = args.text;
|
|
9707
9934
|
const folderId = args.folderId;
|
|
9708
9935
|
const storeText = args.storeText;
|
|
9936
|
+
const status = args.status;
|
|
9709
9937
|
const userId = args.userId;
|
|
9710
9938
|
const orgId = args.orgId;
|
|
9711
9939
|
const clientId = args.clientId;
|
|
9712
9940
|
const expectedVersion = args.expectedVersion;
|
|
9713
9941
|
try {
|
|
9942
|
+
const resolved = await resolveDocumentIdByExternalId(client, { id: documentId, externalId, type });
|
|
9943
|
+
if ("error" in resolved) return toolError("document_update", new Error(resolved.error));
|
|
9714
9944
|
const body = {};
|
|
9715
9945
|
if (title !== void 0) body.title = title;
|
|
9716
9946
|
if (fields !== void 0) body.payload = fields;
|
|
9947
|
+
if (text !== void 0) body.text = text;
|
|
9717
9948
|
if (folderId !== void 0) body.folderId = folderId;
|
|
9718
9949
|
if (storeText !== void 0) body.storeText = storeText;
|
|
9950
|
+
if (status !== void 0) body.status = status;
|
|
9719
9951
|
if (userId !== void 0) body.userId = userId;
|
|
9720
9952
|
if (orgId !== void 0) body.orgId = orgId;
|
|
9721
9953
|
if (clientId !== void 0) body.clientId = clientId;
|
|
9722
9954
|
if (expectedVersion !== void 0) body.expectedVersion = expectedVersion;
|
|
9723
9955
|
const updated = await client.documents.patchDocument({
|
|
9724
|
-
id:
|
|
9956
|
+
id: resolved.id,
|
|
9725
9957
|
body
|
|
9726
9958
|
});
|
|
9727
|
-
log.debug({ tool: "document_update", documentId }, "document_update ok");
|
|
9959
|
+
log.debug({ tool: "document_update", documentId: resolved.id, externalId }, "document_update ok");
|
|
9728
9960
|
return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
|
|
9729
9961
|
} catch (err) {
|
|
9730
9962
|
log.warn({ tool: "document_update", documentId, err: String(err) }, "document_update failed");
|
|
@@ -9742,7 +9974,7 @@ var inputSchema13 = {
|
|
|
9742
9974
|
var documentDelete = ({ client, log }) => ({
|
|
9743
9975
|
name: "document_delete",
|
|
9744
9976
|
title: "Delete a document",
|
|
9745
|
-
description:
|
|
9977
|
+
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).',
|
|
9746
9978
|
inputSchema: inputSchema13,
|
|
9747
9979
|
handler: async (args) => {
|
|
9748
9980
|
const documentId = args.documentId;
|
|
@@ -9826,13 +10058,15 @@ var folderCreate = ({ client, log }) => ({
|
|
|
9826
10058
|
handler: async (args) => {
|
|
9827
10059
|
try {
|
|
9828
10060
|
const folder = await client.folders.createFolder({
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
10061
|
+
body: {
|
|
10062
|
+
name: args.name,
|
|
10063
|
+
description: args.description,
|
|
10064
|
+
parentFolderId: args.parentId,
|
|
10065
|
+
slug: args.slug,
|
|
10066
|
+
userId: args.userId,
|
|
10067
|
+
orgId: args.orgId,
|
|
10068
|
+
clientId: args.clientId
|
|
10069
|
+
}
|
|
9836
10070
|
});
|
|
9837
10071
|
log.debug({ tool: "folder_create", id: folder.id, name: folder.name }, "folder_create ok");
|
|
9838
10072
|
return { content: [{ type: "text", text: JSON.stringify(folder, null, 2) }] };
|
|
@@ -10020,6 +10254,9 @@ var inputSchema19 = {
|
|
|
10020
10254
|
externalId: z18.string().optional().describe(
|
|
10021
10255
|
"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."
|
|
10022
10256
|
),
|
|
10257
|
+
upsert: z18.boolean().optional().describe(
|
|
10258
|
+
"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)."
|
|
10259
|
+
),
|
|
10023
10260
|
schemaId: z18.string().optional().describe(
|
|
10024
10261
|
"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."
|
|
10025
10262
|
),
|
|
@@ -10045,13 +10282,14 @@ var inputSchema19 = {
|
|
|
10045
10282
|
var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
10046
10283
|
name: "document_ingest",
|
|
10047
10284
|
title: "Ingest a new document (text body or file upload)",
|
|
10048
|
-
description: "Create a new document in
|
|
10285
|
+
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).",
|
|
10049
10286
|
inputSchema: inputSchema19,
|
|
10050
10287
|
handler: async (args) => {
|
|
10051
10288
|
const title = args.title;
|
|
10052
10289
|
const text = args.text;
|
|
10053
10290
|
const filePath = args.filePath;
|
|
10054
10291
|
const schemaId = args.schemaId;
|
|
10292
|
+
const upsert = args.upsert;
|
|
10055
10293
|
const indexMode = args.indexMode ?? (schemaId ? void 0 : "HYBRID");
|
|
10056
10294
|
if (!text && !filePath) {
|
|
10057
10295
|
return toolError(
|
|
@@ -10086,11 +10324,14 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10086
10324
|
if (text) {
|
|
10087
10325
|
const storeText = args.storeText ?? true;
|
|
10088
10326
|
const result = await client.documents.ingestDocument({
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10327
|
+
upsert,
|
|
10328
|
+
body: {
|
|
10329
|
+
title,
|
|
10330
|
+
text,
|
|
10331
|
+
indexMode,
|
|
10332
|
+
storeText,
|
|
10333
|
+
...common
|
|
10334
|
+
}
|
|
10094
10335
|
});
|
|
10095
10336
|
log.debug(
|
|
10096
10337
|
{ tool: "document_ingest", mode: "text", id: result?.id, indexMode },
|
|
@@ -10120,6 +10361,7 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10120
10361
|
const fileName = basename(safePath);
|
|
10121
10362
|
const fileType = args.fileType ?? inferMimeType(safePath);
|
|
10122
10363
|
const upload = await client.documents.uploadDocument({
|
|
10364
|
+
upsert,
|
|
10123
10365
|
fileName,
|
|
10124
10366
|
fileType,
|
|
10125
10367
|
indexMode,
|
|
@@ -10158,8 +10400,8 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10158
10400
|
text: JSON.stringify(
|
|
10159
10401
|
{
|
|
10160
10402
|
...upload,
|
|
10161
|
-
|
|
10162
|
-
_note: "File uploaded; indexing is asynchronous. Poll document_get(id) until
|
|
10403
|
+
indexStatus: "PENDING_INDEX",
|
|
10404
|
+
_note: "File uploaded; indexing is asynchronous. Poll document_get(id) until indexStatus is INDEXED."
|
|
10163
10405
|
},
|
|
10164
10406
|
null,
|
|
10165
10407
|
2
|
|
@@ -10456,6 +10698,14 @@ function zodTypeToJsonSchema(schema) {
|
|
|
10456
10698
|
|
|
10457
10699
|
// src/server.ts
|
|
10458
10700
|
var DEFAULT_ENVIRONMENT = "https://api.vectros.ai";
|
|
10701
|
+
function formatArgError(tool, error) {
|
|
10702
|
+
const unknownKeys = error.issues.filter((i) => i.code === "unrecognized_keys").flatMap((i) => i.keys);
|
|
10703
|
+
if (unknownKeys.length > 0) {
|
|
10704
|
+
const valid = Object.keys(tool.inputSchema).join(", ");
|
|
10705
|
+
return `Unknown argument(s): ${unknownKeys.join(", ")}. Valid arguments for ${tool.name}: ${valid}. Pass only these \u2014 an unrecognized argument is rejected, not ignored.`;
|
|
10706
|
+
}
|
|
10707
|
+
return `Invalid arguments: ${error.message}`;
|
|
10708
|
+
}
|
|
10459
10709
|
var VectrosMCPServer = class {
|
|
10460
10710
|
server;
|
|
10461
10711
|
log;
|
|
@@ -10545,7 +10795,11 @@ var VectrosMCPServer = class {
|
|
|
10545
10795
|
name: t.name,
|
|
10546
10796
|
title: t.title,
|
|
10547
10797
|
description: t.description,
|
|
10548
|
-
|
|
10798
|
+
// additionalProperties:false advertises strict argument validation to the
|
|
10799
|
+
// MCP client (a well-behaved client rejects an unknown key before the call).
|
|
10800
|
+
// The server enforces it too (z.object(...).strict() below) so a raw JSON-RPC
|
|
10801
|
+
// call that skips client validation is still rejected — belt and suspenders.
|
|
10802
|
+
inputSchema: { ...zodShapeToJsonSchema(t.inputSchema), additionalProperties: false }
|
|
10549
10803
|
}))
|
|
10550
10804
|
})
|
|
10551
10805
|
);
|
|
@@ -10555,9 +10809,9 @@ var VectrosMCPServer = class {
|
|
|
10555
10809
|
if (!tool) {
|
|
10556
10810
|
result = toolError(req.params.name ?? "unknown", new Error("No such tool."));
|
|
10557
10811
|
} else {
|
|
10558
|
-
const parsed = z22.object(tool.inputSchema).safeParse(req.params.arguments ?? {});
|
|
10812
|
+
const parsed = z22.object(tool.inputSchema).strict().safeParse(req.params.arguments ?? {});
|
|
10559
10813
|
if (!parsed.success) {
|
|
10560
|
-
result = toolError(tool.name, new Error(
|
|
10814
|
+
result = toolError(tool.name, new Error(formatArgError(tool, parsed.error)));
|
|
10561
10815
|
} else {
|
|
10562
10816
|
try {
|
|
10563
10817
|
result = await tool.handler(
|