@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.js
CHANGED
|
@@ -504,10 +504,18 @@ var DocumentRequest;
|
|
|
504
504
|
Text: "TEXT",
|
|
505
505
|
None: "NONE"
|
|
506
506
|
};
|
|
507
|
+
DocumentRequest2.Status = {
|
|
508
|
+
Active: "ACTIVE",
|
|
509
|
+
Archived: "ARCHIVED"
|
|
510
|
+
};
|
|
507
511
|
})(DocumentRequest || (DocumentRequest = {}));
|
|
508
512
|
var DocumentResponse;
|
|
509
513
|
((DocumentResponse2) => {
|
|
510
514
|
DocumentResponse2.Status = {
|
|
515
|
+
Active: "ACTIVE",
|
|
516
|
+
Archived: "ARCHIVED"
|
|
517
|
+
};
|
|
518
|
+
DocumentResponse2.IndexStatus = {
|
|
511
519
|
PendingUpload: "PENDING_UPLOAD",
|
|
512
520
|
Uploaded: "UPLOADED",
|
|
513
521
|
Extracting: "EXTRACTING",
|
|
@@ -2861,7 +2869,7 @@ var AuthClient = class {
|
|
|
2861
2869
|
);
|
|
2862
2870
|
}
|
|
2863
2871
|
/**
|
|
2864
|
-
* 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.
|
|
2872
|
+
* 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.
|
|
2865
2873
|
*
|
|
2866
2874
|
* @param {Vectros.CreateAccessProfileRequest} request
|
|
2867
2875
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -2883,7 +2891,10 @@ var AuthClient = class {
|
|
|
2883
2891
|
return HttpResponsePromise.fromPromise(this.__createAccessProfile(request, requestOptions));
|
|
2884
2892
|
}
|
|
2885
2893
|
async __createAccessProfile(request, requestOptions) {
|
|
2886
|
-
const { contextId, body: _body } = request;
|
|
2894
|
+
const { contextId, upsert, body: _body } = request;
|
|
2895
|
+
const _queryParams = {
|
|
2896
|
+
upsert
|
|
2897
|
+
};
|
|
2887
2898
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
2888
2899
|
const _headers = mergeHeaders(
|
|
2889
2900
|
_authRequest.headers,
|
|
@@ -2898,7 +2909,7 @@ var AuthClient = class {
|
|
|
2898
2909
|
method: "POST",
|
|
2899
2910
|
headers: _headers,
|
|
2900
2911
|
contentType: "application/json",
|
|
2901
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
2912
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
2902
2913
|
requestType: "json",
|
|
2903
2914
|
body: _body,
|
|
2904
2915
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -2993,9 +3004,9 @@ var AuthClient = class {
|
|
|
2993
3004
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/app-contexts");
|
|
2994
3005
|
}
|
|
2995
3006
|
/**
|
|
2996
|
-
* 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.
|
|
3007
|
+
* 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.
|
|
2997
3008
|
*
|
|
2998
|
-
* @param {Vectros.
|
|
3009
|
+
* @param {Vectros.CreateAppContextRequest} request
|
|
2999
3010
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
3000
3011
|
*
|
|
3001
3012
|
* @throws {@link Vectros.BadRequestError}
|
|
@@ -3004,14 +3015,20 @@ var AuthClient = class {
|
|
|
3004
3015
|
*
|
|
3005
3016
|
* @example
|
|
3006
3017
|
* await client.auth.createAppContext({
|
|
3007
|
-
*
|
|
3008
|
-
*
|
|
3018
|
+
* body: {
|
|
3019
|
+
* contextId: "myapp",
|
|
3020
|
+
* name: "My Internal App"
|
|
3021
|
+
* }
|
|
3009
3022
|
* })
|
|
3010
3023
|
*/
|
|
3011
3024
|
createAppContext(request, requestOptions) {
|
|
3012
3025
|
return HttpResponsePromise.fromPromise(this.__createAppContext(request, requestOptions));
|
|
3013
3026
|
}
|
|
3014
3027
|
async __createAppContext(request, requestOptions) {
|
|
3028
|
+
const { upsert, body: _body } = request;
|
|
3029
|
+
const _queryParams = {
|
|
3030
|
+
upsert
|
|
3031
|
+
};
|
|
3015
3032
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
3016
3033
|
const _headers = mergeHeaders(
|
|
3017
3034
|
_authRequest.headers,
|
|
@@ -3026,9 +3043,9 @@ var AuthClient = class {
|
|
|
3026
3043
|
method: "POST",
|
|
3027
3044
|
headers: _headers,
|
|
3028
3045
|
contentType: "application/json",
|
|
3029
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
3046
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
3030
3047
|
requestType: "json",
|
|
3031
|
-
body:
|
|
3048
|
+
body: _body,
|
|
3032
3049
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
3033
3050
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
3034
3051
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -3124,7 +3141,7 @@ var AuthClient = class {
|
|
|
3124
3141
|
);
|
|
3125
3142
|
}
|
|
3126
3143
|
/**
|
|
3127
|
-
* 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.
|
|
3144
|
+
* 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.
|
|
3128
3145
|
*
|
|
3129
3146
|
* @param {Vectros.CreateRoleRequest} request
|
|
3130
3147
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -3150,7 +3167,10 @@ var AuthClient = class {
|
|
|
3150
3167
|
return HttpResponsePromise.fromPromise(this.__createRole(request, requestOptions));
|
|
3151
3168
|
}
|
|
3152
3169
|
async __createRole(request, requestOptions) {
|
|
3153
|
-
const { contextId, body: _body } = request;
|
|
3170
|
+
const { contextId, upsert, body: _body } = request;
|
|
3171
|
+
const _queryParams = {
|
|
3172
|
+
upsert
|
|
3173
|
+
};
|
|
3154
3174
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
3155
3175
|
const _headers = mergeHeaders(
|
|
3156
3176
|
_authRequest.headers,
|
|
@@ -3165,7 +3185,7 @@ var AuthClient = class {
|
|
|
3165
3185
|
method: "POST",
|
|
3166
3186
|
headers: _headers,
|
|
3167
3187
|
contentType: "application/json",
|
|
3168
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
3188
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
3169
3189
|
requestType: "json",
|
|
3170
3190
|
body: _body,
|
|
3171
3191
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -4649,23 +4669,30 @@ var DocumentsClient = class {
|
|
|
4649
4669
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents");
|
|
4650
4670
|
}
|
|
4651
4671
|
/**
|
|
4652
|
-
* Creates a document from a raw text string and queues it for asynchronous indexing so it becomes searchable. Requires the `documents:c` scope.
|
|
4672
|
+
* 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.
|
|
4653
4673
|
*
|
|
4654
|
-
* @param {Vectros.
|
|
4674
|
+
* @param {Vectros.IngestDocumentRequest} request
|
|
4655
4675
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4656
4676
|
*
|
|
4657
4677
|
* @throws {@link Vectros.BadRequestError}
|
|
4678
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4658
4679
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
4659
4680
|
*
|
|
4660
4681
|
* @example
|
|
4661
4682
|
* await client.documents.ingestDocument({
|
|
4662
|
-
*
|
|
4683
|
+
* body: {
|
|
4684
|
+
* title: "Patient Intake Form \u2014 Jane Doe"
|
|
4685
|
+
* }
|
|
4663
4686
|
* })
|
|
4664
4687
|
*/
|
|
4665
4688
|
ingestDocument(request, requestOptions) {
|
|
4666
4689
|
return HttpResponsePromise.fromPromise(this.__ingestDocument(request, requestOptions));
|
|
4667
4690
|
}
|
|
4668
4691
|
async __ingestDocument(request, requestOptions) {
|
|
4692
|
+
const { upsert, body: _body } = request;
|
|
4693
|
+
const _queryParams = {
|
|
4694
|
+
upsert
|
|
4695
|
+
};
|
|
4669
4696
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4670
4697
|
const _headers = mergeHeaders(
|
|
4671
4698
|
_authRequest.headers,
|
|
@@ -4680,9 +4707,9 @@ var DocumentsClient = class {
|
|
|
4680
4707
|
method: "POST",
|
|
4681
4708
|
headers: _headers,
|
|
4682
4709
|
contentType: "application/json",
|
|
4683
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4710
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
4684
4711
|
requestType: "json",
|
|
4685
|
-
body:
|
|
4712
|
+
body: _body,
|
|
4686
4713
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4687
4714
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4688
4715
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -4696,6 +4723,8 @@ var DocumentsClient = class {
|
|
|
4696
4723
|
switch (_response.error.statusCode) {
|
|
4697
4724
|
case 400:
|
|
4698
4725
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
4726
|
+
case 403:
|
|
4727
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4699
4728
|
case 429:
|
|
4700
4729
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4701
4730
|
default:
|
|
@@ -4962,7 +4991,7 @@ var DocumentsClient = class {
|
|
|
4962
4991
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "PATCH", "/v1/documents/{id}");
|
|
4963
4992
|
}
|
|
4964
4993
|
/**
|
|
4965
|
-
* Finds documents of a given type by
|
|
4994
|
+
* 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.
|
|
4966
4995
|
*
|
|
4967
4996
|
* @param {Vectros.LookupDocumentsRequest} request
|
|
4968
4997
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -5257,12 +5286,13 @@ var DocumentsClient = class {
|
|
|
5257
5286
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/{id}/versions");
|
|
5258
5287
|
}
|
|
5259
5288
|
/**
|
|
5260
|
-
* 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.
|
|
5289
|
+
* 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).
|
|
5261
5290
|
*
|
|
5262
5291
|
* @param {Vectros.FileUploadRequest} request
|
|
5263
5292
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5264
5293
|
*
|
|
5265
5294
|
* @throws {@link Vectros.BadRequestError}
|
|
5295
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5266
5296
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5267
5297
|
*
|
|
5268
5298
|
* @example
|
|
@@ -5275,6 +5305,10 @@ var DocumentsClient = class {
|
|
|
5275
5305
|
return HttpResponsePromise.fromPromise(this.__uploadDocument(request, requestOptions));
|
|
5276
5306
|
}
|
|
5277
5307
|
async __uploadDocument(request, requestOptions) {
|
|
5308
|
+
const { upsert, ..._body } = request;
|
|
5309
|
+
const _queryParams = {
|
|
5310
|
+
upsert
|
|
5311
|
+
};
|
|
5278
5312
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5279
5313
|
const _headers = mergeHeaders(
|
|
5280
5314
|
_authRequest.headers,
|
|
@@ -5289,9 +5323,9 @@ var DocumentsClient = class {
|
|
|
5289
5323
|
method: "POST",
|
|
5290
5324
|
headers: _headers,
|
|
5291
5325
|
contentType: "application/json",
|
|
5292
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5326
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5293
5327
|
requestType: "json",
|
|
5294
|
-
body:
|
|
5328
|
+
body: _body,
|
|
5295
5329
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5296
5330
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5297
5331
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5305,6 +5339,8 @@ var DocumentsClient = class {
|
|
|
5305
5339
|
switch (_response.error.statusCode) {
|
|
5306
5340
|
case 400:
|
|
5307
5341
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5342
|
+
case 403:
|
|
5343
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5308
5344
|
case 429:
|
|
5309
5345
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5310
5346
|
default:
|
|
@@ -5383,23 +5419,30 @@ var FoldersClient = class {
|
|
|
5383
5419
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/folders");
|
|
5384
5420
|
}
|
|
5385
5421
|
/**
|
|
5386
|
-
* 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.
|
|
5422
|
+
* 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.
|
|
5387
5423
|
*
|
|
5388
|
-
* @param {Vectros.
|
|
5424
|
+
* @param {Vectros.CreateFolderRequest} request
|
|
5389
5425
|
* @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5390
5426
|
*
|
|
5391
5427
|
* @throws {@link Vectros.BadRequestError}
|
|
5428
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5392
5429
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5393
5430
|
*
|
|
5394
5431
|
* @example
|
|
5395
5432
|
* await client.folders.createFolder({
|
|
5396
|
-
*
|
|
5433
|
+
* body: {
|
|
5434
|
+
* name: "Patient Records 2024"
|
|
5435
|
+
* }
|
|
5397
5436
|
* })
|
|
5398
5437
|
*/
|
|
5399
5438
|
createFolder(request, requestOptions) {
|
|
5400
5439
|
return HttpResponsePromise.fromPromise(this.__createFolder(request, requestOptions));
|
|
5401
5440
|
}
|
|
5402
5441
|
async __createFolder(request, requestOptions) {
|
|
5442
|
+
const { upsert, body: _body } = request;
|
|
5443
|
+
const _queryParams = {
|
|
5444
|
+
upsert
|
|
5445
|
+
};
|
|
5403
5446
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5404
5447
|
const _headers = mergeHeaders(
|
|
5405
5448
|
_authRequest.headers,
|
|
@@ -5414,9 +5457,9 @@ var FoldersClient = class {
|
|
|
5414
5457
|
method: "POST",
|
|
5415
5458
|
headers: _headers,
|
|
5416
5459
|
contentType: "application/json",
|
|
5417
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5460
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5418
5461
|
requestType: "json",
|
|
5419
|
-
body:
|
|
5462
|
+
body: _body,
|
|
5420
5463
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5421
5464
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5422
5465
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5430,6 +5473,8 @@ var FoldersClient = class {
|
|
|
5430
5473
|
switch (_response.error.statusCode) {
|
|
5431
5474
|
case 400:
|
|
5432
5475
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5476
|
+
case 403:
|
|
5477
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5433
5478
|
case 429:
|
|
5434
5479
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5435
5480
|
default:
|
|
@@ -5838,23 +5883,30 @@ var IdentityClient = class {
|
|
|
5838
5883
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/clients");
|
|
5839
5884
|
}
|
|
5840
5885
|
/**
|
|
5841
|
-
* 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.
|
|
5886
|
+
* 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.
|
|
5842
5887
|
*
|
|
5843
|
-
* @param {Vectros.
|
|
5888
|
+
* @param {Vectros.CreateClientRequest} request
|
|
5844
5889
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5845
5890
|
*
|
|
5846
5891
|
* @throws {@link Vectros.BadRequestError}
|
|
5892
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5847
5893
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5848
5894
|
*
|
|
5849
5895
|
* @example
|
|
5850
5896
|
* await client.identity.createClient({
|
|
5851
|
-
*
|
|
5897
|
+
* body: {
|
|
5898
|
+
* externalId: "patient_789"
|
|
5899
|
+
* }
|
|
5852
5900
|
* })
|
|
5853
5901
|
*/
|
|
5854
5902
|
createClient(request, requestOptions) {
|
|
5855
5903
|
return HttpResponsePromise.fromPromise(this.__createClient(request, requestOptions));
|
|
5856
5904
|
}
|
|
5857
5905
|
async __createClient(request, requestOptions) {
|
|
5906
|
+
const { upsert, body: _body } = request;
|
|
5907
|
+
const _queryParams = {
|
|
5908
|
+
upsert
|
|
5909
|
+
};
|
|
5858
5910
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
5859
5911
|
const _headers = mergeHeaders(
|
|
5860
5912
|
_authRequest.headers,
|
|
@@ -5869,9 +5921,9 @@ var IdentityClient = class {
|
|
|
5869
5921
|
method: "POST",
|
|
5870
5922
|
headers: _headers,
|
|
5871
5923
|
contentType: "application/json",
|
|
5872
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
5924
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
5873
5925
|
requestType: "json",
|
|
5874
|
-
body:
|
|
5926
|
+
body: _body,
|
|
5875
5927
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
5876
5928
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
5877
5929
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -5885,6 +5937,8 @@ var IdentityClient = class {
|
|
|
5885
5937
|
switch (_response.error.statusCode) {
|
|
5886
5938
|
case 400:
|
|
5887
5939
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5940
|
+
case 403:
|
|
5941
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5888
5942
|
case 429:
|
|
5889
5943
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
5890
5944
|
default:
|
|
@@ -6273,23 +6327,30 @@ var IdentityClient = class {
|
|
|
6273
6327
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/orgs");
|
|
6274
6328
|
}
|
|
6275
6329
|
/**
|
|
6276
|
-
* 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.
|
|
6330
|
+
* 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.
|
|
6277
6331
|
*
|
|
6278
|
-
* @param {Vectros.
|
|
6332
|
+
* @param {Vectros.CreateOrgRequest} request
|
|
6279
6333
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6280
6334
|
*
|
|
6281
6335
|
* @throws {@link Vectros.BadRequestError}
|
|
6336
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
6282
6337
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6283
6338
|
*
|
|
6284
6339
|
* @example
|
|
6285
6340
|
* await client.identity.createOrg({
|
|
6286
|
-
*
|
|
6341
|
+
* body: {
|
|
6342
|
+
* externalId: "clinic_001"
|
|
6343
|
+
* }
|
|
6287
6344
|
* })
|
|
6288
6345
|
*/
|
|
6289
6346
|
createOrg(request, requestOptions) {
|
|
6290
6347
|
return HttpResponsePromise.fromPromise(this.__createOrg(request, requestOptions));
|
|
6291
6348
|
}
|
|
6292
6349
|
async __createOrg(request, requestOptions) {
|
|
6350
|
+
const { upsert, body: _body } = request;
|
|
6351
|
+
const _queryParams = {
|
|
6352
|
+
upsert
|
|
6353
|
+
};
|
|
6293
6354
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
6294
6355
|
const _headers = mergeHeaders(
|
|
6295
6356
|
_authRequest.headers,
|
|
@@ -6304,9 +6365,9 @@ var IdentityClient = class {
|
|
|
6304
6365
|
method: "POST",
|
|
6305
6366
|
headers: _headers,
|
|
6306
6367
|
contentType: "application/json",
|
|
6307
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
6368
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
6308
6369
|
requestType: "json",
|
|
6309
|
-
body:
|
|
6370
|
+
body: _body,
|
|
6310
6371
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
6311
6372
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
6312
6373
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -6320,6 +6381,8 @@ var IdentityClient = class {
|
|
|
6320
6381
|
switch (_response.error.statusCode) {
|
|
6321
6382
|
case 400:
|
|
6322
6383
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6384
|
+
case 403:
|
|
6385
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
6323
6386
|
case 429:
|
|
6324
6387
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
6325
6388
|
default:
|
|
@@ -6694,23 +6757,30 @@ var IdentityClient = class {
|
|
|
6694
6757
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users");
|
|
6695
6758
|
}
|
|
6696
6759
|
/**
|
|
6697
|
-
* 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.
|
|
6760
|
+
* 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.
|
|
6698
6761
|
*
|
|
6699
|
-
* @param {Vectros.
|
|
6762
|
+
* @param {Vectros.CreateUserRequest} request
|
|
6700
6763
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6701
6764
|
*
|
|
6702
6765
|
* @throws {@link Vectros.BadRequestError}
|
|
6766
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
6703
6767
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6704
6768
|
*
|
|
6705
6769
|
* @example
|
|
6706
6770
|
* await client.identity.createUser({
|
|
6707
|
-
*
|
|
6771
|
+
* body: {
|
|
6772
|
+
* externalId: "usr_12345"
|
|
6773
|
+
* }
|
|
6708
6774
|
* })
|
|
6709
6775
|
*/
|
|
6710
6776
|
createUser(request, requestOptions) {
|
|
6711
6777
|
return HttpResponsePromise.fromPromise(this.__createUser(request, requestOptions));
|
|
6712
6778
|
}
|
|
6713
6779
|
async __createUser(request, requestOptions) {
|
|
6780
|
+
const { upsert, body: _body } = request;
|
|
6781
|
+
const _queryParams = {
|
|
6782
|
+
upsert
|
|
6783
|
+
};
|
|
6714
6784
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
6715
6785
|
const _headers = mergeHeaders(
|
|
6716
6786
|
_authRequest.headers,
|
|
@@ -6725,9 +6795,9 @@ var IdentityClient = class {
|
|
|
6725
6795
|
method: "POST",
|
|
6726
6796
|
headers: _headers,
|
|
6727
6797
|
contentType: "application/json",
|
|
6728
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
6798
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
6729
6799
|
requestType: "json",
|
|
6730
|
-
body:
|
|
6800
|
+
body: _body,
|
|
6731
6801
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
6732
6802
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
6733
6803
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -6741,6 +6811,8 @@ var IdentityClient = class {
|
|
|
6741
6811
|
switch (_response.error.statusCode) {
|
|
6742
6812
|
case 400:
|
|
6743
6813
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6814
|
+
case 403:
|
|
6815
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
6744
6816
|
case 429:
|
|
6745
6817
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
6746
6818
|
default:
|
|
@@ -7558,9 +7630,9 @@ var RecordsClient = class {
|
|
|
7558
7630
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/records");
|
|
7559
7631
|
}
|
|
7560
7632
|
/**
|
|
7561
|
-
* 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.
|
|
7633
|
+
* 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.
|
|
7562
7634
|
*
|
|
7563
|
-
* @param {Vectros.
|
|
7635
|
+
* @param {Vectros.CreateRecordRequest} request
|
|
7564
7636
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7565
7637
|
*
|
|
7566
7638
|
* @throws {@link Vectros.BadRequestError}
|
|
@@ -7569,19 +7641,25 @@ var RecordsClient = class {
|
|
|
7569
7641
|
*
|
|
7570
7642
|
* @example
|
|
7571
7643
|
* await client.records.createRecord({
|
|
7572
|
-
*
|
|
7573
|
-
*
|
|
7574
|
-
*
|
|
7575
|
-
*
|
|
7576
|
-
*
|
|
7577
|
-
*
|
|
7578
|
-
*
|
|
7644
|
+
* body: {
|
|
7645
|
+
* typeName: "intake_form",
|
|
7646
|
+
* schemaId: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
7647
|
+
* payload: {
|
|
7648
|
+
* "first_name": "Jane",
|
|
7649
|
+
* "email": "jane@example.com"
|
|
7650
|
+
* },
|
|
7651
|
+
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
7652
|
+
* }
|
|
7579
7653
|
* })
|
|
7580
7654
|
*/
|
|
7581
7655
|
createRecord(request, requestOptions) {
|
|
7582
7656
|
return HttpResponsePromise.fromPromise(this.__createRecord(request, requestOptions));
|
|
7583
7657
|
}
|
|
7584
7658
|
async __createRecord(request, requestOptions) {
|
|
7659
|
+
const { upsert, body: _body } = request;
|
|
7660
|
+
const _queryParams = {
|
|
7661
|
+
upsert
|
|
7662
|
+
};
|
|
7585
7663
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
7586
7664
|
const _headers = mergeHeaders(
|
|
7587
7665
|
_authRequest.headers,
|
|
@@ -7596,9 +7674,9 @@ var RecordsClient = class {
|
|
|
7596
7674
|
method: "POST",
|
|
7597
7675
|
headers: _headers,
|
|
7598
7676
|
contentType: "application/json",
|
|
7599
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
7677
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
7600
7678
|
requestType: "json",
|
|
7601
|
-
body:
|
|
7679
|
+
body: _body,
|
|
7602
7680
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
7603
7681
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
7604
7682
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -8194,43 +8272,50 @@ var SchemasClient = class {
|
|
|
8194
8272
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/schemas");
|
|
8195
8273
|
}
|
|
8196
8274
|
/**
|
|
8197
|
-
* 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.
|
|
8275
|
+
* 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.
|
|
8198
8276
|
*
|
|
8199
|
-
* @param {Vectros.
|
|
8277
|
+
* @param {Vectros.CreateSchemaRequest} request
|
|
8200
8278
|
* @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
8201
8279
|
*
|
|
8202
8280
|
* @throws {@link Vectros.BadRequestError}
|
|
8281
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
8203
8282
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
8204
8283
|
*
|
|
8205
8284
|
* @example
|
|
8206
8285
|
* await client.schemas.createSchema({
|
|
8207
|
-
*
|
|
8208
|
-
*
|
|
8209
|
-
*
|
|
8210
|
-
*
|
|
8211
|
-
*
|
|
8212
|
-
*
|
|
8213
|
-
*
|
|
8214
|
-
*
|
|
8215
|
-
*
|
|
8216
|
-
*
|
|
8217
|
-
*
|
|
8218
|
-
*
|
|
8219
|
-
*
|
|
8220
|
-
*
|
|
8221
|
-
*
|
|
8222
|
-
*
|
|
8223
|
-
*
|
|
8224
|
-
*
|
|
8225
|
-
*
|
|
8226
|
-
*
|
|
8227
|
-
*
|
|
8286
|
+
* body: {
|
|
8287
|
+
* typeName: "intake_form",
|
|
8288
|
+
* displayName: "Client Intake Form",
|
|
8289
|
+
* description: "Captures initial client information",
|
|
8290
|
+
* fields: [{
|
|
8291
|
+
* fieldId: "first_name",
|
|
8292
|
+
* fieldType: "string",
|
|
8293
|
+
* required: true,
|
|
8294
|
+
* searchable: true
|
|
8295
|
+
* }, {
|
|
8296
|
+
* fieldId: "email",
|
|
8297
|
+
* fieldType: "string",
|
|
8298
|
+
* required: true
|
|
8299
|
+
* }],
|
|
8300
|
+
* lookupFields: [{
|
|
8301
|
+
* fieldName: "email",
|
|
8302
|
+
* unique: true
|
|
8303
|
+
* }],
|
|
8304
|
+
* capabilities: {
|
|
8305
|
+
* "auditHistory": true
|
|
8306
|
+
* },
|
|
8307
|
+
* allowedSurfaces: ["record"]
|
|
8308
|
+
* }
|
|
8228
8309
|
* })
|
|
8229
8310
|
*/
|
|
8230
8311
|
createSchema(request, requestOptions) {
|
|
8231
8312
|
return HttpResponsePromise.fromPromise(this.__createSchema(request, requestOptions));
|
|
8232
8313
|
}
|
|
8233
8314
|
async __createSchema(request, requestOptions) {
|
|
8315
|
+
const { upsert, body: _body } = request;
|
|
8316
|
+
const _queryParams = {
|
|
8317
|
+
upsert
|
|
8318
|
+
};
|
|
8234
8319
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
8235
8320
|
const _headers = mergeHeaders(
|
|
8236
8321
|
_authRequest.headers,
|
|
@@ -8245,9 +8330,9 @@ var SchemasClient = class {
|
|
|
8245
8330
|
method: "POST",
|
|
8246
8331
|
headers: _headers,
|
|
8247
8332
|
contentType: "application/json",
|
|
8248
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
8333
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
8249
8334
|
requestType: "json",
|
|
8250
|
-
body:
|
|
8335
|
+
body: _body,
|
|
8251
8336
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
8252
8337
|
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
8253
8338
|
abortSignal: requestOptions?.abortSignal,
|
|
@@ -8261,6 +8346,8 @@ var SchemasClient = class {
|
|
|
8261
8346
|
switch (_response.error.statusCode) {
|
|
8262
8347
|
case 400:
|
|
8263
8348
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8349
|
+
case 403:
|
|
8350
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
8264
8351
|
case 429:
|
|
8265
8352
|
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
8266
8353
|
default:
|
|
@@ -8695,8 +8782,8 @@ function warnOnSuboptimalKey(key, log) {
|
|
|
8695
8782
|
|
|
8696
8783
|
// src/build-info.ts
|
|
8697
8784
|
var BUILD_INFO = {
|
|
8698
|
-
mcpServer: true ? "0.
|
|
8699
|
-
sdk: true ? "0.
|
|
8785
|
+
mcpServer: true ? "0.6.0" : "dev",
|
|
8786
|
+
sdk: true ? "0.32.0" : "dev"
|
|
8700
8787
|
};
|
|
8701
8788
|
function formatBuildInfo() {
|
|
8702
8789
|
return `vectros-mcp-server ${BUILD_INFO.mcpServer} (sdk ${BUILD_INFO.sdk})`;
|
|
@@ -8936,6 +9023,32 @@ ${detail}${pointer}`
|
|
|
8936
9023
|
// src/tools/hybrid_search.ts
|
|
8937
9024
|
var MCP_DEFAULT_LIMIT = 3;
|
|
8938
9025
|
var MCP_MAX_LIMIT = 10;
|
|
9026
|
+
var MCP_RESPONSE_CHAR_BUDGET = 24e3;
|
|
9027
|
+
var SNIPPET_MAX_CHARS = 160;
|
|
9028
|
+
var INTERNAL_METADATA_KEYS = /* @__PURE__ */ new Set(["tenantId", "owner_id", "model_type", "rootFolderId", "folderId"]);
|
|
9029
|
+
function trimMetadata(md) {
|
|
9030
|
+
if (!md || typeof md !== "object" || Array.isArray(md)) return md;
|
|
9031
|
+
const out = {};
|
|
9032
|
+
for (const [k, v] of Object.entries(md)) {
|
|
9033
|
+
if (!INTERNAL_METADATA_KEYS.has(k)) out[k] = v;
|
|
9034
|
+
}
|
|
9035
|
+
return out;
|
|
9036
|
+
}
|
|
9037
|
+
function reshapeHit(hit, includeContext) {
|
|
9038
|
+
const out = { ...hit };
|
|
9039
|
+
if ("metadata" in out) out.metadata = trimMetadata(out.metadata);
|
|
9040
|
+
const chunk = typeof hit.chunkText === "string" ? hit.chunkText : void 0;
|
|
9041
|
+
const ctx = typeof hit.contextText === "string" ? hit.contextText : void 0;
|
|
9042
|
+
if (includeContext) {
|
|
9043
|
+
if (chunk && ctx && ctx.includes(chunk)) delete out.chunkText;
|
|
9044
|
+
} else {
|
|
9045
|
+
delete out.contextText;
|
|
9046
|
+
}
|
|
9047
|
+
if ((out.snippet == null || out.snippet === "") && chunk) {
|
|
9048
|
+
out.snippet = chunk.length > SNIPPET_MAX_CHARS ? chunk.slice(0, SNIPPET_MAX_CHARS) + "\u2026" : chunk;
|
|
9049
|
+
}
|
|
9050
|
+
return out;
|
|
9051
|
+
}
|
|
8939
9052
|
var inputSchema = {
|
|
8940
9053
|
query: import_zod.z.string().min(1, "query must be non-empty").describe("Natural-language or keyword query."),
|
|
8941
9054
|
mode: import_zod.z.enum(["HYBRID", "TEXT", "SEMANTIC"]).optional().describe("HYBRID (BM25 + dense, default), TEXT (BM25 only), or SEMANTIC (dense only)."),
|
|
@@ -8950,7 +9063,9 @@ var inputSchema = {
|
|
|
8950
9063
|
rootFolderId: import_zod.z.string().optional().describe("Scope to content under this folder AND all its descendants (subtree-root folder id)."),
|
|
8951
9064
|
// Content narrowing.
|
|
8952
9065
|
contentTypes: import_zod.z.array(import_zod.z.enum(["documents", "records"])).optional().describe('Narrow to content types. ["documents"] or ["records"]; omit for unified (both).'),
|
|
8953
|
-
typeName: import_zod.z.string().optional().describe(
|
|
9066
|
+
typeName: import_zod.z.string().optional().describe(
|
|
9067
|
+
'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.'
|
|
9068
|
+
),
|
|
8954
9069
|
filters: import_zod.z.record(import_zod.z.unknown()).optional().describe(
|
|
8955
9070
|
'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}}.'
|
|
8956
9071
|
),
|
|
@@ -8965,6 +9080,9 @@ var inputSchema = {
|
|
|
8965
9080
|
minSimilarity: import_zod.z.number().min(0).max(1).optional().describe("Minimum semantic similarity (0.0\u20131.0); results below are excluded."),
|
|
8966
9081
|
minTextRelevance: import_zod.z.number().min(0).max(1).optional().describe("Minimum relative keyword (BM25) relevance (0.0\u20131.0); the keyword-leg analogue of minSimilarity."),
|
|
8967
9082
|
uniqueDocuments: import_zod.z.boolean().optional().describe("When true, return at most one chunk per source document."),
|
|
9083
|
+
includeContext: import_zod.z.boolean().optional().describe(
|
|
9084
|
+
"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."
|
|
9085
|
+
),
|
|
8968
9086
|
requireComplete: import_zod.z.boolean().optional().describe(
|
|
8969
9087
|
"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)."
|
|
8970
9088
|
)
|
|
@@ -8972,7 +9090,7 @@ var inputSchema = {
|
|
|
8972
9090
|
var hybridSearch = ({ client, log }) => ({
|
|
8973
9091
|
name: "hybrid_search",
|
|
8974
9092
|
title: "Hybrid search",
|
|
8975
|
-
description:
|
|
9093
|
+
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".`,
|
|
8976
9094
|
inputSchema,
|
|
8977
9095
|
handler: async (args) => {
|
|
8978
9096
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT;
|
|
@@ -8999,13 +9117,30 @@ var hybridSearch = ({ client, log }) => ({
|
|
|
8999
9117
|
uniqueDocuments: args.uniqueDocuments,
|
|
9000
9118
|
requireComplete: args.requireComplete
|
|
9001
9119
|
});
|
|
9120
|
+
const hits = Array.isArray(
|
|
9121
|
+
result.results
|
|
9122
|
+
) ? result.results : [];
|
|
9123
|
+
const includeContext = args.includeContext ?? false;
|
|
9124
|
+
let shaped = hits.map((h) => reshapeHit(h, includeContext));
|
|
9125
|
+
const textLegEmpty = mode !== "SEMANTIC" && hits.length > 0 && hits.every((h) => !(Number(h.textScore) > 0));
|
|
9126
|
+
const envelope = {
|
|
9127
|
+
...result,
|
|
9128
|
+
results: shaped
|
|
9129
|
+
};
|
|
9130
|
+
if (textLegEmpty) envelope.textLegEmpty = true;
|
|
9131
|
+
let text = JSON.stringify(envelope, null, 2);
|
|
9132
|
+
while (shaped.length > 1 && text.length > MCP_RESPONSE_CHAR_BUDGET) {
|
|
9133
|
+
shaped = shaped.slice(0, -1);
|
|
9134
|
+
envelope.results = shaped;
|
|
9135
|
+
envelope.truncated = true;
|
|
9136
|
+
envelope.returnedResults = shaped.length;
|
|
9137
|
+
text = JSON.stringify(envelope, null, 2);
|
|
9138
|
+
}
|
|
9002
9139
|
log.debug(
|
|
9003
|
-
{ tool: "hybrid_search", mode, limit, returned:
|
|
9140
|
+
{ tool: "hybrid_search", mode, limit, returned: shaped.length, textLegEmpty },
|
|
9004
9141
|
"hybrid_search ok"
|
|
9005
9142
|
);
|
|
9006
|
-
return {
|
|
9007
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
9008
|
-
};
|
|
9143
|
+
return { content: [{ type: "text", text }] };
|
|
9009
9144
|
} catch (err) {
|
|
9010
9145
|
log.warn({ tool: "hybrid_search", err: String(err) }, "hybrid_search failed");
|
|
9011
9146
|
return toolError("hybrid_search", err);
|
|
@@ -9040,7 +9175,9 @@ var MCP_MAX_LIMIT2 = 10;
|
|
|
9040
9175
|
var inputSchema2 = {
|
|
9041
9176
|
type: import_zod2.z.string().min(1, "type (record type) is required").describe('Record type / schema name (e.g. "patient", "clinical_note").'),
|
|
9042
9177
|
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | from+to | prefix.
|
|
9043
|
-
field: import_zod2.z.string().optional().describe(
|
|
9178
|
+
field: import_zod2.z.string().optional().describe(
|
|
9179
|
+
'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.)'
|
|
9180
|
+
),
|
|
9044
9181
|
value: import_zod2.z.string().optional().describe("Lookup mode (equality): exact-match value for `field`."),
|
|
9045
9182
|
from: import_zod2.z.string().optional().describe("Lookup mode (range): inclusive lower bound; requires `to`. Non-sensitive fields only."),
|
|
9046
9183
|
to: import_zod2.z.string().optional().describe("Lookup mode (range): inclusive upper bound; requires `from`."),
|
|
@@ -9135,19 +9272,77 @@ var record_query_default = recordQuery;
|
|
|
9135
9272
|
|
|
9136
9273
|
// src/tools/record_get.ts
|
|
9137
9274
|
var import_zod3 = require("zod");
|
|
9275
|
+
|
|
9276
|
+
// src/tools/resolve-external-id.ts
|
|
9277
|
+
function validateSelector(sel, entity) {
|
|
9278
|
+
const hasId = sel.id !== void 0 && sel.id !== "";
|
|
9279
|
+
const hasExt = sel.externalId !== void 0 && sel.externalId !== "";
|
|
9280
|
+
if (hasId && hasExt) {
|
|
9281
|
+
return `Provide either id or externalId (not both) to identify the ${entity}.`;
|
|
9282
|
+
}
|
|
9283
|
+
if (!hasId && !hasExt) {
|
|
9284
|
+
return `Provide id, or externalId + type, to identify the ${entity}.`;
|
|
9285
|
+
}
|
|
9286
|
+
if (hasExt && (sel.type === void 0 || sel.type === "")) {
|
|
9287
|
+
return "type is required when selecting by externalId (externalId is unique within a type).";
|
|
9288
|
+
}
|
|
9289
|
+
return void 0;
|
|
9290
|
+
}
|
|
9291
|
+
async function resolveRecordIdByExternalId(client, sel) {
|
|
9292
|
+
const err = validateSelector(sel, "record");
|
|
9293
|
+
if (err) return { error: err };
|
|
9294
|
+
if (sel.id) return { id: sel.id };
|
|
9295
|
+
const page = await client.records.lookupRecordsByBody({
|
|
9296
|
+
type: sel.type,
|
|
9297
|
+
field: "externalId",
|
|
9298
|
+
value: sel.externalId,
|
|
9299
|
+
limit: 1
|
|
9300
|
+
});
|
|
9301
|
+
const items = pageItems(page);
|
|
9302
|
+
if (items.length === 0) {
|
|
9303
|
+
return { error: `No record of type '${sel.type}' with externalId '${sel.externalId}'.` };
|
|
9304
|
+
}
|
|
9305
|
+
return { id: items[0].id };
|
|
9306
|
+
}
|
|
9307
|
+
async function resolveDocumentIdByExternalId(client, sel) {
|
|
9308
|
+
const err = validateSelector(sel, "document");
|
|
9309
|
+
if (err) return { error: err };
|
|
9310
|
+
if (sel.id) return { id: sel.id };
|
|
9311
|
+
const page = await client.documents.lookupDocumentsByBody({
|
|
9312
|
+
type: sel.type,
|
|
9313
|
+
field: "externalId",
|
|
9314
|
+
value: sel.externalId,
|
|
9315
|
+
limit: 1
|
|
9316
|
+
});
|
|
9317
|
+
const items = pageItems(page);
|
|
9318
|
+
if (items.length === 0) {
|
|
9319
|
+
return { error: `No document of type '${sel.type}' with externalId '${sel.externalId}'.` };
|
|
9320
|
+
}
|
|
9321
|
+
return { id: items[0].id };
|
|
9322
|
+
}
|
|
9323
|
+
|
|
9324
|
+
// src/tools/record_get.ts
|
|
9138
9325
|
var MAX_PAYLOAD_CHARS = 32e3;
|
|
9139
9326
|
var inputSchema3 = {
|
|
9140
|
-
id: import_zod3.z.string().
|
|
9327
|
+
id: import_zod3.z.string().optional().describe("The Vectros record id (e.g. from record_query or hybrid_search). Provide this OR externalId+type."),
|
|
9328
|
+
externalId: import_zod3.z.string().optional().describe(
|
|
9329
|
+
"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."
|
|
9330
|
+
),
|
|
9331
|
+
type: import_zod3.z.string().optional().describe("Record type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type).")
|
|
9141
9332
|
};
|
|
9142
9333
|
var recordGet = ({ client, log }) => ({
|
|
9143
9334
|
name: "record_get",
|
|
9144
|
-
title: "Get a record by id",
|
|
9145
|
-
description: "Fetch a single structured record
|
|
9335
|
+
title: "Get a record by id or externalId",
|
|
9336
|
+
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.",
|
|
9146
9337
|
inputSchema: inputSchema3,
|
|
9147
9338
|
handler: async (args) => {
|
|
9148
9339
|
const id = args.id;
|
|
9340
|
+
const externalId = args.externalId;
|
|
9341
|
+
const type = args.type;
|
|
9149
9342
|
try {
|
|
9150
|
-
const
|
|
9343
|
+
const resolved = await resolveRecordIdByExternalId(client, { id, externalId, type });
|
|
9344
|
+
if ("error" in resolved) return toolError("record_get", new Error(resolved.error));
|
|
9345
|
+
const record = await client.records.getRecord({ id: resolved.id });
|
|
9151
9346
|
const out = { ...record };
|
|
9152
9347
|
if (record.payload !== void 0) {
|
|
9153
9348
|
const json = JSON.stringify(record.payload);
|
|
@@ -9159,12 +9354,12 @@ var recordGet = ({ client, log }) => ({
|
|
|
9159
9354
|
}
|
|
9160
9355
|
}
|
|
9161
9356
|
log.debug(
|
|
9162
|
-
{ tool: "record_get", id, truncated: out.payloadTruncated === true },
|
|
9357
|
+
{ tool: "record_get", id: resolved.id, externalId, truncated: out.payloadTruncated === true },
|
|
9163
9358
|
"record_get ok"
|
|
9164
9359
|
);
|
|
9165
9360
|
return { content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
|
|
9166
9361
|
} catch (err) {
|
|
9167
|
-
log.warn({ tool: "record_get", id, err: String(err) }, "record_get failed");
|
|
9362
|
+
log.warn({ tool: "record_get", id, externalId, type, err: String(err) }, "record_get failed");
|
|
9168
9363
|
return toolError("record_get", err);
|
|
9169
9364
|
}
|
|
9170
9365
|
}
|
|
@@ -9199,15 +9394,17 @@ var recordCreate = ({ client, log }) => ({
|
|
|
9199
9394
|
const type = args.type;
|
|
9200
9395
|
try {
|
|
9201
9396
|
const created = await client.records.createRecord({
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9397
|
+
body: {
|
|
9398
|
+
typeName: type,
|
|
9399
|
+
payload: args.fields,
|
|
9400
|
+
externalId: args.externalId,
|
|
9401
|
+
indexMode: args.indexMode,
|
|
9402
|
+
status: args.status,
|
|
9403
|
+
folderId: args.folderId,
|
|
9404
|
+
userId: args.userId,
|
|
9405
|
+
orgId: args.orgId,
|
|
9406
|
+
clientId: args.clientId
|
|
9407
|
+
}
|
|
9211
9408
|
});
|
|
9212
9409
|
log.debug({ tool: "record_create", type, id: created.id }, "record_create ok");
|
|
9213
9410
|
return { content: [{ type: "text", text: JSON.stringify(created, null, 2) }] };
|
|
@@ -9222,7 +9419,11 @@ var record_create_default = recordCreate;
|
|
|
9222
9419
|
// src/tools/record_update.ts
|
|
9223
9420
|
var import_zod5 = require("zod");
|
|
9224
9421
|
var inputSchema5 = {
|
|
9225
|
-
id: import_zod5.z.string().
|
|
9422
|
+
id: import_zod5.z.string().optional().describe("The Vectros record id to update. Provide this OR externalId+type."),
|
|
9423
|
+
externalId: import_zod5.z.string().optional().describe(
|
|
9424
|
+
"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."
|
|
9425
|
+
),
|
|
9426
|
+
type: import_zod5.z.string().optional().describe("Record type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9226
9427
|
fields: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.unknown()).describe(
|
|
9227
9428
|
"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."
|
|
9228
9429
|
),
|
|
@@ -9233,23 +9434,27 @@ var inputSchema5 = {
|
|
|
9233
9434
|
};
|
|
9234
9435
|
var recordUpdate = ({ client, log }) => ({
|
|
9235
9436
|
name: "record_update",
|
|
9236
|
-
title: "Update a record",
|
|
9237
|
-
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.",
|
|
9437
|
+
title: "Update a record by id or externalId",
|
|
9438
|
+
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.",
|
|
9238
9439
|
inputSchema: inputSchema5,
|
|
9239
9440
|
handler: async (args) => {
|
|
9240
9441
|
const id = args.id;
|
|
9442
|
+
const externalId = args.externalId;
|
|
9443
|
+
const type = args.type;
|
|
9241
9444
|
const fields = args.fields;
|
|
9242
9445
|
const status = args.status;
|
|
9243
9446
|
const expectedVersion = args.expectedVersion;
|
|
9244
9447
|
try {
|
|
9448
|
+
const resolved = await resolveRecordIdByExternalId(client, { id, externalId, type });
|
|
9449
|
+
if ("error" in resolved) return toolError("record_update", new Error(resolved.error));
|
|
9245
9450
|
const body = { payload: fields };
|
|
9246
9451
|
if (status !== void 0) body.status = status;
|
|
9247
9452
|
if (expectedVersion !== void 0) body.expectedVersion = expectedVersion;
|
|
9248
|
-
const updated = await client.records.patchRecord({ id, body });
|
|
9249
|
-
log.debug({ tool: "record_update", id }, "record_update ok");
|
|
9453
|
+
const updated = await client.records.patchRecord({ id: resolved.id, body });
|
|
9454
|
+
log.debug({ tool: "record_update", id: resolved.id, externalId }, "record_update ok");
|
|
9250
9455
|
return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
|
|
9251
9456
|
} catch (err) {
|
|
9252
|
-
log.warn({ tool: "record_update", id, err: String(err) }, "record_update failed");
|
|
9457
|
+
log.warn({ tool: "record_update", id, externalId, type, err: String(err) }, "record_update failed");
|
|
9253
9458
|
return toolError("record_update", err);
|
|
9254
9459
|
}
|
|
9255
9460
|
}
|
|
@@ -9516,7 +9721,11 @@ var list_schemas_default = listSchemas;
|
|
|
9516
9721
|
var import_zod10 = require("zod");
|
|
9517
9722
|
var MAX_TEXT_CHARS = 32e3;
|
|
9518
9723
|
var inputSchema10 = {
|
|
9519
|
-
documentId: import_zod10.z.string().
|
|
9724
|
+
documentId: import_zod10.z.string().optional().describe("The document ID returned by document_ingest or hybrid_search. Provide this OR externalId+type."),
|
|
9725
|
+
externalId: import_zod10.z.string().optional().describe(
|
|
9726
|
+
"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."
|
|
9727
|
+
),
|
|
9728
|
+
type: import_zod10.z.string().optional().describe("Document type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9520
9729
|
includeText: import_zod10.z.boolean().optional().describe(
|
|
9521
9730
|
"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."
|
|
9522
9731
|
),
|
|
@@ -9536,13 +9745,18 @@ function isNotAvailable(err) {
|
|
|
9536
9745
|
var documentGet = ({ client, log }) => ({
|
|
9537
9746
|
name: "document_get",
|
|
9538
9747
|
title: "Get document metadata (and optionally text)",
|
|
9539
|
-
description: "Fetch metadata for a single document by
|
|
9748
|
+
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`.",
|
|
9540
9749
|
inputSchema: inputSchema10,
|
|
9541
9750
|
handler: async (args) => {
|
|
9542
|
-
const
|
|
9751
|
+
const documentId = args.documentId;
|
|
9752
|
+
const externalId = args.externalId;
|
|
9753
|
+
const type = args.type;
|
|
9543
9754
|
const includeText = args.includeText ?? false;
|
|
9544
9755
|
const includeDownloadUrl = args.includeDownloadUrl ?? false;
|
|
9545
9756
|
try {
|
|
9757
|
+
const resolved = await resolveDocumentIdByExternalId(client, { id: documentId, externalId, type });
|
|
9758
|
+
if ("error" in resolved) return toolError("document_get", new Error(resolved.error));
|
|
9759
|
+
const id = resolved.id;
|
|
9546
9760
|
const doc = await client.documents.getDocument({ id });
|
|
9547
9761
|
let extra = {};
|
|
9548
9762
|
if (includeText) {
|
|
@@ -9589,7 +9803,7 @@ var documentGet = ({ client, log }) => ({
|
|
|
9589
9803
|
]
|
|
9590
9804
|
};
|
|
9591
9805
|
} catch (err) {
|
|
9592
|
-
log.warn({ tool: "document_get",
|
|
9806
|
+
log.warn({ tool: "document_get", documentId, externalId, type, err: String(err) }, "document_get failed");
|
|
9593
9807
|
return toolError("document_get", err);
|
|
9594
9808
|
}
|
|
9595
9809
|
}
|
|
@@ -9704,13 +9918,23 @@ var document_query_default = documentQuery;
|
|
|
9704
9918
|
// src/tools/document_update.ts
|
|
9705
9919
|
var import_zod12 = require("zod");
|
|
9706
9920
|
var inputSchema12 = {
|
|
9707
|
-
documentId: import_zod12.z.string().
|
|
9921
|
+
documentId: import_zod12.z.string().optional().describe("The Vectros document id to update. Provide this OR externalId+type."),
|
|
9922
|
+
externalId: import_zod12.z.string().optional().describe(
|
|
9923
|
+
"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."
|
|
9924
|
+
),
|
|
9925
|
+
type: import_zod12.z.string().optional().describe("Document type \u2014 REQUIRED when selecting by `externalId` (externalId is unique within a type)."),
|
|
9708
9926
|
title: import_zod12.z.string().optional().describe("New title. Omit to keep the current title."),
|
|
9709
9927
|
fields: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown()).optional().describe(
|
|
9710
9928
|
"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."
|
|
9711
9929
|
),
|
|
9930
|
+
text: import_zod12.z.string().optional().describe(
|
|
9931
|
+
"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."
|
|
9932
|
+
),
|
|
9712
9933
|
folderId: import_zod12.z.string().optional().describe("Move the document into this folder (cannot be cleared once set)."),
|
|
9713
9934
|
storeText: import_zod12.z.boolean().optional().describe("Whether the raw text is stored + retrievable."),
|
|
9935
|
+
status: import_zod12.z.enum(["ACTIVE", "ARCHIVED"]).optional().describe(
|
|
9936
|
+
"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."
|
|
9937
|
+
),
|
|
9714
9938
|
userId: import_zod12.z.string().optional().describe("Reassign the owning user (Vectros UUID)."),
|
|
9715
9939
|
orgId: import_zod12.z.string().optional().describe("Reassign the owning org (Vectros UUID)."),
|
|
9716
9940
|
clientId: import_zod12.z.string().optional().describe("Reassign the associated client (Vectros UUID)."),
|
|
@@ -9721,33 +9945,41 @@ var inputSchema12 = {
|
|
|
9721
9945
|
var documentUpdate = ({ client, log }) => ({
|
|
9722
9946
|
name: "document_update",
|
|
9723
9947
|
title: "Update a document",
|
|
9724
|
-
description:
|
|
9948
|
+
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.',
|
|
9725
9949
|
inputSchema: inputSchema12,
|
|
9726
9950
|
handler: async (args) => {
|
|
9727
9951
|
const documentId = args.documentId;
|
|
9952
|
+
const externalId = args.externalId;
|
|
9953
|
+
const type = args.type;
|
|
9728
9954
|
const title = args.title;
|
|
9729
9955
|
const fields = args.fields;
|
|
9956
|
+
const text = args.text;
|
|
9730
9957
|
const folderId = args.folderId;
|
|
9731
9958
|
const storeText = args.storeText;
|
|
9959
|
+
const status = args.status;
|
|
9732
9960
|
const userId = args.userId;
|
|
9733
9961
|
const orgId = args.orgId;
|
|
9734
9962
|
const clientId = args.clientId;
|
|
9735
9963
|
const expectedVersion = args.expectedVersion;
|
|
9736
9964
|
try {
|
|
9965
|
+
const resolved = await resolveDocumentIdByExternalId(client, { id: documentId, externalId, type });
|
|
9966
|
+
if ("error" in resolved) return toolError("document_update", new Error(resolved.error));
|
|
9737
9967
|
const body = {};
|
|
9738
9968
|
if (title !== void 0) body.title = title;
|
|
9739
9969
|
if (fields !== void 0) body.payload = fields;
|
|
9970
|
+
if (text !== void 0) body.text = text;
|
|
9740
9971
|
if (folderId !== void 0) body.folderId = folderId;
|
|
9741
9972
|
if (storeText !== void 0) body.storeText = storeText;
|
|
9973
|
+
if (status !== void 0) body.status = status;
|
|
9742
9974
|
if (userId !== void 0) body.userId = userId;
|
|
9743
9975
|
if (orgId !== void 0) body.orgId = orgId;
|
|
9744
9976
|
if (clientId !== void 0) body.clientId = clientId;
|
|
9745
9977
|
if (expectedVersion !== void 0) body.expectedVersion = expectedVersion;
|
|
9746
9978
|
const updated = await client.documents.patchDocument({
|
|
9747
|
-
id:
|
|
9979
|
+
id: resolved.id,
|
|
9748
9980
|
body
|
|
9749
9981
|
});
|
|
9750
|
-
log.debug({ tool: "document_update", documentId }, "document_update ok");
|
|
9982
|
+
log.debug({ tool: "document_update", documentId: resolved.id, externalId }, "document_update ok");
|
|
9751
9983
|
return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
|
|
9752
9984
|
} catch (err) {
|
|
9753
9985
|
log.warn({ tool: "document_update", documentId, err: String(err) }, "document_update failed");
|
|
@@ -9765,7 +9997,7 @@ var inputSchema13 = {
|
|
|
9765
9997
|
var documentDelete = ({ client, log }) => ({
|
|
9766
9998
|
name: "document_delete",
|
|
9767
9999
|
title: "Delete a document",
|
|
9768
|
-
description:
|
|
10000
|
+
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).',
|
|
9769
10001
|
inputSchema: inputSchema13,
|
|
9770
10002
|
handler: async (args) => {
|
|
9771
10003
|
const documentId = args.documentId;
|
|
@@ -9849,13 +10081,15 @@ var folderCreate = ({ client, log }) => ({
|
|
|
9849
10081
|
handler: async (args) => {
|
|
9850
10082
|
try {
|
|
9851
10083
|
const folder = await client.folders.createFolder({
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
9857
|
-
|
|
9858
|
-
|
|
10084
|
+
body: {
|
|
10085
|
+
name: args.name,
|
|
10086
|
+
description: args.description,
|
|
10087
|
+
parentFolderId: args.parentId,
|
|
10088
|
+
slug: args.slug,
|
|
10089
|
+
userId: args.userId,
|
|
10090
|
+
orgId: args.orgId,
|
|
10091
|
+
clientId: args.clientId
|
|
10092
|
+
}
|
|
9859
10093
|
});
|
|
9860
10094
|
log.debug({ tool: "folder_create", id: folder.id, name: folder.name }, "folder_create ok");
|
|
9861
10095
|
return { content: [{ type: "text", text: JSON.stringify(folder, null, 2) }] };
|
|
@@ -10043,6 +10277,9 @@ var inputSchema19 = {
|
|
|
10043
10277
|
externalId: import_zod18.z.string().optional().describe(
|
|
10044
10278
|
"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."
|
|
10045
10279
|
),
|
|
10280
|
+
upsert: import_zod18.z.boolean().optional().describe(
|
|
10281
|
+
"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)."
|
|
10282
|
+
),
|
|
10046
10283
|
schemaId: import_zod18.z.string().optional().describe(
|
|
10047
10284
|
"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."
|
|
10048
10285
|
),
|
|
@@ -10068,13 +10305,14 @@ var inputSchema19 = {
|
|
|
10068
10305
|
var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
10069
10306
|
name: "document_ingest",
|
|
10070
10307
|
title: "Ingest a new document (text body or file upload)",
|
|
10071
|
-
description: "Create a new document in
|
|
10308
|
+
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).",
|
|
10072
10309
|
inputSchema: inputSchema19,
|
|
10073
10310
|
handler: async (args) => {
|
|
10074
10311
|
const title = args.title;
|
|
10075
10312
|
const text = args.text;
|
|
10076
10313
|
const filePath = args.filePath;
|
|
10077
10314
|
const schemaId = args.schemaId;
|
|
10315
|
+
const upsert = args.upsert;
|
|
10078
10316
|
const indexMode = args.indexMode ?? (schemaId ? void 0 : "HYBRID");
|
|
10079
10317
|
if (!text && !filePath) {
|
|
10080
10318
|
return toolError(
|
|
@@ -10109,11 +10347,14 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10109
10347
|
if (text) {
|
|
10110
10348
|
const storeText = args.storeText ?? true;
|
|
10111
10349
|
const result = await client.documents.ingestDocument({
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10350
|
+
upsert,
|
|
10351
|
+
body: {
|
|
10352
|
+
title,
|
|
10353
|
+
text,
|
|
10354
|
+
indexMode,
|
|
10355
|
+
storeText,
|
|
10356
|
+
...common
|
|
10357
|
+
}
|
|
10117
10358
|
});
|
|
10118
10359
|
log.debug(
|
|
10119
10360
|
{ tool: "document_ingest", mode: "text", id: result?.id, indexMode },
|
|
@@ -10143,6 +10384,7 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10143
10384
|
const fileName = (0, import_node_path.basename)(safePath);
|
|
10144
10385
|
const fileType = args.fileType ?? inferMimeType(safePath);
|
|
10145
10386
|
const upload = await client.documents.uploadDocument({
|
|
10387
|
+
upsert,
|
|
10146
10388
|
fileName,
|
|
10147
10389
|
fileType,
|
|
10148
10390
|
indexMode,
|
|
@@ -10181,8 +10423,8 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10181
10423
|
text: JSON.stringify(
|
|
10182
10424
|
{
|
|
10183
10425
|
...upload,
|
|
10184
|
-
|
|
10185
|
-
_note: "File uploaded; indexing is asynchronous. Poll document_get(id) until
|
|
10426
|
+
indexStatus: "PENDING_INDEX",
|
|
10427
|
+
_note: "File uploaded; indexing is asynchronous. Poll document_get(id) until indexStatus is INDEXED."
|
|
10186
10428
|
},
|
|
10187
10429
|
null,
|
|
10188
10430
|
2
|
|
@@ -10479,6 +10721,14 @@ function zodTypeToJsonSchema(schema) {
|
|
|
10479
10721
|
|
|
10480
10722
|
// src/server.ts
|
|
10481
10723
|
var DEFAULT_ENVIRONMENT = "https://api.vectros.ai";
|
|
10724
|
+
function formatArgError(tool, error) {
|
|
10725
|
+
const unknownKeys = error.issues.filter((i) => i.code === "unrecognized_keys").flatMap((i) => i.keys);
|
|
10726
|
+
if (unknownKeys.length > 0) {
|
|
10727
|
+
const valid = Object.keys(tool.inputSchema).join(", ");
|
|
10728
|
+
return `Unknown argument(s): ${unknownKeys.join(", ")}. Valid arguments for ${tool.name}: ${valid}. Pass only these \u2014 an unrecognized argument is rejected, not ignored.`;
|
|
10729
|
+
}
|
|
10730
|
+
return `Invalid arguments: ${error.message}`;
|
|
10731
|
+
}
|
|
10482
10732
|
var VectrosMCPServer = class {
|
|
10483
10733
|
server;
|
|
10484
10734
|
log;
|
|
@@ -10568,7 +10818,11 @@ var VectrosMCPServer = class {
|
|
|
10568
10818
|
name: t.name,
|
|
10569
10819
|
title: t.title,
|
|
10570
10820
|
description: t.description,
|
|
10571
|
-
|
|
10821
|
+
// additionalProperties:false advertises strict argument validation to the
|
|
10822
|
+
// MCP client (a well-behaved client rejects an unknown key before the call).
|
|
10823
|
+
// The server enforces it too (z.object(...).strict() below) so a raw JSON-RPC
|
|
10824
|
+
// call that skips client validation is still rejected — belt and suspenders.
|
|
10825
|
+
inputSchema: { ...zodShapeToJsonSchema(t.inputSchema), additionalProperties: false }
|
|
10572
10826
|
}))
|
|
10573
10827
|
})
|
|
10574
10828
|
);
|
|
@@ -10578,9 +10832,9 @@ var VectrosMCPServer = class {
|
|
|
10578
10832
|
if (!tool) {
|
|
10579
10833
|
result = toolError(req.params.name ?? "unknown", new Error("No such tool."));
|
|
10580
10834
|
} else {
|
|
10581
|
-
const parsed = import_zod22.z.object(tool.inputSchema).safeParse(req.params.arguments ?? {});
|
|
10835
|
+
const parsed = import_zod22.z.object(tool.inputSchema).strict().safeParse(req.params.arguments ?? {});
|
|
10582
10836
|
if (!parsed.success) {
|
|
10583
|
-
result = toolError(tool.name, new Error(
|
|
10837
|
+
result = toolError(tool.name, new Error(formatArgError(tool, parsed.error)));
|
|
10584
10838
|
} else {
|
|
10585
10839
|
try {
|
|
10586
10840
|
result = await tool.handler(
|