@vectros-ai/mcp-server 0.7.0 → 0.9.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 +58 -0
- package/README.md +7 -0
- package/dist/cli-http.js +152 -60
- package/dist/cli-http.js.map +1 -1
- package/dist/cli-http.mjs +152 -60
- package/dist/cli-http.mjs.map +1 -1
- package/dist/cli.js +152 -60
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +152 -60
- package/dist/cli.mjs.map +1 -1
- package/dist/index.js +152 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -60
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -652,6 +652,10 @@ var ReadAccessLogResponse;
|
|
|
652
652
|
})(ReadAccessLogResponse || (ReadAccessLogResponse = {}));
|
|
653
653
|
var RecordRequest;
|
|
654
654
|
((RecordRequest2) => {
|
|
655
|
+
RecordRequest2.Status = {
|
|
656
|
+
Active: "ACTIVE",
|
|
657
|
+
Archived: "ARCHIVED"
|
|
658
|
+
};
|
|
655
659
|
RecordRequest2.IndexMode = {
|
|
656
660
|
Hybrid: "HYBRID",
|
|
657
661
|
Semantic: "SEMANTIC",
|
|
@@ -661,6 +665,10 @@ var RecordRequest;
|
|
|
661
665
|
})(RecordRequest || (RecordRequest = {}));
|
|
662
666
|
var RecordResponse;
|
|
663
667
|
((RecordResponse2) => {
|
|
668
|
+
RecordResponse2.Status = {
|
|
669
|
+
Active: "ACTIVE",
|
|
670
|
+
Archived: "ARCHIVED"
|
|
671
|
+
};
|
|
664
672
|
RecordResponse2.IndexStatus = {
|
|
665
673
|
PendingIndex: "PENDING_INDEX",
|
|
666
674
|
Indexed: "INDEXED",
|
|
@@ -3135,7 +3143,7 @@ var AuthClient = class {
|
|
|
3135
3143
|
* roleId: "engineering-member",
|
|
3136
3144
|
* name: "Engineering Team Member",
|
|
3137
3145
|
* scopes: [{
|
|
3138
|
-
* allowed_actions: ["
|
|
3146
|
+
* allowed_actions: ["records:cru", "search:r"]
|
|
3139
3147
|
* }]
|
|
3140
3148
|
* }
|
|
3141
3149
|
* })
|
|
@@ -3683,7 +3691,7 @@ var AuthClient = class {
|
|
|
3683
3691
|
* roleId: "engineering-member",
|
|
3684
3692
|
* name: "Engineering Team Member",
|
|
3685
3693
|
* scopes: [{
|
|
3686
|
-
* allowed_actions: ["
|
|
3694
|
+
* allowed_actions: ["records:cru", "search:r"]
|
|
3687
3695
|
* }]
|
|
3688
3696
|
* }
|
|
3689
3697
|
* })
|
|
@@ -4586,7 +4594,7 @@ var DocumentsClient = class {
|
|
|
4586
4594
|
this._options = normalizeClientOptionsWithAuth(options);
|
|
4587
4595
|
}
|
|
4588
4596
|
/**
|
|
4589
|
-
* Returns a paginated list of your documents, optionally filtered by folder (`folderId`) and/or owner (`userId`, `orgId`, or `
|
|
4597
|
+
* Returns a paginated list of your documents, optionally filtered by folder (`folderId`) and/or owner (`userId`, `orgId`, `clientId`, or `scope`). The response is a `{data, nextCursor}` envelope; pass `nextCursor` back as `startFrom` to fetch the next page. Requires the `documents:r` scope.
|
|
4590
4598
|
*
|
|
4591
4599
|
* @param {Vectros.ListDocumentsRequest} request
|
|
4592
4600
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -4596,6 +4604,7 @@ var DocumentsClient = class {
|
|
|
4596
4604
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
4597
4605
|
* orgId: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
4598
4606
|
* clientId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
4607
|
+
* scope: "group:eng-team",
|
|
4599
4608
|
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
4600
4609
|
* startFrom: "doc_prev123"
|
|
4601
4610
|
* })
|
|
@@ -4604,11 +4613,12 @@ var DocumentsClient = class {
|
|
|
4604
4613
|
return HttpResponsePromise.fromPromise(this.__listDocuments(request, requestOptions));
|
|
4605
4614
|
}
|
|
4606
4615
|
async __listDocuments(request = {}, requestOptions) {
|
|
4607
|
-
const { userId, orgId, clientId, folderId, startFrom, limit } = request;
|
|
4616
|
+
const { userId, orgId, clientId, scope, folderId, startFrom, limit } = request;
|
|
4608
4617
|
const _queryParams = {
|
|
4609
4618
|
userId,
|
|
4610
4619
|
orgId,
|
|
4611
4620
|
clientId,
|
|
4621
|
+
scope,
|
|
4612
4622
|
folderId,
|
|
4613
4623
|
startFrom,
|
|
4614
4624
|
limit
|
|
@@ -4666,9 +4676,10 @@ var DocumentsClient = class {
|
|
|
4666
4676
|
return HttpResponsePromise.fromPromise(this.__ingestDocument(request, requestOptions));
|
|
4667
4677
|
}
|
|
4668
4678
|
async __ingestDocument(request, requestOptions) {
|
|
4669
|
-
const { upsert, body: _body } = request;
|
|
4679
|
+
const { upsert, allowClear, body: _body } = request;
|
|
4670
4680
|
const _queryParams = {
|
|
4671
|
-
upsert
|
|
4681
|
+
upsert,
|
|
4682
|
+
allowClear
|
|
4672
4683
|
};
|
|
4673
4684
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4674
4685
|
const _headers = mergeHeaders(
|
|
@@ -4792,7 +4803,10 @@ var DocumentsClient = class {
|
|
|
4792
4803
|
return HttpResponsePromise.fromPromise(this.__updateDocument(request, requestOptions));
|
|
4793
4804
|
}
|
|
4794
4805
|
async __updateDocument(request, requestOptions) {
|
|
4795
|
-
const { id, body: _body } = request;
|
|
4806
|
+
const { id, allowClear, body: _body } = request;
|
|
4807
|
+
const _queryParams = {
|
|
4808
|
+
allowClear
|
|
4809
|
+
};
|
|
4796
4810
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4797
4811
|
const _headers = mergeHeaders(
|
|
4798
4812
|
_authRequest.headers,
|
|
@@ -4807,7 +4821,7 @@ var DocumentsClient = class {
|
|
|
4807
4821
|
method: "PUT",
|
|
4808
4822
|
headers: _headers,
|
|
4809
4823
|
contentType: "application/json",
|
|
4810
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4824
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
4811
4825
|
requestType: "json",
|
|
4812
4826
|
body: _body,
|
|
4813
4827
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -7543,7 +7557,7 @@ var RecordsClient = class {
|
|
|
7543
7557
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/records/batch");
|
|
7544
7558
|
}
|
|
7545
7559
|
/**
|
|
7546
|
-
* Returns a paginated list of records in your account as a `{data, nextCursor}` page. Supply exactly one of `type`, `folderId`, or `recent=true` to choose the mode: `type` lists all records of a single type; `folderId` lists all records in a folder (any type); and `recent=true` returns the account-wide recently-updated feed across all types, newest first. You may combine `type` with `folderId` to list a single type within a folder. The owner filters (`userId`, `orgId`, `clientId`) further narrow the type and folder modes; the `recent` feed is standalone and ignores all filters. Each token only sees the record types it is scoped to read. Requires the `records:r` scope. By default the response returns the indexed projection of each record; set `includePayload=true` to include full payloads.
|
|
7560
|
+
* Returns a paginated list of records in your account as a `{data, nextCursor}` page. Supply exactly one of `type`, `folderId`, or `recent=true` to choose the mode: `type` lists all records of a single type; `folderId` lists all records in a folder (any type); and `recent=true` returns the account-wide recently-updated feed across all types, newest first. You may combine `type` with `folderId` to list a single type within a folder. The owner filters (`userId`, `orgId`, `clientId`, `scope`) further narrow the type and folder modes; the `recent` feed is standalone and ignores all filters. Each token only sees the record types it is scoped to read. Requires the `records:r` scope. By default the response returns the indexed projection of each record; set `includePayload=true` to include full payloads.
|
|
7547
7561
|
*
|
|
7548
7562
|
* @param {Vectros.ListRecordsRequest} request
|
|
7549
7563
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -7555,6 +7569,7 @@ var RecordsClient = class {
|
|
|
7555
7569
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
7556
7570
|
* orgId: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
7557
7571
|
* clientId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
7572
|
+
* scope: "group:eng-team",
|
|
7558
7573
|
* startFrom: "550e8400-e29b-41d4-a716-446655440000"
|
|
7559
7574
|
* })
|
|
7560
7575
|
*/
|
|
@@ -7562,13 +7577,25 @@ var RecordsClient = class {
|
|
|
7562
7577
|
return HttpResponsePromise.fromPromise(this.__listRecords(request, requestOptions));
|
|
7563
7578
|
}
|
|
7564
7579
|
async __listRecords(request = {}, requestOptions) {
|
|
7565
|
-
const {
|
|
7580
|
+
const {
|
|
7581
|
+
type: type_,
|
|
7582
|
+
folderId,
|
|
7583
|
+
userId,
|
|
7584
|
+
orgId,
|
|
7585
|
+
clientId,
|
|
7586
|
+
scope,
|
|
7587
|
+
startFrom,
|
|
7588
|
+
limit,
|
|
7589
|
+
includePayload,
|
|
7590
|
+
recent
|
|
7591
|
+
} = request;
|
|
7566
7592
|
const _queryParams = {
|
|
7567
7593
|
type: type_,
|
|
7568
7594
|
folderId,
|
|
7569
7595
|
userId,
|
|
7570
7596
|
orgId,
|
|
7571
7597
|
clientId,
|
|
7598
|
+
scope,
|
|
7572
7599
|
startFrom,
|
|
7573
7600
|
limit,
|
|
7574
7601
|
includePayload,
|
|
@@ -7633,9 +7660,10 @@ var RecordsClient = class {
|
|
|
7633
7660
|
return HttpResponsePromise.fromPromise(this.__createRecord(request, requestOptions));
|
|
7634
7661
|
}
|
|
7635
7662
|
async __createRecord(request, requestOptions) {
|
|
7636
|
-
const { upsert, body: _body } = request;
|
|
7663
|
+
const { upsert, allowClear, body: _body } = request;
|
|
7637
7664
|
const _queryParams = {
|
|
7638
|
-
upsert
|
|
7665
|
+
upsert,
|
|
7666
|
+
allowClear
|
|
7639
7667
|
};
|
|
7640
7668
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
7641
7669
|
const _headers = mergeHeaders(
|
|
@@ -7757,7 +7785,10 @@ var RecordsClient = class {
|
|
|
7757
7785
|
return HttpResponsePromise.fromPromise(this.__updateRecord(request, requestOptions));
|
|
7758
7786
|
}
|
|
7759
7787
|
async __updateRecord(request, requestOptions) {
|
|
7760
|
-
const { id, body: _body } = request;
|
|
7788
|
+
const { id, allowClear, body: _body } = request;
|
|
7789
|
+
const _queryParams = {
|
|
7790
|
+
allowClear
|
|
7791
|
+
};
|
|
7761
7792
|
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
7762
7793
|
const _headers = mergeHeaders(
|
|
7763
7794
|
_authRequest.headers,
|
|
@@ -7772,7 +7803,7 @@ var RecordsClient = class {
|
|
|
7772
7803
|
method: "PUT",
|
|
7773
7804
|
headers: _headers,
|
|
7774
7805
|
contentType: "application/json",
|
|
7775
|
-
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
7806
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
7776
7807
|
requestType: "json",
|
|
7777
7808
|
body: _body,
|
|
7778
7809
|
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
@@ -8764,8 +8795,8 @@ function warnOnSuboptimalKey(key, log) {
|
|
|
8764
8795
|
|
|
8765
8796
|
// src/build-info.ts
|
|
8766
8797
|
var BUILD_INFO = {
|
|
8767
|
-
mcpServer: true ? "0.
|
|
8768
|
-
sdk: true ? "0.
|
|
8798
|
+
mcpServer: true ? "0.9.0" : "dev",
|
|
8799
|
+
sdk: true ? "0.34.0" : "dev"
|
|
8769
8800
|
};
|
|
8770
8801
|
function formatBuildInfo() {
|
|
8771
8802
|
return `vectros-mcp-server ${BUILD_INFO.mcpServer} (sdk ${BUILD_INFO.sdk})`;
|
|
@@ -9004,7 +9035,7 @@ ${detail}${pointer}`
|
|
|
9004
9035
|
|
|
9005
9036
|
// src/tools/hybrid_search.ts
|
|
9006
9037
|
var MCP_DEFAULT_LIMIT = 3;
|
|
9007
|
-
var MCP_MAX_LIMIT =
|
|
9038
|
+
var MCP_MAX_LIMIT = 50;
|
|
9008
9039
|
var MCP_RESPONSE_CHAR_BUDGET = 24e3;
|
|
9009
9040
|
var SNIPPET_MAX_CHARS = 160;
|
|
9010
9041
|
var INTERNAL_METADATA_KEYS = /* @__PURE__ */ new Set(["tenantId", "owner_id", "model_type", "rootFolderId", "folderId"]);
|
|
@@ -9038,9 +9069,9 @@ var inputSchema = {
|
|
|
9038
9069
|
"Keyword-match precision for the BM25 leg (TEXT/HYBRID modes). OR = any term (broad recall), AND = all terms (higher precision), PHRASE = contiguous phrase. Default: PHRASE (slop 3) in HYBRID, OR in TEXT. (The advanced raw-query COMPLEX mode is intentionally not exposed here.)"
|
|
9039
9070
|
),
|
|
9040
9071
|
limit: z.number().int().min(1).max(MCP_MAX_LIMIT).optional().describe(
|
|
9041
|
-
`Max hits
|
|
9072
|
+
`Max hits per page. Defaults to a low ${MCP_DEFAULT_LIMIT} to protect the agent context window; raise up to ${MCP_MAX_LIMIT} (the most a single search returns) in one call when you can accept the larger result, or page with \`offset\` instead.`
|
|
9042
9073
|
),
|
|
9043
|
-
offset: z.number().int().min(0).optional().describe("Skip the first N hits \u2014 for pagination."),
|
|
9074
|
+
offset: z.number().int().min(0).max(200).optional().describe("Skip the first N hits \u2014 for pagination (0\u2013200)."),
|
|
9044
9075
|
folderId: z.string().optional().describe("Scope to content in this EXACT folder (Vectros folder id)."),
|
|
9045
9076
|
rootFolderId: z.string().optional().describe("Scope to content under this folder AND all its descendants (subtree-root folder id)."),
|
|
9046
9077
|
// Content narrowing.
|
|
@@ -9055,6 +9086,9 @@ var inputSchema = {
|
|
|
9055
9086
|
userId: z.string().optional().describe("Restrict to content owned by this user (Vectros UUID)."),
|
|
9056
9087
|
orgId: z.string().optional().describe("Restrict to content belonging to this org (Vectros UUID)."),
|
|
9057
9088
|
clientId: z.string().optional().describe("Restrict to content associated with this client (Vectros UUID)."),
|
|
9089
|
+
scope: z.string().optional().describe(
|
|
9090
|
+
'Restrict to content carrying this scope value, in `namespace:value` form (e.g. "org:<uuid>", "group:eng-team"). `scope=org:<id>`/`scope=client:<id>` are equivalent to the orgId/clientId filters.'
|
|
9091
|
+
),
|
|
9058
9092
|
// Date window.
|
|
9059
9093
|
createdAfter: z.string().optional().describe("Restrict to content created at/after this ISO 8601 UTC timestamp."),
|
|
9060
9094
|
createdBefore: z.string().optional().describe("Restrict to content created at/before this ISO 8601 UTC timestamp."),
|
|
@@ -9072,7 +9106,7 @@ var inputSchema = {
|
|
|
9072
9106
|
var hybridSearch = ({ client, log }) => ({
|
|
9073
9107
|
name: "hybrid_search",
|
|
9074
9108
|
title: "Hybrid search",
|
|
9075
|
-
description:
|
|
9109
|
+
description: "Search your tenant's indexed content (documents + structured records) using hybrid BM25 + dense ranking. Returns up to `limit` results (default 3, max 50 \u2014 raise it in one call when you can accept the larger result) 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). totalResults is the full matching pool and hasMore:true means results remain past this page \u2014 raise limit or advance offset to fetch them. textLegEmpty:true flags that the keyword leg matched nothing (all textScores 0) \u2014 usually a too-long PHRASE query; retry with textMode:\"OR\".",
|
|
9076
9110
|
inputSchema,
|
|
9077
9111
|
handler: async (args) => {
|
|
9078
9112
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT;
|
|
@@ -9092,6 +9126,7 @@ var hybridSearch = ({ client, log }) => ({
|
|
|
9092
9126
|
userId: args.userId,
|
|
9093
9127
|
orgId: args.orgId,
|
|
9094
9128
|
clientId: args.clientId,
|
|
9129
|
+
scope: args.scope,
|
|
9095
9130
|
createdAfter: args.createdAfter,
|
|
9096
9131
|
createdBefore: args.createdBefore,
|
|
9097
9132
|
minSimilarity: args.minSimilarity,
|
|
@@ -9118,6 +9153,12 @@ var hybridSearch = ({ client, log }) => ({
|
|
|
9118
9153
|
envelope.returnedResults = shaped.length;
|
|
9119
9154
|
text = JSON.stringify(envelope, null, 2);
|
|
9120
9155
|
}
|
|
9156
|
+
const offset = args.offset ?? 0;
|
|
9157
|
+
const totalResults = result.totalResults;
|
|
9158
|
+
if (typeof totalResults === "number" && offset + shaped.length < totalResults) {
|
|
9159
|
+
envelope.hasMore = true;
|
|
9160
|
+
text = JSON.stringify(envelope, null, 2);
|
|
9161
|
+
}
|
|
9121
9162
|
log.debug(
|
|
9122
9163
|
{ tool: "hybrid_search", mode, limit, returned: shaped.length, textLegEmpty },
|
|
9123
9164
|
"hybrid_search ok"
|
|
@@ -9153,7 +9194,7 @@ async function drainPages(fetchPage) {
|
|
|
9153
9194
|
|
|
9154
9195
|
// src/tools/record_query.ts
|
|
9155
9196
|
var MCP_DEFAULT_LIMIT2 = 3;
|
|
9156
|
-
var MCP_MAX_LIMIT2 =
|
|
9197
|
+
var MCP_MAX_LIMIT2 = 100;
|
|
9157
9198
|
var inputSchema2 = {
|
|
9158
9199
|
type: z2.string().min(1, "type (record type) is required").describe('Record type / schema name (e.g. "patient", "clinical_note").'),
|
|
9159
9200
|
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | from+to | prefix.
|
|
@@ -9171,14 +9212,18 @@ var inputSchema2 = {
|
|
|
9171
9212
|
userId: z2.string().optional().describe("List mode: scope to records owned by this user."),
|
|
9172
9213
|
orgId: z2.string().optional().describe("List mode: scope to records owned by this org."),
|
|
9173
9214
|
clientId: z2.string().optional().describe("List mode: scope to records associated with this client."),
|
|
9215
|
+
scope: z2.string().optional().describe(
|
|
9216
|
+
'List mode: filter to records carrying this scope value, in `namespace:value` form (e.g. "org:<uuid>", "group:eng-team"). `scope=org:<id>`/`scope=client:<id>` are equivalent to the orgId/clientId filters.'
|
|
9217
|
+
),
|
|
9218
|
+
startFrom: z2.string().optional().describe("Pagination cursor \u2014 pass the `nextCursor` from the previous page to fetch the next. Works in both list and lookup mode."),
|
|
9174
9219
|
limit: z2.number().int().min(1).max(MCP_MAX_LIMIT2).optional().describe(
|
|
9175
|
-
`Max records
|
|
9220
|
+
`Max records per page. Defaults to a low ${MCP_DEFAULT_LIMIT2} to protect the agent context window; raise up to ${MCP_MAX_LIMIT2} (the records API max) in one call when you can accept the larger payload, or page with \`startFrom\` instead.`
|
|
9176
9221
|
)
|
|
9177
9222
|
};
|
|
9178
9223
|
var recordQuery = ({ client, log }) => ({
|
|
9179
9224
|
name: "record_query",
|
|
9180
9225
|
title: "Record query (list or lookup)",
|
|
9181
|
-
description: "Query structured records of a given type. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Works on sensitive fields too.\n \u2022 List by type: omit `field`; optionally filter by `userId`/`orgId`/`clientId`.\nReturns up to
|
|
9226
|
+
description: "Query structured records of a given type. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Works on sensitive fields too.\n \u2022 List by type: omit `field`; optionally filter by `userId`/`orgId`/`clientId`.\nReturns a `{ data, nextCursor }` page: `data` holds up to `limit` records (default 3, max 100 \u2014 raise it in one call when you can accept the payload), and a non-null `nextCursor` means more remain \u2014 pass it back as `startFrom` to page. Mode is auto-detected from the arguments present.",
|
|
9182
9227
|
inputSchema: inputSchema2,
|
|
9183
9228
|
handler: async (args) => {
|
|
9184
9229
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT2;
|
|
@@ -9188,8 +9233,9 @@ var recordQuery = ({ client, log }) => ({
|
|
|
9188
9233
|
const from = args.from;
|
|
9189
9234
|
const to = args.to;
|
|
9190
9235
|
const prefix = args.prefix;
|
|
9236
|
+
const startFrom = args.startFrom;
|
|
9191
9237
|
try {
|
|
9192
|
-
let
|
|
9238
|
+
let page;
|
|
9193
9239
|
if (field) {
|
|
9194
9240
|
const hasEquality = value !== void 0;
|
|
9195
9241
|
const hasRange = from !== void 0 || to !== void 0;
|
|
@@ -9212,7 +9258,7 @@ var recordQuery = ({ client, log }) => ({
|
|
|
9212
9258
|
if (hasRange && !(from !== void 0 && to !== void 0)) {
|
|
9213
9259
|
return toolError("record_query", new Error("range lookup requires both 'from' and 'to'."));
|
|
9214
9260
|
}
|
|
9215
|
-
|
|
9261
|
+
page = await client.records.lookupRecordsByBody({
|
|
9216
9262
|
type,
|
|
9217
9263
|
field,
|
|
9218
9264
|
value,
|
|
@@ -9220,29 +9266,32 @@ var recordQuery = ({ client, log }) => ({
|
|
|
9220
9266
|
to,
|
|
9221
9267
|
prefix,
|
|
9222
9268
|
order: args.order,
|
|
9269
|
+
startFrom,
|
|
9223
9270
|
limit
|
|
9224
9271
|
});
|
|
9225
|
-
records = pageItems(page);
|
|
9226
9272
|
log.debug(
|
|
9227
|
-
{ tool: "record_query", mode: "lookup", type, field, returned:
|
|
9273
|
+
{ tool: "record_query", mode: "lookup", type, field, returned: pageItems(page).length },
|
|
9228
9274
|
"record_query lookup ok"
|
|
9229
9275
|
);
|
|
9230
9276
|
} else {
|
|
9231
|
-
|
|
9277
|
+
page = await client.records.listRecords({
|
|
9232
9278
|
type,
|
|
9233
9279
|
userId: args.userId,
|
|
9234
9280
|
orgId: args.orgId,
|
|
9235
9281
|
clientId: args.clientId,
|
|
9282
|
+
scope: args.scope,
|
|
9283
|
+
startFrom,
|
|
9236
9284
|
limit
|
|
9237
9285
|
});
|
|
9238
|
-
records = pageItems(page);
|
|
9239
9286
|
log.debug(
|
|
9240
|
-
{ tool: "record_query", mode: "list", type, limit, returned:
|
|
9287
|
+
{ tool: "record_query", mode: "list", type, limit, returned: pageItems(page).length },
|
|
9241
9288
|
"record_query list ok"
|
|
9242
9289
|
);
|
|
9243
9290
|
}
|
|
9291
|
+
const records = pageItems(page);
|
|
9292
|
+
const nextCursor = page.nextCursor ?? null;
|
|
9244
9293
|
return {
|
|
9245
|
-
content: [{ type: "text", text: JSON.stringify(records, null, 2) }]
|
|
9294
|
+
content: [{ type: "text", text: JSON.stringify({ data: records, nextCursor }, null, 2) }]
|
|
9246
9295
|
};
|
|
9247
9296
|
} catch (err) {
|
|
9248
9297
|
log.warn({ tool: "record_query", err: String(err) }, "record_query failed");
|
|
@@ -9365,7 +9414,10 @@ var inputSchema4 = {
|
|
|
9365
9414
|
folderId: z4.string().optional().describe("Group this record into a folder."),
|
|
9366
9415
|
userId: z4.string().optional().describe("Owning user id."),
|
|
9367
9416
|
orgId: z4.string().optional().describe("Owning organization id."),
|
|
9368
|
-
clientId: z4.string().optional().describe("Associated client id.")
|
|
9417
|
+
clientId: z4.string().optional().describe("Associated client id."),
|
|
9418
|
+
scopes: z4.array(z4.string()).optional().describe(
|
|
9419
|
+
'Scope ownership as `namespace:value` entries, at most 2 (e.g. ["org:<uuid>", "group:eng-team"]). This is the record\'s COMPLETE scope declaration and values must come from the credential\'s own identity. An empty array `[]` creates a PRIVATE record owned by the calling user alone. Omit to stamp the credential\'s full identity \u2014 the default. `org:`/`client:` entries are equivalent to the orgId/clientId fields.'
|
|
9420
|
+
)
|
|
9369
9421
|
};
|
|
9370
9422
|
var recordCreate = ({ client, log }) => ({
|
|
9371
9423
|
name: "record_create",
|
|
@@ -9385,7 +9437,8 @@ var recordCreate = ({ client, log }) => ({
|
|
|
9385
9437
|
folderId: args.folderId,
|
|
9386
9438
|
userId: args.userId,
|
|
9387
9439
|
orgId: args.orgId,
|
|
9388
|
-
clientId: args.clientId
|
|
9440
|
+
clientId: args.clientId,
|
|
9441
|
+
scopes: args.scopes
|
|
9389
9442
|
}
|
|
9390
9443
|
});
|
|
9391
9444
|
log.debug({ tool: "record_create", type, id: created.id }, "record_create ok");
|
|
@@ -9470,24 +9523,29 @@ var record_delete_default = recordDelete;
|
|
|
9470
9523
|
// src/tools/rag_ask.ts
|
|
9471
9524
|
import { z as z7 } from "zod";
|
|
9472
9525
|
var SEARCH_MCP_DEFAULT_LIMIT = 5;
|
|
9473
|
-
var SEARCH_MCP_MAX_LIMIT =
|
|
9526
|
+
var SEARCH_MCP_MAX_LIMIT = 50;
|
|
9474
9527
|
var inputSchema7 = {
|
|
9475
9528
|
query: z7.string().min(1, "query must be non-empty").describe("Question to ground against retrieved content."),
|
|
9476
9529
|
instructions: z7.string().optional().describe(
|
|
9477
9530
|
'System prompt that overrides the default for the generation step \u2014 e.g. "answer only from the provided context, cite sources, be concise". Default: a generic answer-from-context instruction.'
|
|
9478
9531
|
),
|
|
9479
9532
|
model: z7.string().optional().describe(
|
|
9480
|
-
"Inference model alias (e.g. claude-haiku-4-5, claude-sonnet-
|
|
9533
|
+
"Inference model alias (e.g. claude-haiku-4-5, claude-sonnet-5, claude-opus-4-8). Default = tier-appropriate Haiku. See GET /v1/models for the catalog the calling key can reach."
|
|
9481
9534
|
),
|
|
9482
9535
|
search: z7.object({
|
|
9483
9536
|
mode: z7.enum(["HYBRID", "TEXT", "SEMANTIC"]).optional().describe("Retrieval mode. Default HYBRID."),
|
|
9484
|
-
limit: z7.number().int().min(1).max(SEARCH_MCP_MAX_LIMIT).optional().describe(
|
|
9537
|
+
limit: z7.number().int().min(1).max(SEARCH_MCP_MAX_LIMIT).optional().describe(
|
|
9538
|
+
`Passages to retrieve before generating (the grounding-corpus size). Default ${SEARCH_MCP_DEFAULT_LIMIT}; raise up to ${SEARCH_MCP_MAX_LIMIT} (the RAG search API max) for a broader corpus when the extra grounding is worth the larger prompt.`
|
|
9539
|
+
),
|
|
9485
9540
|
// Retrieval scoping — parity with hybrid_search so an agent can ground the
|
|
9486
9541
|
// answer on a specific owner / folder / type / metadata subset, not just the
|
|
9487
9542
|
// whole-tenant corpus.
|
|
9488
9543
|
userId: z7.string().optional().describe("Restrict retrieval to content owned by this user (Vectros UUID)."),
|
|
9489
9544
|
orgId: z7.string().optional().describe("Restrict retrieval to content owned by this org (Vectros UUID)."),
|
|
9490
9545
|
clientId: z7.string().optional().describe("Restrict retrieval to content tagged with this client (Vectros UUID)."),
|
|
9546
|
+
scope: z7.string().optional().describe(
|
|
9547
|
+
'Restrict retrieval to content carrying this scope value, in `namespace:value` form (e.g. "org:<uuid>", "group:eng-team"). `scope=org:<id>`/`scope=client:<id>` are equivalent to the orgId/clientId filters.'
|
|
9548
|
+
),
|
|
9491
9549
|
folderId: z7.string().optional().describe("Restrict retrieval to this exact folder."),
|
|
9492
9550
|
rootFolderId: z7.string().optional().describe("Restrict retrieval to this folder and all its descendants."),
|
|
9493
9551
|
typeName: z7.string().optional().describe("Restrict record retrieval to this schema type."),
|
|
@@ -9505,7 +9563,7 @@ var inputSchema7 = {
|
|
|
9505
9563
|
var ragAsk = ({ client, log }) => ({
|
|
9506
9564
|
name: "rag_ask",
|
|
9507
9565
|
title: "RAG ask (corpus-wide)",
|
|
9508
|
-
description: "Ask a question grounded against
|
|
9566
|
+
description: "Ask a question grounded against your tenant's indexed content. Vectros performs a hybrid search, injects the top-K passages into the prompt, and streams a model answer back. Scope retrieval with `search` (ownership, folder, type, metadata filters, date window) to ground on a subset \u2014 e.g. one patient or one folder \u2014 and steer generation with `instructions` / `temperature`. The full answer is returned as a single response; progress notifications keep the call alive during the 30-45s generation window. Inference runs in-perimeter against AWS Bedrock \u2014 PHI never leaves the BAA boundary.",
|
|
9509
9567
|
inputSchema: inputSchema7,
|
|
9510
9568
|
handler: async (args, extra) => {
|
|
9511
9569
|
try {
|
|
@@ -9516,6 +9574,7 @@ var ragAsk = ({ client, log }) => ({
|
|
|
9516
9574
|
userId: searchArg.userId,
|
|
9517
9575
|
orgId: searchArg.orgId,
|
|
9518
9576
|
clientId: searchArg.clientId,
|
|
9577
|
+
scope: searchArg.scope,
|
|
9519
9578
|
folderId: searchArg.folderId,
|
|
9520
9579
|
rootFolderId: searchArg.rootFolderId,
|
|
9521
9580
|
typeName: searchArg.typeName,
|
|
@@ -9673,7 +9732,7 @@ var inputSchema9 = {
|
|
|
9673
9732
|
var listSchemas = ({ client, log }) => ({
|
|
9674
9733
|
name: "list_schemas",
|
|
9675
9734
|
title: "List record schemas",
|
|
9676
|
-
description: 'List the structured-record schema catalog for
|
|
9735
|
+
description: 'List the structured-record schema catalog for your tenant. Each schema describes a record type (e.g. "patient", "clinical_note") \u2014 its fields, lookup-indexed fields, and capabilities. Use this to discover what record types exist before calling `record_query`. Filter with `surface` (record/document/user/org/client \u2014 e.g. only document types), `recordType` (resolve one schema by its type name), or `userId`/`orgId`; default returns everything the credential can see.',
|
|
9677
9736
|
inputSchema: inputSchema9,
|
|
9678
9737
|
handler: async (args) => {
|
|
9679
9738
|
const userId = args.userId;
|
|
@@ -9795,7 +9854,7 @@ var document_get_default = documentGet;
|
|
|
9795
9854
|
// src/tools/document_query.ts
|
|
9796
9855
|
import { z as z11 } from "zod";
|
|
9797
9856
|
var MCP_DEFAULT_LIMIT3 = 3;
|
|
9798
|
-
var MCP_MAX_LIMIT3 =
|
|
9857
|
+
var MCP_MAX_LIMIT3 = 100;
|
|
9799
9858
|
var inputSchema11 = {
|
|
9800
9859
|
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | from+to | prefix.
|
|
9801
9860
|
field: z11.string().optional().describe("Lookup mode: name of the lookup-indexed field to query by."),
|
|
@@ -9812,14 +9871,18 @@ var inputSchema11 = {
|
|
|
9812
9871
|
userId: z11.string().optional().describe("List mode: scope to documents owned by this user."),
|
|
9813
9872
|
orgId: z11.string().optional().describe("List mode: scope to documents belonging to this org."),
|
|
9814
9873
|
clientId: z11.string().optional().describe("List mode: scope to documents associated with this client."),
|
|
9874
|
+
scope: z11.string().optional().describe(
|
|
9875
|
+
'List mode: filter to documents carrying this scope value, in `namespace:value` form (e.g. "org:<uuid>", "group:eng-team"). `scope=org:<id>`/`scope=client:<id>` are equivalent to the orgId/clientId filters.'
|
|
9876
|
+
),
|
|
9877
|
+
startFrom: z11.string().optional().describe("Pagination cursor \u2014 pass the `nextCursor` from the previous page to fetch the next. Works in both list and lookup mode."),
|
|
9815
9878
|
limit: z11.number().int().min(1).max(MCP_MAX_LIMIT3).optional().describe(
|
|
9816
|
-
`Max documents
|
|
9879
|
+
`Max documents per page. Defaults to a low ${MCP_DEFAULT_LIMIT3} to protect the agent context window; raise up to ${MCP_MAX_LIMIT3} (the documents API max) in one call when you can accept the larger payload, or page with \`startFrom\` instead.`
|
|
9817
9880
|
)
|
|
9818
9881
|
};
|
|
9819
9882
|
var documentQuery = ({ client, log }) => ({
|
|
9820
9883
|
name: "document_query",
|
|
9821
9884
|
title: "Document query (list or lookup)",
|
|
9822
|
-
description: "Query document metadata. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `type` and `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Works on sensitive fields (equality only there); range/prefix need a range-enabled field.\n \u2022 List: omit `field`; optionally filter by `folderId`/`userId`/`orgId`/`clientId`.\nReturns up to
|
|
9885
|
+
description: "Query document metadata. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `type` and `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Works on sensitive fields (equality only there); range/prefix need a range-enabled field.\n \u2022 List: omit `field`; optionally filter by `folderId`/`userId`/`orgId`/`clientId`/`scope`.\nReturns a `{ data, nextCursor }` page: `data` holds up to `limit` documents (default 3, max 100 \u2014 raise it in one call when you can accept the payload), and a non-null `nextCursor` means more remain \u2014 pass it back as `startFrom` to page. Mode is auto-detected. Use document_get for the full text/download URL of one document.",
|
|
9823
9886
|
inputSchema: inputSchema11,
|
|
9824
9887
|
handler: async (args) => {
|
|
9825
9888
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT3;
|
|
@@ -9829,8 +9892,9 @@ var documentQuery = ({ client, log }) => ({
|
|
|
9829
9892
|
const to = args.to;
|
|
9830
9893
|
const prefix = args.prefix;
|
|
9831
9894
|
const type = args.type;
|
|
9895
|
+
const startFrom = args.startFrom;
|
|
9832
9896
|
try {
|
|
9833
|
-
let
|
|
9897
|
+
let page;
|
|
9834
9898
|
if (field) {
|
|
9835
9899
|
const hasEquality = value !== void 0;
|
|
9836
9900
|
const hasRange = from !== void 0 || to !== void 0;
|
|
@@ -9859,7 +9923,7 @@ var documentQuery = ({ client, log }) => ({
|
|
|
9859
9923
|
new Error("lookup requires 'type' (the document's bound schema type) alongside 'field'.")
|
|
9860
9924
|
);
|
|
9861
9925
|
}
|
|
9862
|
-
|
|
9926
|
+
page = await client.documents.lookupDocumentsByBody({
|
|
9863
9927
|
type,
|
|
9864
9928
|
field,
|
|
9865
9929
|
value,
|
|
@@ -9867,28 +9931,31 @@ var documentQuery = ({ client, log }) => ({
|
|
|
9867
9931
|
to,
|
|
9868
9932
|
prefix,
|
|
9869
9933
|
order: args.order,
|
|
9934
|
+
startFrom,
|
|
9870
9935
|
limit
|
|
9871
9936
|
});
|
|
9872
|
-
documents = pageItems(page);
|
|
9873
9937
|
log.debug(
|
|
9874
|
-
{ tool: "document_query", mode: "lookup", type, field, returned:
|
|
9938
|
+
{ tool: "document_query", mode: "lookup", type, field, returned: pageItems(page).length },
|
|
9875
9939
|
"document_query lookup ok"
|
|
9876
9940
|
);
|
|
9877
9941
|
} else {
|
|
9878
|
-
|
|
9942
|
+
page = await client.documents.listDocuments({
|
|
9879
9943
|
folderId: args.folderId,
|
|
9880
9944
|
userId: args.userId,
|
|
9881
9945
|
orgId: args.orgId,
|
|
9882
9946
|
clientId: args.clientId,
|
|
9947
|
+
scope: args.scope,
|
|
9948
|
+
startFrom,
|
|
9883
9949
|
limit
|
|
9884
9950
|
});
|
|
9885
|
-
documents = pageItems(page);
|
|
9886
9951
|
log.debug(
|
|
9887
|
-
{ tool: "document_query", mode: "list", limit, returned:
|
|
9952
|
+
{ tool: "document_query", mode: "list", limit, returned: pageItems(page).length },
|
|
9888
9953
|
"document_query list ok"
|
|
9889
9954
|
);
|
|
9890
9955
|
}
|
|
9891
|
-
|
|
9956
|
+
const documents = pageItems(page);
|
|
9957
|
+
const nextCursor = page.nextCursor ?? null;
|
|
9958
|
+
return { content: [{ type: "text", text: JSON.stringify({ data: documents, nextCursor }, null, 2) }] };
|
|
9892
9959
|
} catch (err) {
|
|
9893
9960
|
log.warn({ tool: "document_query", err: String(err) }, "document_query failed");
|
|
9894
9961
|
return toolError("document_query", err);
|
|
@@ -9997,7 +10064,7 @@ var document_delete_default = documentDelete;
|
|
|
9997
10064
|
// src/tools/folder_query.ts
|
|
9998
10065
|
import { z as z14 } from "zod";
|
|
9999
10066
|
var MCP_DEFAULT_LIMIT4 = 10;
|
|
10000
|
-
var MCP_MAX_LIMIT4 =
|
|
10067
|
+
var MCP_MAX_LIMIT4 = 100;
|
|
10001
10068
|
var inputSchema14 = {
|
|
10002
10069
|
id: z14.string().optional().describe("Get mode: fetch this single folder by id."),
|
|
10003
10070
|
parentId: z14.string().optional().describe("List mode: direct children of this folder (tree navigation). Omit for a flat tenant list."),
|
|
@@ -10005,12 +10072,14 @@ var inputSchema14 = {
|
|
|
10005
10072
|
orgId: z14.string().optional().describe("List mode: scope to folders belonging to this org."),
|
|
10006
10073
|
clientId: z14.string().optional().describe("List mode: scope to folders associated with this client."),
|
|
10007
10074
|
startFrom: z14.string().optional().describe("List mode: pagination cursor \u2014 pass the `nextCursor` from the previous page to fetch the next."),
|
|
10008
|
-
limit: z14.number().int().min(1).max(MCP_MAX_LIMIT4).optional().describe(
|
|
10075
|
+
limit: z14.number().int().min(1).max(MCP_MAX_LIMIT4).optional().describe(
|
|
10076
|
+
`List mode: max folders per page. Default 10; raise up to ${MCP_MAX_LIMIT4} (the folders API max) in one call when you can accept the larger page, or page with \`startFrom\`.`
|
|
10077
|
+
)
|
|
10009
10078
|
};
|
|
10010
10079
|
var folderQuery = ({ client, log }) => ({
|
|
10011
10080
|
name: "folder_query",
|
|
10012
10081
|
title: "Folder query (list or get)",
|
|
10013
|
-
description: "Read folders. Two modes:\n \u2022 Get: pass `id` \u2192 returns the single folder.\n \u2022 List: omit `id`; pass `parentId` for a folder's direct children (tree navigation) or omit for a flat tenant list. Optionally filter by `userId`/`orgId`/`clientId`.\nList mode returns `{ data, nextCursor }` (default 10, max
|
|
10082
|
+
description: "Read folders. Two modes:\n \u2022 Get: pass `id` \u2192 returns the single folder.\n \u2022 List: omit `id`; pass `parentId` for a folder's direct children (tree navigation) or omit for a flat tenant list. Optionally filter by `userId`/`orgId`/`clientId`.\nList mode returns `{ data, nextCursor }` (default 10, max 100 per page \u2014 raise it in one call when you can accept the larger page); a non-null `nextCursor` means more remain \u2014 pass it back as `startFrom` to page through all folders. Get mode returns the single folder object.",
|
|
10014
10083
|
inputSchema: inputSchema14,
|
|
10015
10084
|
handler: async (args) => {
|
|
10016
10085
|
const id = args.id;
|
|
@@ -10050,7 +10119,10 @@ var inputSchema15 = {
|
|
|
10050
10119
|
slug: z15.string().optional().describe("Optional stable slug (sibling-unique; idempotency key). Lowercase letters/digits/hyphens. Derived from name when omitted."),
|
|
10051
10120
|
userId: z15.string().optional().describe("Owning user (Vectros UUID)."),
|
|
10052
10121
|
orgId: z15.string().optional().describe("Owning org (Vectros UUID)."),
|
|
10053
|
-
clientId: z15.string().optional().describe("Associated client (Vectros UUID).")
|
|
10122
|
+
clientId: z15.string().optional().describe("Associated client (Vectros UUID)."),
|
|
10123
|
+
scopes: z15.array(z15.string()).optional().describe(
|
|
10124
|
+
'Scope ownership as `namespace:value` entries, at most 2 (e.g. ["org:<uuid>", "group:eng-team"]). This is the folder\'s COMPLETE scope declaration and values must come from the credential\'s own identity. An empty array `[]` creates a PRIVATE folder owned by the calling user alone. Omit to stamp the credential\'s full identity \u2014 the default. `org:`/`client:` entries are equivalent to the orgId/clientId fields.'
|
|
10125
|
+
)
|
|
10054
10126
|
};
|
|
10055
10127
|
var folderCreate = ({ client, log }) => ({
|
|
10056
10128
|
name: "folder_create",
|
|
@@ -10067,7 +10139,8 @@ var folderCreate = ({ client, log }) => ({
|
|
|
10067
10139
|
slug: args.slug,
|
|
10068
10140
|
userId: args.userId,
|
|
10069
10141
|
orgId: args.orgId,
|
|
10070
|
-
clientId: args.clientId
|
|
10142
|
+
clientId: args.clientId,
|
|
10143
|
+
scopes: args.scopes
|
|
10071
10144
|
}
|
|
10072
10145
|
});
|
|
10073
10146
|
log.debug({ tool: "folder_create", id: folder.id, name: folder.name }, "folder_create ok");
|
|
@@ -10279,7 +10352,10 @@ var inputSchema19 = {
|
|
|
10279
10352
|
folderId: z18.string().optional().describe("Optional folder to ingest into. Default: tenant root."),
|
|
10280
10353
|
userId: z18.string().optional().describe("Owning user ID. Optional."),
|
|
10281
10354
|
orgId: z18.string().optional().describe("Owning org ID. Optional."),
|
|
10282
|
-
clientId: z18.string().optional().describe("Owning client ID. Optional.")
|
|
10355
|
+
clientId: z18.string().optional().describe("Owning client ID. Optional."),
|
|
10356
|
+
scopes: z18.array(z18.string()).optional().describe(
|
|
10357
|
+
"TEXT MODE ONLY. Scope ownership as `namespace:value` entries, at most 2 (e.g. [\"org:<uuid>\", \"group:eng-team\"]). This is the document's COMPLETE scope declaration and values must come from the credential's own identity. An empty array `[]` creates a PRIVATE document owned by the calling user alone. Omit to stamp the credential's full identity \u2014 the default. `org:`/`client:` entries are equivalent to the orgId/clientId fields. Rejected with `filePath` (file uploads do not accept a scope declaration): a file-uploaded document is stamped with the credential's full identity."
|
|
10358
|
+
)
|
|
10283
10359
|
};
|
|
10284
10360
|
var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
10285
10361
|
name: "document_ingest",
|
|
@@ -10313,6 +10389,14 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10313
10389
|
)
|
|
10314
10390
|
);
|
|
10315
10391
|
}
|
|
10392
|
+
if (filePath && args.scopes !== void 0) {
|
|
10393
|
+
return toolError(
|
|
10394
|
+
"document_ingest",
|
|
10395
|
+
new Error(
|
|
10396
|
+
"`scopes` is not supported with `filePath` \u2014 file uploads do not accept a scope declaration, and silently ignoring it could make an intended-private document team-visible. Use `text` mode to declare scopes, or omit `scopes` (the upload is stamped with the credential's full identity)."
|
|
10397
|
+
)
|
|
10398
|
+
);
|
|
10399
|
+
}
|
|
10316
10400
|
const common = {
|
|
10317
10401
|
folderId: args.folderId,
|
|
10318
10402
|
payload: args.payload,
|
|
@@ -10330,6 +10414,9 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
|
|
|
10330
10414
|
title,
|
|
10331
10415
|
text,
|
|
10332
10416
|
indexMode,
|
|
10417
|
+
// Scope ownership is a TEXT-mode contract only (the upload-init
|
|
10418
|
+
// endpoint has no scopes field — see the gate above).
|
|
10419
|
+
scopes: args.scopes,
|
|
10333
10420
|
...common
|
|
10334
10421
|
}
|
|
10335
10422
|
});
|
|
@@ -10422,7 +10509,7 @@ var document_ingest_default = documentIngest;
|
|
|
10422
10509
|
// src/tools/lookup_principal.ts
|
|
10423
10510
|
import { z as z19 } from "zod";
|
|
10424
10511
|
var MCP_DEFAULT_LIMIT5 = 10;
|
|
10425
|
-
var MCP_MAX_LIMIT5 =
|
|
10512
|
+
var MCP_MAX_LIMIT5 = 100;
|
|
10426
10513
|
var inputSchema20 = {
|
|
10427
10514
|
kind: z19.enum(["user", "org", "client"]).describe("Which principal to look up: a user, an organization, or a client."),
|
|
10428
10515
|
externalId: z19.string().optional().describe(
|
|
@@ -10436,12 +10523,15 @@ var inputSchema20 = {
|
|
|
10436
10523
|
to: z19.string().optional().describe("Lookup mode (range): inclusive upper bound; requires `from`."),
|
|
10437
10524
|
prefix: z19.string().optional().describe("Lookup mode (prefix): match values starting with this. Range-enabled string fields only."),
|
|
10438
10525
|
order: z19.enum(["asc", "desc"]).optional().describe("Lookup mode: sort direction by the looked-up field. `asc` (default) or `desc`."),
|
|
10439
|
-
|
|
10526
|
+
startFrom: z19.string().optional().describe("Lookup mode: pagination cursor \u2014 pass the `nextCursor` from the previous page to fetch the next."),
|
|
10527
|
+
limit: z19.number().int().min(1).max(MCP_MAX_LIMIT5).optional().describe(
|
|
10528
|
+
`Max principals per page. Defaults to ${MCP_DEFAULT_LIMIT5}; raise up to ${MCP_MAX_LIMIT5} (the principals API max) in one call when you can accept the payload, or page with \`startFrom\`.`
|
|
10529
|
+
)
|
|
10440
10530
|
};
|
|
10441
10531
|
var lookupPrincipal = ({ client, log }) => ({
|
|
10442
10532
|
name: "lookup_principal",
|
|
10443
10533
|
title: "Look up a user / org / client identity",
|
|
10444
|
-
description: "Resolve a user, org, or client identity. Two modes:\n \u2022 Resolve by your own id: pass `externalId` \u2192 the matching principal incl. its Vectros UUID (the id the ownership filters on record_query / hybrid_search / rag_ask expect).\n \u2022 Lookup by a schema field: pass `type` and `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Sensitive-field-safe. (If both `externalId` and a `field` lookup are given, `externalId` wins.) Returns
|
|
10534
|
+
description: "Resolve a user, org, or client identity. Two modes:\n \u2022 Resolve by your own id: pass `externalId` \u2192 the matching principal incl. its Vectros UUID (the id the ownership filters on record_query / hybrid_search / rag_ask expect).\n \u2022 Lookup by a schema field: pass `type` and `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Sensitive-field-safe. (If both `externalId` and a `field` lookup are given, `externalId` wins.) Returns a `{ data, nextCursor }` page (default 10, max 100 \u2014 raise it in one call when you can accept the payload); a non-null `nextCursor` means more remain \u2014 pass it back as `startFrom`. Read-only \u2014 does not create or modify identities.",
|
|
10445
10535
|
inputSchema: inputSchema20,
|
|
10446
10536
|
handler: async (args) => {
|
|
10447
10537
|
const kind = args.kind;
|
|
@@ -10454,6 +10544,7 @@ var lookupPrincipal = ({ client, log }) => ({
|
|
|
10454
10544
|
const to = args.to;
|
|
10455
10545
|
const prefix = args.prefix;
|
|
10456
10546
|
const order = args.order;
|
|
10547
|
+
const startFrom = args.startFrom;
|
|
10457
10548
|
try {
|
|
10458
10549
|
let page;
|
|
10459
10550
|
if (externalId !== void 0) {
|
|
@@ -10491,7 +10582,7 @@ var lookupPrincipal = ({ client, log }) => ({
|
|
|
10491
10582
|
new Error("lookup requires 'type' (the identity schema's record type) alongside 'field'.")
|
|
10492
10583
|
);
|
|
10493
10584
|
}
|
|
10494
|
-
const req = { type, field, value, from, to, prefix, order, limit };
|
|
10585
|
+
const req = { type, field, value, from, to, prefix, order, startFrom, limit };
|
|
10495
10586
|
if (kind === "user") {
|
|
10496
10587
|
page = await client.identity.lookupUsers(req);
|
|
10497
10588
|
} else if (kind === "org") {
|
|
@@ -10507,7 +10598,8 @@ var lookupPrincipal = ({ client, log }) => ({
|
|
|
10507
10598
|
);
|
|
10508
10599
|
}
|
|
10509
10600
|
const principals = pageItems(page);
|
|
10510
|
-
|
|
10601
|
+
const nextCursor = page.nextCursor ?? null;
|
|
10602
|
+
return { content: [{ type: "text", text: JSON.stringify({ data: principals, nextCursor }, null, 2) }] };
|
|
10511
10603
|
} catch (err) {
|
|
10512
10604
|
log.warn({ tool: "lookup_principal", kind, err: String(err) }, "lookup_principal failed");
|
|
10513
10605
|
return toolError("lookup_principal", err);
|