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