portkey-admin-mcp 0.4.2 → 0.5.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/README.md +68 -28
- package/build/index.js +1212 -632
- package/build/server.js +1596 -682
- package/package.json +15 -12
package/build/server.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
|
|
6
6
|
// src/lib/http-app.ts
|
|
7
|
-
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
8
8
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
9
9
|
import {
|
|
10
10
|
createServer as createHttpServer
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
createServer as createHttpsServer
|
|
14
14
|
} from "node:https";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
StreamableHTTPServerTransport
|
|
17
|
+
} from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
16
18
|
import {
|
|
17
19
|
isInitializeRequest,
|
|
18
20
|
LATEST_PROTOCOL_VERSION,
|
|
@@ -212,11 +214,11 @@ var BaseService = class {
|
|
|
212
214
|
}
|
|
213
215
|
this.apiKey = apiKey;
|
|
214
216
|
if (baseUrlOverride !== void 0) {
|
|
215
|
-
this.baseUrl = baseUrlOverride;
|
|
217
|
+
this.baseUrl = baseUrlOverride.replace(/\/+$/, "");
|
|
216
218
|
} else {
|
|
217
219
|
const baseUrl = process.env.PORTKEY_BASE_URL ?? DEFAULT_BASE_URL;
|
|
218
220
|
validateUrl(baseUrl);
|
|
219
|
-
this.baseUrl = baseUrl;
|
|
221
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
220
222
|
}
|
|
221
223
|
}
|
|
222
224
|
encodePathSegment(value) {
|
|
@@ -781,6 +783,12 @@ var KeysService = class extends BaseService {
|
|
|
781
783
|
await this.put(`/api-keys/${this.encodePathSegment(id)}`, data);
|
|
782
784
|
return { success: true };
|
|
783
785
|
}
|
|
786
|
+
async rotateApiKey(id, data = {}) {
|
|
787
|
+
return this.post(
|
|
788
|
+
`/api-keys/${this.encodePathSegment(id)}/rotate`,
|
|
789
|
+
data
|
|
790
|
+
);
|
|
791
|
+
}
|
|
784
792
|
async deleteApiKey(id) {
|
|
785
793
|
await this.delete(`/api-keys/${this.encodePathSegment(id)}`);
|
|
786
794
|
return { success: true };
|
|
@@ -1490,6 +1498,31 @@ var ProvidersService = class extends BaseService {
|
|
|
1490
1498
|
}
|
|
1491
1499
|
};
|
|
1492
1500
|
|
|
1501
|
+
// src/services/secret-references.service.ts
|
|
1502
|
+
var SecretReferencesService = class extends BaseService {
|
|
1503
|
+
async createSecretReference(data) {
|
|
1504
|
+
return this.post("/secret-references", data);
|
|
1505
|
+
}
|
|
1506
|
+
async listSecretReferences(params) {
|
|
1507
|
+
return this.get("/secret-references", params);
|
|
1508
|
+
}
|
|
1509
|
+
async getSecretReference(id) {
|
|
1510
|
+
return this.get(
|
|
1511
|
+
`/secret-references/${this.encodePathSegment(id)}`
|
|
1512
|
+
);
|
|
1513
|
+
}
|
|
1514
|
+
async updateSecretReference(id, data) {
|
|
1515
|
+
return this.put(
|
|
1516
|
+
`/secret-references/${this.encodePathSegment(id)}`,
|
|
1517
|
+
data
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
async deleteSecretReference(id) {
|
|
1521
|
+
await this.delete(`/secret-references/${this.encodePathSegment(id)}`);
|
|
1522
|
+
return { success: true };
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
|
|
1493
1526
|
// src/services/tracing.service.ts
|
|
1494
1527
|
var TracingService = class extends BaseService {
|
|
1495
1528
|
// Feedback endpoints
|
|
@@ -1640,8 +1673,9 @@ var WorkspacesService = class extends BaseService {
|
|
|
1640
1673
|
};
|
|
1641
1674
|
|
|
1642
1675
|
// src/services/index.ts
|
|
1643
|
-
import
|
|
1676
|
+
import { createHmac, randomBytes } from "node:crypto";
|
|
1644
1677
|
var MISSING_API_KEY_PLACEHOLDER = "__PORTKEY_API_KEY_NOT_CONFIGURED__";
|
|
1678
|
+
var SERVICE_CACHE_HMAC_KEY = randomBytes(32);
|
|
1645
1679
|
function resolvePortkeyApiKey(apiKey) {
|
|
1646
1680
|
const resolvedApiKey = apiKey ?? process.env.PORTKEY_API_KEY;
|
|
1647
1681
|
if (!resolvedApiKey) {
|
|
@@ -1655,7 +1689,7 @@ function resolveSharedPortkeyApiKey(apiKey) {
|
|
|
1655
1689
|
return apiKey ?? process.env.PORTKEY_API_KEY ?? MISSING_API_KEY_PLACEHOLDER;
|
|
1656
1690
|
}
|
|
1657
1691
|
function getSharedServiceCacheKey(apiKey) {
|
|
1658
|
-
const keyDigest =
|
|
1692
|
+
const keyDigest = createHmac("sha256", SERVICE_CACHE_HMAC_KEY).update(apiKey).digest("hex");
|
|
1659
1693
|
return JSON.stringify({
|
|
1660
1694
|
apiKey: keyDigest,
|
|
1661
1695
|
baseUrl: process.env.PORTKEY_BASE_URL?.trim() || ""
|
|
@@ -1679,6 +1713,7 @@ var PortkeyService = class {
|
|
|
1679
1713
|
tracing;
|
|
1680
1714
|
logging;
|
|
1681
1715
|
providers;
|
|
1716
|
+
secretReferences;
|
|
1682
1717
|
mcpIntegrations;
|
|
1683
1718
|
mcpServers;
|
|
1684
1719
|
health;
|
|
@@ -1705,6 +1740,10 @@ var PortkeyService = class {
|
|
|
1705
1740
|
this.tracing = new TracingService(resolvedApiKey, resolvedBaseUrl);
|
|
1706
1741
|
this.logging = new LoggingService(resolvedApiKey, resolvedBaseUrl);
|
|
1707
1742
|
this.providers = new ProvidersService(resolvedApiKey, resolvedBaseUrl);
|
|
1743
|
+
this.secretReferences = new SecretReferencesService(
|
|
1744
|
+
resolvedApiKey,
|
|
1745
|
+
resolvedBaseUrl
|
|
1746
|
+
);
|
|
1708
1747
|
this.mcpIntegrations = new McpIntegrationsService(
|
|
1709
1748
|
resolvedApiKey,
|
|
1710
1749
|
resolvedBaseUrl
|
|
@@ -1726,52 +1765,92 @@ function getSharedPortkeyService(apiKey) {
|
|
|
1726
1765
|
}
|
|
1727
1766
|
|
|
1728
1767
|
// src/tools/index.ts
|
|
1729
|
-
import { z as
|
|
1768
|
+
import { z as z22 } from "zod";
|
|
1730
1769
|
|
|
1731
1770
|
// src/lib/type-guards.ts
|
|
1732
1771
|
function isRecord(value) {
|
|
1733
1772
|
return typeof value === "object" && value !== null;
|
|
1734
1773
|
}
|
|
1735
1774
|
|
|
1736
|
-
// src/
|
|
1775
|
+
// src/schemas/contracts/secret-references.contract.ts
|
|
1737
1776
|
import { z } from "zod";
|
|
1777
|
+
var SecretManagerTypeSchema = z.enum([
|
|
1778
|
+
"aws_sm",
|
|
1779
|
+
"azure_kv",
|
|
1780
|
+
"hashicorp_vault"
|
|
1781
|
+
]);
|
|
1782
|
+
var SecretReferenceListItemSchema = z.object({
|
|
1783
|
+
id: z.string().uuid(),
|
|
1784
|
+
name: z.string(),
|
|
1785
|
+
slug: z.string(),
|
|
1786
|
+
manager_type: SecretManagerTypeSchema,
|
|
1787
|
+
status: z.literal("ACTIVE"),
|
|
1788
|
+
created_at: z.iso.datetime(),
|
|
1789
|
+
last_updated_at: z.iso.datetime(),
|
|
1790
|
+
object: z.literal("secret-reference")
|
|
1791
|
+
});
|
|
1792
|
+
var ListSecretReferencesResponseSchema = z.object({
|
|
1793
|
+
object: z.literal("list"),
|
|
1794
|
+
total: z.number().int().nonnegative(),
|
|
1795
|
+
data: z.array(SecretReferenceListItemSchema)
|
|
1796
|
+
});
|
|
1797
|
+
var SecretReferenceDetailSchema = SecretReferenceListItemSchema.extend(
|
|
1798
|
+
{
|
|
1799
|
+
organisation_id: z.string().uuid(),
|
|
1800
|
+
description: z.string().nullable(),
|
|
1801
|
+
secret_path: z.string(),
|
|
1802
|
+
secret_key: z.string().nullable(),
|
|
1803
|
+
allow_all_workspaces: z.boolean(),
|
|
1804
|
+
tags: z.record(z.string(), z.string()).nullable(),
|
|
1805
|
+
created_by: z.string(),
|
|
1806
|
+
auth_config: z.record(z.string(), z.unknown())
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1809
|
+
var CreateSecretReferenceResponseSchema = z.object({
|
|
1810
|
+
id: z.string().uuid(),
|
|
1811
|
+
slug: z.string(),
|
|
1812
|
+
object: z.literal("secret-reference")
|
|
1813
|
+
});
|
|
1814
|
+
|
|
1815
|
+
// src/tools/analytics.tools.ts
|
|
1816
|
+
import { z as z2 } from "zod";
|
|
1738
1817
|
var baseAnalyticsSchema = {
|
|
1739
|
-
time_of_generation_min:
|
|
1818
|
+
time_of_generation_min: z2.string().describe(
|
|
1740
1819
|
"Start time for the analytics period (ISO8601 format, e.g., '2024-01-01T00:00:00Z')"
|
|
1741
1820
|
),
|
|
1742
|
-
time_of_generation_max:
|
|
1821
|
+
time_of_generation_max: z2.string().describe(
|
|
1743
1822
|
"End time for the analytics period (ISO8601 format, e.g., '2024-02-01T00:00:00Z')"
|
|
1744
1823
|
),
|
|
1745
|
-
total_units_min:
|
|
1746
|
-
total_units_max:
|
|
1747
|
-
cost_min:
|
|
1748
|
-
cost_max:
|
|
1749
|
-
prompt_token_min:
|
|
1750
|
-
prompt_token_max:
|
|
1751
|
-
completion_token_min:
|
|
1752
|
-
completion_token_max:
|
|
1753
|
-
status_code:
|
|
1824
|
+
total_units_min: z2.coerce.number().positive().optional().describe("Minimum number of total tokens to filter by"),
|
|
1825
|
+
total_units_max: z2.coerce.number().positive().optional().describe("Maximum number of total tokens to filter by"),
|
|
1826
|
+
cost_min: z2.coerce.number().positive().optional().describe("Minimum cost in cents to filter by"),
|
|
1827
|
+
cost_max: z2.coerce.number().positive().optional().describe("Maximum cost in cents to filter by"),
|
|
1828
|
+
prompt_token_min: z2.coerce.number().positive().optional().describe("Minimum number of prompt tokens"),
|
|
1829
|
+
prompt_token_max: z2.coerce.number().positive().optional().describe("Maximum number of prompt tokens"),
|
|
1830
|
+
completion_token_min: z2.coerce.number().positive().optional().describe("Minimum number of completion tokens"),
|
|
1831
|
+
completion_token_max: z2.coerce.number().positive().optional().describe("Maximum number of completion tokens"),
|
|
1832
|
+
status_code: z2.string().optional().describe(
|
|
1754
1833
|
"Legacy Portkey query param for HTTP status codes. Comma-separated string; prefer status_codes for structured inputs."
|
|
1755
1834
|
),
|
|
1756
|
-
weighted_feedback_min:
|
|
1757
|
-
weighted_feedback_max:
|
|
1758
|
-
virtual_keys:
|
|
1835
|
+
weighted_feedback_min: z2.coerce.number().min(-10).max(10).optional().describe("Minimum weighted feedback score (-10 to 10)"),
|
|
1836
|
+
weighted_feedback_max: z2.coerce.number().min(-10).max(10).optional().describe("Maximum weighted feedback score (-10 to 10)"),
|
|
1837
|
+
virtual_keys: z2.string().optional().describe(
|
|
1759
1838
|
"Legacy Portkey query param for virtual key slugs. Comma-separated string; prefer virtual_key_slugs for structured inputs."
|
|
1760
1839
|
),
|
|
1761
|
-
configs:
|
|
1840
|
+
configs: z2.string().optional().describe(
|
|
1762
1841
|
"Legacy Portkey query param for config slugs. Comma-separated string; prefer config_slugs for structured inputs."
|
|
1763
1842
|
),
|
|
1764
|
-
status_codes:
|
|
1843
|
+
status_codes: z2.array(z2.string()).optional().describe(
|
|
1765
1844
|
"Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
|
|
1766
1845
|
),
|
|
1767
|
-
virtual_key_slugs:
|
|
1846
|
+
virtual_key_slugs: z2.array(z2.string()).optional().describe(
|
|
1768
1847
|
"Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
|
|
1769
1848
|
),
|
|
1770
|
-
config_slugs:
|
|
1849
|
+
config_slugs: z2.array(z2.string()).optional().describe(
|
|
1771
1850
|
"Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
|
|
1772
1851
|
),
|
|
1773
|
-
workspace_slug:
|
|
1774
|
-
api_key_ids:
|
|
1852
|
+
workspace_slug: z2.string().optional().describe("Filter by specific workspace"),
|
|
1853
|
+
api_key_ids: z2.preprocess((value) => {
|
|
1775
1854
|
if (value == null) {
|
|
1776
1855
|
return value;
|
|
1777
1856
|
}
|
|
@@ -1779,43 +1858,43 @@ var baseAnalyticsSchema = {
|
|
|
1779
1858
|
return value.map((item) => String(item)).join(",");
|
|
1780
1859
|
}
|
|
1781
1860
|
return value;
|
|
1782
|
-
},
|
|
1861
|
+
}, z2.string().optional()).describe(
|
|
1783
1862
|
"Legacy Portkey query param for API key UUIDs. Comma-separated string; request_analytics also accepts an array and normalizes it to this form."
|
|
1784
1863
|
),
|
|
1785
|
-
metadata:
|
|
1864
|
+
metadata: z2.string().optional().describe(
|
|
1786
1865
|
`Legacy Portkey query param for metadata filtering. Stringified JSON object, e.g. '{"env":"prod","app":"myapp"}'; prefer metadata_filter for structured inputs.`
|
|
1787
1866
|
),
|
|
1788
|
-
ai_org_model:
|
|
1867
|
+
ai_org_model: z2.string().optional().describe(
|
|
1789
1868
|
"Legacy Portkey query param for provider/model pairs. Format: 'provider__model' with double underscore, e.g. 'openai__gpt-4' or 'anthropic__claude-3-opus'. Comma-separated string; prefer provider_models for structured inputs."
|
|
1790
1869
|
),
|
|
1791
|
-
provider_models:
|
|
1870
|
+
provider_models: z2.array(z2.string()).optional().describe(
|
|
1792
1871
|
"Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
|
|
1793
1872
|
),
|
|
1794
|
-
trace_id:
|
|
1873
|
+
trace_id: z2.string().optional().describe(
|
|
1795
1874
|
"Legacy Portkey query param for trace IDs. Comma-separated string; prefer trace_ids for structured inputs."
|
|
1796
1875
|
),
|
|
1797
|
-
trace_ids:
|
|
1876
|
+
trace_ids: z2.array(z2.string()).optional().describe(
|
|
1798
1877
|
"Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
|
|
1799
1878
|
),
|
|
1800
|
-
span_id:
|
|
1879
|
+
span_id: z2.string().optional().describe(
|
|
1801
1880
|
"Legacy Portkey query param for span IDs. Comma-separated string; prefer span_ids for structured inputs."
|
|
1802
1881
|
),
|
|
1803
|
-
span_ids:
|
|
1882
|
+
span_ids: z2.array(z2.string()).optional().describe(
|
|
1804
1883
|
"Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
|
|
1805
1884
|
),
|
|
1806
|
-
metadata_filter:
|
|
1885
|
+
metadata_filter: z2.record(z2.string(), z2.unknown()).optional().describe(
|
|
1807
1886
|
"Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
|
|
1808
1887
|
),
|
|
1809
|
-
prompt_slug:
|
|
1888
|
+
prompt_slug: z2.string().optional().describe("Filter by prompt slug")
|
|
1810
1889
|
};
|
|
1811
1890
|
var paginatedAnalyticsSchema = {
|
|
1812
1891
|
...baseAnalyticsSchema,
|
|
1813
|
-
current_page:
|
|
1814
|
-
page_size:
|
|
1892
|
+
current_page: z2.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
1893
|
+
page_size: z2.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
|
|
1815
1894
|
};
|
|
1816
1895
|
var analyticsGroupMetadataSchema = {
|
|
1817
1896
|
...paginatedAnalyticsSchema,
|
|
1818
|
-
metadata_key:
|
|
1897
|
+
metadata_key: z2.string().describe("The metadata key to group by (e.g., 'env', 'app', 'client_id')")
|
|
1819
1898
|
};
|
|
1820
1899
|
function formatGraphAnalytics(summary, dataPoints) {
|
|
1821
1900
|
return {
|
|
@@ -2398,26 +2477,26 @@ function registerAnalyticsTools(server, service) {
|
|
|
2398
2477
|
}
|
|
2399
2478
|
|
|
2400
2479
|
// src/tools/audit.tools.ts
|
|
2401
|
-
import { z as
|
|
2480
|
+
import { z as z3 } from "zod";
|
|
2402
2481
|
var AUDIT_TOOL_SCHEMAS = {
|
|
2403
2482
|
listAuditLogs: {
|
|
2404
|
-
workspace_id:
|
|
2405
|
-
actor_id:
|
|
2406
|
-
action:
|
|
2483
|
+
workspace_id: z3.string().optional().describe("Filter audit logs by workspace ID"),
|
|
2484
|
+
actor_id: z3.string().optional().describe("Filter by the user ID who performed the action"),
|
|
2485
|
+
action: z3.string().optional().describe(
|
|
2407
2486
|
"Filter by action type (e.g., 'create', 'update', 'delete', 'login')"
|
|
2408
2487
|
),
|
|
2409
|
-
resource_type:
|
|
2488
|
+
resource_type: z3.string().optional().describe(
|
|
2410
2489
|
"Filter by resource type (e.g., 'user', 'workspace', 'config', 'virtual_key')"
|
|
2411
2490
|
),
|
|
2412
|
-
resource_id:
|
|
2413
|
-
start_time:
|
|
2491
|
+
resource_id: z3.string().optional().describe("Filter by specific resource ID"),
|
|
2492
|
+
start_time: z3.string().optional().describe(
|
|
2414
2493
|
"Start of time range filter (ISO 8601 format, e.g., '2024-01-01T00:00:00Z')"
|
|
2415
2494
|
),
|
|
2416
|
-
end_time:
|
|
2495
|
+
end_time: z3.string().optional().describe(
|
|
2417
2496
|
"End of time range filter (ISO 8601 format, e.g., '2024-01-31T23:59:59Z')"
|
|
2418
2497
|
),
|
|
2419
|
-
current_page:
|
|
2420
|
-
page_size:
|
|
2498
|
+
current_page: z3.coerce.number().int().positive().optional().describe("Page number for pagination (starts at 1)"),
|
|
2499
|
+
page_size: z3.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
2421
2500
|
}
|
|
2422
2501
|
};
|
|
2423
2502
|
function registerAuditTools(server, service) {
|
|
@@ -2470,30 +2549,30 @@ function registerAuditTools(server, service) {
|
|
|
2470
2549
|
}
|
|
2471
2550
|
|
|
2472
2551
|
// src/tools/collections.tools.ts
|
|
2473
|
-
import { z as
|
|
2552
|
+
import { z as z4 } from "zod";
|
|
2474
2553
|
var COLLECTIONS_TOOL_SCHEMAS = {
|
|
2475
2554
|
listCollections: {
|
|
2476
|
-
workspace_id:
|
|
2477
|
-
search:
|
|
2478
|
-
current_page:
|
|
2479
|
-
page_size:
|
|
2555
|
+
workspace_id: z4.string().optional().describe("Filter by workspace ID"),
|
|
2556
|
+
search: z4.string().optional().describe("Search collections by name"),
|
|
2557
|
+
current_page: z4.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
2558
|
+
page_size: z4.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
|
|
2480
2559
|
},
|
|
2481
2560
|
createCollection: {
|
|
2482
|
-
name:
|
|
2561
|
+
name: z4.string().describe(
|
|
2483
2562
|
"Collection name (e.g., 'hourlink', 'apizone', 'research-pilot')"
|
|
2484
2563
|
),
|
|
2485
|
-
workspace_id:
|
|
2564
|
+
workspace_id: z4.string().optional().describe("Workspace ID to create collection in")
|
|
2486
2565
|
},
|
|
2487
2566
|
getCollection: {
|
|
2488
|
-
collection_id:
|
|
2567
|
+
collection_id: z4.string().describe("Collection ID or slug to retrieve")
|
|
2489
2568
|
},
|
|
2490
2569
|
updateCollection: {
|
|
2491
|
-
collection_id:
|
|
2492
|
-
name:
|
|
2493
|
-
description:
|
|
2570
|
+
collection_id: z4.string().describe("Collection ID to update"),
|
|
2571
|
+
name: z4.string().optional().describe("New name for the collection"),
|
|
2572
|
+
description: z4.string().optional().describe("New description for the collection")
|
|
2494
2573
|
},
|
|
2495
2574
|
deleteCollection: {
|
|
2496
|
-
collection_id:
|
|
2575
|
+
collection_id: z4.string().describe("Collection ID to delete")
|
|
2497
2576
|
}
|
|
2498
2577
|
};
|
|
2499
2578
|
function registerCollectionsTools(server, service) {
|
|
@@ -2614,69 +2693,69 @@ function registerCollectionsTools(server, service) {
|
|
|
2614
2693
|
}
|
|
2615
2694
|
|
|
2616
2695
|
// src/tools/configs.tools.ts
|
|
2617
|
-
import { z as
|
|
2696
|
+
import { z as z5 } from "zod";
|
|
2618
2697
|
var CONFIGS_TOOL_SCHEMAS = {
|
|
2619
2698
|
listConfigs: {
|
|
2620
|
-
current_page:
|
|
2621
|
-
page_size:
|
|
2699
|
+
current_page: z5.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
2700
|
+
page_size: z5.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
2622
2701
|
},
|
|
2623
2702
|
getConfig: {
|
|
2624
|
-
slug:
|
|
2703
|
+
slug: z5.string().describe(
|
|
2625
2704
|
"The unique identifier (slug) of the configuration to retrieve. This can be found in the configuration's URL or from the list_configs tool response"
|
|
2626
2705
|
)
|
|
2627
2706
|
},
|
|
2628
2707
|
createConfig: {
|
|
2629
|
-
name:
|
|
2630
|
-
workspace_id:
|
|
2631
|
-
cache_mode:
|
|
2632
|
-
cache_max_age:
|
|
2633
|
-
retry_attempts:
|
|
2634
|
-
retry_on_status_codes:
|
|
2635
|
-
strategy_mode:
|
|
2636
|
-
targets:
|
|
2637
|
-
|
|
2638
|
-
provider:
|
|
2639
|
-
virtual_key:
|
|
2708
|
+
name: z5.string().describe("Name for the new configuration"),
|
|
2709
|
+
workspace_id: z5.string().optional().describe("Workspace ID to create config in"),
|
|
2710
|
+
cache_mode: z5.enum(["simple", "semantic"]).optional().describe("Cache mode: 'simple' or 'semantic'"),
|
|
2711
|
+
cache_max_age: z5.coerce.number().positive().optional().describe("Cache max age in seconds"),
|
|
2712
|
+
retry_attempts: z5.coerce.number().positive().max(5).optional().describe("Number of retry attempts (1-5)"),
|
|
2713
|
+
retry_on_status_codes: z5.array(z5.coerce.number()).optional().describe("HTTP status codes to retry on (e.g., [429, 500, 502, 503])"),
|
|
2714
|
+
strategy_mode: z5.enum(["loadbalance", "fallback"]).optional().describe("Routing strategy: 'loadbalance' or 'fallback'"),
|
|
2715
|
+
targets: z5.array(
|
|
2716
|
+
z5.object({
|
|
2717
|
+
provider: z5.string().optional(),
|
|
2718
|
+
virtual_key: z5.string().optional()
|
|
2640
2719
|
}).refine((t) => t.provider || t.virtual_key, {
|
|
2641
2720
|
message: "Each target must have at least provider or virtual_key"
|
|
2642
2721
|
})
|
|
2643
2722
|
).optional().describe("Array of target providers with virtual keys")
|
|
2644
2723
|
},
|
|
2645
2724
|
updateConfig: {
|
|
2646
|
-
slug:
|
|
2647
|
-
name:
|
|
2648
|
-
status:
|
|
2649
|
-
cache_mode:
|
|
2650
|
-
cache_max_age:
|
|
2651
|
-
retry_attempts:
|
|
2652
|
-
retry_on_status_codes:
|
|
2653
|
-
strategy_mode:
|
|
2654
|
-
targets:
|
|
2655
|
-
|
|
2656
|
-
provider:
|
|
2657
|
-
virtual_key:
|
|
2725
|
+
slug: z5.string().describe("Configuration slug to update"),
|
|
2726
|
+
name: z5.string().optional().describe("New name for the configuration"),
|
|
2727
|
+
status: z5.enum(["active", "inactive"]).optional().describe("Configuration status"),
|
|
2728
|
+
cache_mode: z5.enum(["simple", "semantic"]).optional().describe("Cache mode: 'simple' or 'semantic'"),
|
|
2729
|
+
cache_max_age: z5.coerce.number().positive().optional().describe("Cache max age in seconds"),
|
|
2730
|
+
retry_attempts: z5.coerce.number().positive().max(5).optional().describe("Number of retry attempts (1-5)"),
|
|
2731
|
+
retry_on_status_codes: z5.array(z5.coerce.number()).optional().describe("HTTP status codes to retry on"),
|
|
2732
|
+
strategy_mode: z5.enum(["loadbalance", "fallback"]).optional().describe("Routing strategy"),
|
|
2733
|
+
targets: z5.array(
|
|
2734
|
+
z5.object({
|
|
2735
|
+
provider: z5.string().optional(),
|
|
2736
|
+
virtual_key: z5.string().optional()
|
|
2658
2737
|
}).refine((t) => t.provider || t.virtual_key, {
|
|
2659
2738
|
message: "Each target must have at least provider or virtual_key"
|
|
2660
2739
|
})
|
|
2661
2740
|
).optional().describe("Array of target providers")
|
|
2662
2741
|
},
|
|
2663
2742
|
deleteConfig: {
|
|
2664
|
-
slug:
|
|
2743
|
+
slug: z5.string().describe("Configuration slug to delete")
|
|
2665
2744
|
},
|
|
2666
2745
|
listConfigVersions: {
|
|
2667
|
-
slug:
|
|
2746
|
+
slug: z5.string().describe("Configuration slug to list versions for")
|
|
2668
2747
|
}
|
|
2669
2748
|
};
|
|
2670
|
-
var configPayloadSchema =
|
|
2671
|
-
cache_mode:
|
|
2672
|
-
cache_max_age:
|
|
2673
|
-
retry_attempts:
|
|
2674
|
-
retry_on_status_codes:
|
|
2675
|
-
strategy_mode:
|
|
2676
|
-
targets:
|
|
2677
|
-
|
|
2678
|
-
provider:
|
|
2679
|
-
virtual_key:
|
|
2749
|
+
var configPayloadSchema = z5.object({
|
|
2750
|
+
cache_mode: z5.enum(["simple", "semantic"]).optional(),
|
|
2751
|
+
cache_max_age: z5.coerce.number().positive().optional(),
|
|
2752
|
+
retry_attempts: z5.coerce.number().positive().max(5).optional(),
|
|
2753
|
+
retry_on_status_codes: z5.array(z5.coerce.number()).optional(),
|
|
2754
|
+
strategy_mode: z5.enum(["loadbalance", "fallback"]).optional(),
|
|
2755
|
+
targets: z5.array(
|
|
2756
|
+
z5.object({
|
|
2757
|
+
provider: z5.string().optional(),
|
|
2758
|
+
virtual_key: z5.string().optional()
|
|
2680
2759
|
})
|
|
2681
2760
|
).optional()
|
|
2682
2761
|
});
|
|
@@ -2893,53 +2972,53 @@ function registerConfigsTools(server, service) {
|
|
|
2893
2972
|
}
|
|
2894
2973
|
|
|
2895
2974
|
// src/tools/guardrails.tools.ts
|
|
2896
|
-
import { z as
|
|
2897
|
-
var guardrailCheckSchema =
|
|
2898
|
-
id:
|
|
2899
|
-
name:
|
|
2900
|
-
is_enabled:
|
|
2901
|
-
parameters:
|
|
2975
|
+
import { z as z6 } from "zod";
|
|
2976
|
+
var guardrailCheckSchema = z6.object({
|
|
2977
|
+
id: z6.string().describe("Check identifier (e.g., 'default.jwt', 'default.pii')"),
|
|
2978
|
+
name: z6.string().optional().describe("Display name for the check"),
|
|
2979
|
+
is_enabled: z6.boolean().optional().describe("Whether the check is enabled"),
|
|
2980
|
+
parameters: z6.record(z6.string(), z6.unknown()).optional().describe("Check-specific configuration parameters")
|
|
2902
2981
|
});
|
|
2903
|
-
var guardrailFeedbackSchema =
|
|
2904
|
-
value:
|
|
2905
|
-
weight:
|
|
2906
|
-
metadata:
|
|
2982
|
+
var guardrailFeedbackSchema = z6.object({
|
|
2983
|
+
value: z6.coerce.number().optional().describe("Feedback value"),
|
|
2984
|
+
weight: z6.coerce.number().optional().describe("Feedback weight"),
|
|
2985
|
+
metadata: z6.record(z6.string(), z6.unknown()).optional().describe("Additional metadata")
|
|
2907
2986
|
});
|
|
2908
|
-
var guardrailActionSchema =
|
|
2909
|
-
deny:
|
|
2910
|
-
async:
|
|
2987
|
+
var guardrailActionSchema = z6.object({
|
|
2988
|
+
deny: z6.boolean().optional().describe("Whether to deny the request on check failure"),
|
|
2989
|
+
async: z6.boolean().optional().describe("Whether to run checks asynchronously"),
|
|
2911
2990
|
on_success: guardrailFeedbackSchema.optional().describe("Feedback configuration for successful checks"),
|
|
2912
2991
|
on_fail: guardrailFeedbackSchema.optional().describe("Feedback configuration for failed checks"),
|
|
2913
|
-
on_fail_action:
|
|
2914
|
-
message:
|
|
2992
|
+
on_fail_action: z6.string().optional().describe("Simple action on failure (e.g., 'block')"),
|
|
2993
|
+
message: z6.string().optional().describe("Message to return when guardrail triggers")
|
|
2915
2994
|
});
|
|
2916
2995
|
var GUARDRAILS_TOOL_SCHEMAS = {
|
|
2917
2996
|
listGuardrails: {
|
|
2918
|
-
workspace_id:
|
|
2919
|
-
organisation_id:
|
|
2920
|
-
page_size:
|
|
2921
|
-
current_page:
|
|
2997
|
+
workspace_id: z6.string().optional().describe("Filter guardrails by workspace ID"),
|
|
2998
|
+
organisation_id: z6.string().optional().describe("Filter guardrails by organization ID"),
|
|
2999
|
+
page_size: z6.coerce.number().int().min(1).max(100).optional().describe("Number of items per page (1-100, default: 100)"),
|
|
3000
|
+
current_page: z6.coerce.number().int().positive().optional().describe("Page number for pagination")
|
|
2922
3001
|
},
|
|
2923
3002
|
getGuardrail: {
|
|
2924
|
-
guardrail_id:
|
|
3003
|
+
guardrail_id: z6.string().describe("The guardrail UUID or slug (with guard_ prefix) to retrieve")
|
|
2925
3004
|
},
|
|
2926
3005
|
createGuardrail: {
|
|
2927
|
-
name:
|
|
2928
|
-
checks:
|
|
3006
|
+
name: z6.string().describe("Name of the guardrail"),
|
|
3007
|
+
checks: z6.array(guardrailCheckSchema).min(1).describe("Array of checks to apply (at least one required)"),
|
|
2929
3008
|
actions: guardrailActionSchema.describe(
|
|
2930
3009
|
"Actions to take when guardrail checks pass or fail"
|
|
2931
3010
|
),
|
|
2932
|
-
workspace_id:
|
|
2933
|
-
organisation_id:
|
|
3011
|
+
workspace_id: z6.string().optional().describe("Workspace ID to create the guardrail in"),
|
|
3012
|
+
organisation_id: z6.string().optional().describe("Organisation ID (required if workspace_id not provided)")
|
|
2934
3013
|
},
|
|
2935
3014
|
updateGuardrail: {
|
|
2936
|
-
guardrail_id:
|
|
2937
|
-
name:
|
|
2938
|
-
checks:
|
|
3015
|
+
guardrail_id: z6.string().describe("The guardrail UUID or slug to update"),
|
|
3016
|
+
name: z6.string().optional().describe("New name for the guardrail"),
|
|
3017
|
+
checks: z6.array(guardrailCheckSchema).min(1).optional().describe("Updated array of checks to apply"),
|
|
2939
3018
|
actions: guardrailActionSchema.optional().describe("Updated actions configuration")
|
|
2940
3019
|
},
|
|
2941
3020
|
deleteGuardrail: {
|
|
2942
|
-
guardrail_id:
|
|
3021
|
+
guardrail_id: z6.string().describe("The guardrail UUID or slug to delete")
|
|
2943
3022
|
}
|
|
2944
3023
|
};
|
|
2945
3024
|
function registerGuardrailsTools(server, service) {
|
|
@@ -3089,7 +3168,7 @@ function registerGuardrailsTools(server, service) {
|
|
|
3089
3168
|
}
|
|
3090
3169
|
|
|
3091
3170
|
// src/tools/integrations.tools.ts
|
|
3092
|
-
import { z as
|
|
3171
|
+
import { z as z7 } from "zod";
|
|
3093
3172
|
|
|
3094
3173
|
// src/lib/limits.ts
|
|
3095
3174
|
var PERIODIC_RESET_DEFAULT = "monthly";
|
|
@@ -3134,91 +3213,91 @@ function buildRateLimits(params) {
|
|
|
3134
3213
|
// src/tools/integrations.tools.ts
|
|
3135
3214
|
var INTEGRATIONS_TOOL_SCHEMAS = {
|
|
3136
3215
|
listIntegrations: {
|
|
3137
|
-
current_page:
|
|
3138
|
-
page_size:
|
|
3139
|
-
workspace_id:
|
|
3140
|
-
type:
|
|
3216
|
+
current_page: z7.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
3217
|
+
page_size: z7.coerce.number().int().positive().max(100).optional().describe("Number of results per page (default 100, max 100)"),
|
|
3218
|
+
workspace_id: z7.string().optional().describe("Filter integrations accessible by a specific workspace"),
|
|
3219
|
+
type: z7.enum(["workspace", "organisation", "all"]).optional().describe(
|
|
3141
3220
|
"Filter by integration type: 'workspace', 'organisation', or 'all' (default)"
|
|
3142
3221
|
)
|
|
3143
3222
|
},
|
|
3144
3223
|
createIntegration: {
|
|
3145
|
-
name:
|
|
3146
|
-
ai_provider_id:
|
|
3224
|
+
name: z7.string().describe("Human-readable name for the integration"),
|
|
3225
|
+
ai_provider_id: z7.string().describe(
|
|
3147
3226
|
"ID of the AI provider (e.g., 'openai', 'anthropic', 'azure-openai', 'aws-bedrock', 'vertex-ai')"
|
|
3148
3227
|
),
|
|
3149
|
-
slug:
|
|
3228
|
+
slug: z7.string().optional().describe(
|
|
3150
3229
|
"URL-friendly identifier (auto-generated from name if not provided)"
|
|
3151
3230
|
),
|
|
3152
|
-
key:
|
|
3153
|
-
description:
|
|
3154
|
-
workspace_id:
|
|
3155
|
-
api_version:
|
|
3156
|
-
resource_name:
|
|
3157
|
-
deployment_name:
|
|
3158
|
-
aws_region:
|
|
3159
|
-
aws_access_key_id:
|
|
3160
|
-
aws_secret_access_key:
|
|
3161
|
-
vertex_project_id:
|
|
3162
|
-
vertex_region:
|
|
3163
|
-
custom_host:
|
|
3231
|
+
key: z7.string().optional().describe("API key for the provider (if required)"),
|
|
3232
|
+
description: z7.string().optional().describe("Optional description of the integration"),
|
|
3233
|
+
workspace_id: z7.string().optional().describe("Workspace ID for workspace-scoped integrations"),
|
|
3234
|
+
api_version: z7.string().optional().describe("API version (for Azure OpenAI)"),
|
|
3235
|
+
resource_name: z7.string().optional().describe("Resource name (for Azure OpenAI)"),
|
|
3236
|
+
deployment_name: z7.string().optional().describe("Deployment name (for Azure OpenAI)"),
|
|
3237
|
+
aws_region: z7.string().optional().describe("AWS region (for AWS Bedrock)"),
|
|
3238
|
+
aws_access_key_id: z7.string().optional().describe("AWS access key ID (for AWS Bedrock)"),
|
|
3239
|
+
aws_secret_access_key: z7.string().optional().describe("AWS secret access key (for AWS Bedrock)"),
|
|
3240
|
+
vertex_project_id: z7.string().optional().describe("GCP project ID (for Vertex AI)"),
|
|
3241
|
+
vertex_region: z7.string().optional().describe("GCP region (for Vertex AI)"),
|
|
3242
|
+
custom_host: z7.string().optional().describe("Custom base URL for the provider")
|
|
3164
3243
|
},
|
|
3165
3244
|
getIntegration: {
|
|
3166
|
-
slug:
|
|
3245
|
+
slug: z7.string().describe("The unique slug identifier of the integration to retrieve")
|
|
3167
3246
|
},
|
|
3168
3247
|
updateIntegration: {
|
|
3169
|
-
slug:
|
|
3170
|
-
name:
|
|
3171
|
-
key:
|
|
3172
|
-
description:
|
|
3173
|
-
api_version:
|
|
3174
|
-
resource_name:
|
|
3175
|
-
deployment_name:
|
|
3176
|
-
aws_region:
|
|
3177
|
-
aws_access_key_id:
|
|
3178
|
-
aws_secret_access_key:
|
|
3179
|
-
vertex_project_id:
|
|
3180
|
-
vertex_region:
|
|
3181
|
-
custom_host:
|
|
3248
|
+
slug: z7.string().describe("The slug of the integration to update"),
|
|
3249
|
+
name: z7.string().optional().describe("New human-readable name for the integration"),
|
|
3250
|
+
key: z7.string().optional().describe("New API key for the provider"),
|
|
3251
|
+
description: z7.string().optional().describe("New description for the integration"),
|
|
3252
|
+
api_version: z7.string().optional().describe("New API version (for Azure OpenAI)"),
|
|
3253
|
+
resource_name: z7.string().optional().describe("New resource name (for Azure OpenAI)"),
|
|
3254
|
+
deployment_name: z7.string().optional().describe("New deployment name (for Azure OpenAI)"),
|
|
3255
|
+
aws_region: z7.string().optional().describe("New AWS region (for AWS Bedrock)"),
|
|
3256
|
+
aws_access_key_id: z7.string().optional().describe("New AWS access key ID (for AWS Bedrock)"),
|
|
3257
|
+
aws_secret_access_key: z7.string().optional().describe("New AWS secret access key (for AWS Bedrock)"),
|
|
3258
|
+
vertex_project_id: z7.string().optional().describe("New GCP project ID (for Vertex AI)"),
|
|
3259
|
+
vertex_region: z7.string().optional().describe("New GCP region (for Vertex AI)"),
|
|
3260
|
+
custom_host: z7.string().optional().describe("New custom base URL for the provider")
|
|
3182
3261
|
},
|
|
3183
3262
|
deleteIntegration: {
|
|
3184
|
-
slug:
|
|
3263
|
+
slug: z7.string().describe("The slug of the integration to delete")
|
|
3185
3264
|
},
|
|
3186
3265
|
listIntegrationModels: {
|
|
3187
|
-
slug:
|
|
3188
|
-
current_page:
|
|
3189
|
-
page_size:
|
|
3266
|
+
slug: z7.string().describe("The slug of the integration"),
|
|
3267
|
+
current_page: z7.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
3268
|
+
page_size: z7.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
|
|
3190
3269
|
},
|
|
3191
3270
|
updateIntegrationModels: {
|
|
3192
|
-
slug:
|
|
3193
|
-
models:
|
|
3194
|
-
|
|
3195
|
-
slug:
|
|
3196
|
-
model_name:
|
|
3271
|
+
slug: z7.string().describe("The slug of the integration"),
|
|
3272
|
+
models: z7.array(
|
|
3273
|
+
z7.object({
|
|
3274
|
+
slug: z7.string().describe("The model slug identifier"),
|
|
3275
|
+
model_name: z7.string().optional().describe(
|
|
3197
3276
|
"Display name for the model (required for custom models)"
|
|
3198
3277
|
),
|
|
3199
|
-
enabled:
|
|
3200
|
-
is_custom:
|
|
3278
|
+
enabled: z7.boolean().describe("Whether the model is enabled"),
|
|
3279
|
+
is_custom: z7.boolean().optional().describe("Whether this is a custom model (default: false)")
|
|
3201
3280
|
})
|
|
3202
3281
|
).describe("Array of model configurations to update")
|
|
3203
3282
|
},
|
|
3204
3283
|
deleteIntegrationModel: {
|
|
3205
|
-
slug:
|
|
3206
|
-
model_slug:
|
|
3284
|
+
slug: z7.string().describe("The slug of the integration"),
|
|
3285
|
+
model_slug: z7.string().describe("The slug of the model to delete")
|
|
3207
3286
|
},
|
|
3208
3287
|
listIntegrationWorkspaces: {
|
|
3209
|
-
slug:
|
|
3210
|
-
current_page:
|
|
3211
|
-
page_size:
|
|
3288
|
+
slug: z7.string().describe("The slug of the integration"),
|
|
3289
|
+
current_page: z7.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
3290
|
+
page_size: z7.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
|
|
3212
3291
|
},
|
|
3213
3292
|
updateIntegrationWorkspaces: {
|
|
3214
|
-
slug:
|
|
3215
|
-
workspaces:
|
|
3216
|
-
|
|
3217
|
-
id:
|
|
3218
|
-
enabled:
|
|
3219
|
-
credit_limit:
|
|
3220
|
-
alert_threshold:
|
|
3221
|
-
rate_limit_rpm:
|
|
3293
|
+
slug: z7.string().describe("The slug of the integration"),
|
|
3294
|
+
workspaces: z7.array(
|
|
3295
|
+
z7.object({
|
|
3296
|
+
id: z7.string().describe("The workspace ID"),
|
|
3297
|
+
enabled: z7.boolean().describe("Whether the workspace has access to this integration"),
|
|
3298
|
+
credit_limit: z7.coerce.number().positive().optional().describe("Credit limit for this workspace"),
|
|
3299
|
+
alert_threshold: z7.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
|
|
3300
|
+
rate_limit_rpm: z7.coerce.number().positive().optional().describe("Rate limit in requests per minute")
|
|
3222
3301
|
})
|
|
3223
3302
|
).describe("Array of workspace configurations to update")
|
|
3224
3303
|
}
|
|
@@ -3551,104 +3630,110 @@ function registerIntegrationsTools(server, service) {
|
|
|
3551
3630
|
}
|
|
3552
3631
|
|
|
3553
3632
|
// src/tools/keys.tools.ts
|
|
3554
|
-
import { z as
|
|
3633
|
+
import { z as z8 } from "zod";
|
|
3555
3634
|
var KEYS_TOOL_SCHEMAS = {
|
|
3556
3635
|
listVirtualKeys: {
|
|
3557
|
-
current_page:
|
|
3558
|
-
page_size:
|
|
3636
|
+
current_page: z8.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
3637
|
+
page_size: z8.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
3559
3638
|
},
|
|
3560
3639
|
createVirtualKey: {
|
|
3561
|
-
name:
|
|
3562
|
-
provider:
|
|
3640
|
+
name: z8.string().describe("Display name for the virtual key"),
|
|
3641
|
+
provider: z8.string().describe(
|
|
3563
3642
|
"Provider slug (e.g., 'openai', 'anthropic', 'azure-openai', 'google')"
|
|
3564
3643
|
),
|
|
3565
|
-
key:
|
|
3566
|
-
note:
|
|
3567
|
-
workspace_id:
|
|
3568
|
-
api_version:
|
|
3569
|
-
resource_name:
|
|
3570
|
-
deployment_name:
|
|
3571
|
-
credit_limit:
|
|
3572
|
-
alert_threshold:
|
|
3644
|
+
key: z8.string().describe("The actual provider API key to store"),
|
|
3645
|
+
note: z8.string().optional().describe("Optional note or description for this key"),
|
|
3646
|
+
workspace_id: z8.string().optional().describe("Workspace ID to create the key in"),
|
|
3647
|
+
api_version: z8.string().optional().describe("API version (for Azure OpenAI)"),
|
|
3648
|
+
resource_name: z8.string().optional().describe("Resource name (for Azure OpenAI)"),
|
|
3649
|
+
deployment_name: z8.string().optional().describe("Deployment name (for Azure OpenAI)"),
|
|
3650
|
+
credit_limit: z8.coerce.number().positive().optional().describe("Maximum usage cost threshold"),
|
|
3651
|
+
alert_threshold: z8.coerce.number().min(0).max(100).optional().describe(
|
|
3573
3652
|
"Percentage of credit_limit at which to send alert emails (0-100)"
|
|
3574
3653
|
),
|
|
3575
|
-
rate_limit_rpm:
|
|
3654
|
+
rate_limit_rpm: z8.coerce.number().positive().optional().describe("Requests per minute limit")
|
|
3576
3655
|
},
|
|
3577
3656
|
getVirtualKey: {
|
|
3578
|
-
slug:
|
|
3657
|
+
slug: z8.string().describe("The unique slug identifier of the virtual key to retrieve")
|
|
3579
3658
|
},
|
|
3580
3659
|
updateVirtualKey: {
|
|
3581
|
-
slug:
|
|
3582
|
-
name:
|
|
3583
|
-
key:
|
|
3584
|
-
note:
|
|
3585
|
-
credit_limit:
|
|
3586
|
-
alert_threshold:
|
|
3587
|
-
rate_limit_rpm:
|
|
3660
|
+
slug: z8.string().describe("The slug of the virtual key to update"),
|
|
3661
|
+
name: z8.string().optional().describe("New display name for the key"),
|
|
3662
|
+
key: z8.string().optional().describe("New provider API key value"),
|
|
3663
|
+
note: z8.string().optional().describe("New note or description"),
|
|
3664
|
+
credit_limit: z8.coerce.number().positive().optional().describe("New credit limit for usage"),
|
|
3665
|
+
alert_threshold: z8.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
|
|
3666
|
+
rate_limit_rpm: z8.coerce.number().positive().optional().describe("New rate limit in requests per minute")
|
|
3588
3667
|
},
|
|
3589
3668
|
deleteVirtualKey: {
|
|
3590
|
-
slug:
|
|
3669
|
+
slug: z8.string().describe("The slug of the virtual key to delete")
|
|
3591
3670
|
},
|
|
3592
3671
|
createApiKey: {
|
|
3593
|
-
type:
|
|
3672
|
+
type: z8.enum(["organisation", "workspace"]).describe(
|
|
3594
3673
|
"Key type: 'organisation' for org-wide access or 'workspace' for workspace-scoped"
|
|
3595
3674
|
),
|
|
3596
|
-
sub_type:
|
|
3675
|
+
sub_type: z8.enum(["user", "service"]).describe(
|
|
3597
3676
|
"Sub-type: 'user' for user-associated keys or 'service' for service accounts"
|
|
3598
3677
|
),
|
|
3599
|
-
name:
|
|
3600
|
-
description:
|
|
3601
|
-
workspace_id:
|
|
3602
|
-
user_id:
|
|
3603
|
-
scopes:
|
|
3678
|
+
name: z8.string().describe("Display name for the API key"),
|
|
3679
|
+
description: z8.string().optional().describe("Optional description for the key"),
|
|
3680
|
+
workspace_id: z8.string().optional().describe("Workspace ID (required for workspace-type keys)"),
|
|
3681
|
+
user_id: z8.string().optional().describe("User ID (required for user sub-type keys)"),
|
|
3682
|
+
scopes: z8.array(z8.string()).describe(
|
|
3604
3683
|
"Permission scopes for the key (e.g., ['logs.read', 'analytics.read'])"
|
|
3605
3684
|
),
|
|
3606
|
-
credit_limit:
|
|
3607
|
-
alert_threshold:
|
|
3608
|
-
rate_limit_rpm:
|
|
3609
|
-
default_config_id:
|
|
3610
|
-
default_metadata:
|
|
3611
|
-
alert_emails:
|
|
3612
|
-
expires_at:
|
|
3685
|
+
credit_limit: z8.coerce.number().positive().optional().describe("Credit limit for usage"),
|
|
3686
|
+
alert_threshold: z8.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
|
|
3687
|
+
rate_limit_rpm: z8.coerce.number().positive().optional().describe("Rate limit in requests per minute"),
|
|
3688
|
+
default_config_id: z8.string().optional().describe("Default configuration ID to use with this key"),
|
|
3689
|
+
default_metadata: z8.record(z8.string(), z8.string()).optional().describe("Default metadata key-value pairs"),
|
|
3690
|
+
alert_emails: z8.array(z8.string()).optional().describe("Email addresses for alerts"),
|
|
3691
|
+
expires_at: z8.string().optional().describe("Expiration date in ISO 8601 format")
|
|
3613
3692
|
},
|
|
3614
3693
|
listApiKeys: {
|
|
3615
|
-
page_size:
|
|
3616
|
-
current_page:
|
|
3617
|
-
workspace_id:
|
|
3694
|
+
page_size: z8.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
|
|
3695
|
+
current_page: z8.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
3696
|
+
workspace_id: z8.string().optional().describe("Filter by workspace ID")
|
|
3618
3697
|
},
|
|
3619
3698
|
getApiKey: {
|
|
3620
|
-
id:
|
|
3699
|
+
id: z8.string().uuid().describe("The UUID of the API key to retrieve")
|
|
3621
3700
|
},
|
|
3622
3701
|
updateApiKey: {
|
|
3623
|
-
id:
|
|
3624
|
-
name:
|
|
3625
|
-
description:
|
|
3626
|
-
scopes:
|
|
3627
|
-
credit_limit:
|
|
3628
|
-
alert_threshold:
|
|
3629
|
-
rate_limit_rpm:
|
|
3630
|
-
default_config_id:
|
|
3631
|
-
default_metadata:
|
|
3632
|
-
alert_emails:
|
|
3633
|
-
expires_at:
|
|
3702
|
+
id: z8.string().uuid().describe("The UUID of the API key to update"),
|
|
3703
|
+
name: z8.string().optional().describe("New display name for the key"),
|
|
3704
|
+
description: z8.string().optional().describe("New description for the key"),
|
|
3705
|
+
scopes: z8.array(z8.string()).optional().describe("New permission scopes for the key"),
|
|
3706
|
+
credit_limit: z8.coerce.number().positive().optional().describe("New credit limit for usage"),
|
|
3707
|
+
alert_threshold: z8.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
|
|
3708
|
+
rate_limit_rpm: z8.coerce.number().positive().optional().describe("New rate limit in requests per minute"),
|
|
3709
|
+
default_config_id: z8.string().optional().describe("New default configuration ID"),
|
|
3710
|
+
default_metadata: z8.record(z8.string(), z8.string()).optional().describe("New default metadata key-value pairs"),
|
|
3711
|
+
alert_emails: z8.array(z8.string()).optional().describe("New email addresses for alerts"),
|
|
3712
|
+
expires_at: z8.string().nullable().optional().describe(
|
|
3634
3713
|
"New expiration date in ISO 8601 format, or null to remove expiration"
|
|
3635
3714
|
)
|
|
3636
3715
|
},
|
|
3716
|
+
rotateApiKey: {
|
|
3717
|
+
id: z8.string().uuid().describe("API key UUID obtained from list_api_keys"),
|
|
3718
|
+
key_transition_period_ms: z8.coerce.number().int().min(18e5).optional().describe(
|
|
3719
|
+
"Overlap in milliseconds while the previous key remains valid; minimum 1,800,000 (30 minutes), for example 3,600,000 for 1 hour"
|
|
3720
|
+
)
|
|
3721
|
+
},
|
|
3637
3722
|
deleteApiKey: {
|
|
3638
|
-
id:
|
|
3723
|
+
id: z8.string().uuid().describe("The UUID of the API key to delete")
|
|
3639
3724
|
}
|
|
3640
3725
|
};
|
|
3641
|
-
var createApiKeySchema =
|
|
3726
|
+
var createApiKeySchema = z8.object(KEYS_TOOL_SCHEMAS.createApiKey).superRefine((value, ctx) => {
|
|
3642
3727
|
if (value.type === "workspace" && !value.workspace_id) {
|
|
3643
3728
|
ctx.addIssue({
|
|
3644
|
-
code:
|
|
3729
|
+
code: z8.ZodIssueCode.custom,
|
|
3645
3730
|
path: ["workspace_id"],
|
|
3646
3731
|
message: "workspace_id is required when type is 'workspace'"
|
|
3647
3732
|
});
|
|
3648
3733
|
}
|
|
3649
3734
|
if (value.sub_type === "user" && !value.user_id) {
|
|
3650
3735
|
ctx.addIssue({
|
|
3651
|
-
code:
|
|
3736
|
+
code: z8.ZodIssueCode.custom,
|
|
3652
3737
|
path: ["user_id"],
|
|
3653
3738
|
message: "user_id is required when sub_type is 'user'"
|
|
3654
3739
|
});
|
|
@@ -4004,40 +4089,71 @@ function registerKeysTools(server, service) {
|
|
|
4004
4089
|
};
|
|
4005
4090
|
}
|
|
4006
4091
|
);
|
|
4092
|
+
server.tool(
|
|
4093
|
+
"rotate_api_key",
|
|
4094
|
+
"Rotate an API key without changing its identity or scopes. The new secret is returned once and exposed to this MCP transcript, while the previous secret remains valid until key_transition_expires_at. Store the new key securely, update callers during the transition window, and never log either secret.",
|
|
4095
|
+
KEYS_TOOL_SCHEMAS.rotateApiKey,
|
|
4096
|
+
{
|
|
4097
|
+
title: "Rotate API Key",
|
|
4098
|
+
readOnlyHint: false,
|
|
4099
|
+
destructiveHint: true,
|
|
4100
|
+
idempotentHint: false,
|
|
4101
|
+
openWorldHint: true
|
|
4102
|
+
},
|
|
4103
|
+
async (params) => {
|
|
4104
|
+
const result = await service.keys.rotateApiKey(params.id, {
|
|
4105
|
+
key_transition_period_ms: params.key_transition_period_ms
|
|
4106
|
+
});
|
|
4107
|
+
return {
|
|
4108
|
+
content: [
|
|
4109
|
+
{
|
|
4110
|
+
type: "text",
|
|
4111
|
+
text: JSON.stringify({
|
|
4112
|
+
message: `Successfully rotated API key "${result.id}"`,
|
|
4113
|
+
warning: "Copy this new key now; it is returned only once. Replace callers before key_transition_expires_at and never log either key.",
|
|
4114
|
+
id: result.id,
|
|
4115
|
+
key: result.key,
|
|
4116
|
+
key_transition_expires_at: result.key_transition_expires_at
|
|
4117
|
+
})
|
|
4118
|
+
}
|
|
4119
|
+
]
|
|
4120
|
+
};
|
|
4121
|
+
}
|
|
4122
|
+
);
|
|
4007
4123
|
}
|
|
4008
4124
|
|
|
4009
4125
|
// src/tools/labels.tools.ts
|
|
4010
|
-
import { z as
|
|
4126
|
+
import { z as z9 } from "zod";
|
|
4011
4127
|
var LABELS_TOOL_SCHEMAS = {
|
|
4012
4128
|
createPromptLabel: {
|
|
4013
|
-
name:
|
|
4014
|
-
organisation_id:
|
|
4015
|
-
workspace_id:
|
|
4016
|
-
description:
|
|
4017
|
-
color_code:
|
|
4129
|
+
name: z9.string().describe("Name of the label"),
|
|
4130
|
+
organisation_id: z9.string().optional().describe("Organisation ID to create the label in"),
|
|
4131
|
+
workspace_id: z9.string().optional().describe("Workspace ID to create the label in"),
|
|
4132
|
+
description: z9.string().optional().describe("Description of the label"),
|
|
4133
|
+
color_code: z9.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe(
|
|
4018
4134
|
"Hex format, e.g. '#FF5733'. Optional \u2014 omit for default color."
|
|
4019
4135
|
)
|
|
4020
4136
|
},
|
|
4021
4137
|
listPromptLabels: {
|
|
4022
|
-
organisation_id:
|
|
4023
|
-
workspace_id:
|
|
4024
|
-
search:
|
|
4025
|
-
current_page:
|
|
4026
|
-
page_size:
|
|
4138
|
+
organisation_id: z9.string().optional().describe("Filter by organisation ID"),
|
|
4139
|
+
workspace_id: z9.string().optional().describe("Filter by workspace ID"),
|
|
4140
|
+
search: z9.string().optional().describe("Search labels by name"),
|
|
4141
|
+
current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
4142
|
+
page_size: z9.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
|
|
4027
4143
|
},
|
|
4028
4144
|
getPromptLabel: {
|
|
4029
|
-
label_id:
|
|
4030
|
-
organisation_id:
|
|
4031
|
-
workspace_id:
|
|
4145
|
+
label_id: z9.string().describe("Label ID to retrieve"),
|
|
4146
|
+
organisation_id: z9.string().optional().describe("Organisation ID for filtering"),
|
|
4147
|
+
workspace_id: z9.string().optional().describe("Workspace ID for filtering")
|
|
4032
4148
|
},
|
|
4033
4149
|
updatePromptLabel: {
|
|
4034
|
-
label_id:
|
|
4035
|
-
name:
|
|
4036
|
-
description:
|
|
4037
|
-
color_code:
|
|
4150
|
+
label_id: z9.string().describe("Label ID to update"),
|
|
4151
|
+
name: z9.string().optional().describe("New name for the label"),
|
|
4152
|
+
description: z9.string().optional().describe("New description"),
|
|
4153
|
+
color_code: z9.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("New hex color code (e.g., '#FF5733')")
|
|
4038
4154
|
},
|
|
4039
4155
|
deletePromptLabel: {
|
|
4040
|
-
label_id:
|
|
4156
|
+
label_id: z9.string().describe("Label ID to delete")
|
|
4041
4157
|
}
|
|
4042
4158
|
};
|
|
4043
4159
|
function registerLabelsTools(server, service) {
|
|
@@ -4177,86 +4293,86 @@ function registerLabelsTools(server, service) {
|
|
|
4177
4293
|
}
|
|
4178
4294
|
|
|
4179
4295
|
// src/tools/limits.tools.ts
|
|
4180
|
-
import { z as
|
|
4181
|
-
var conditionSchema =
|
|
4182
|
-
field:
|
|
4296
|
+
import { z as z10 } from "zod";
|
|
4297
|
+
var conditionSchema = z10.object({
|
|
4298
|
+
field: z10.string().describe(
|
|
4183
4299
|
"The field to match on (e.g., 'virtual_key', 'api_key', 'user_id', 'metadata.key')"
|
|
4184
4300
|
),
|
|
4185
|
-
operator:
|
|
4186
|
-
value:
|
|
4301
|
+
operator: z10.string().describe("The comparison operator (e.g., 'is', 'contains', 'is_not')"),
|
|
4302
|
+
value: z10.string().describe("The value to match against")
|
|
4187
4303
|
});
|
|
4188
4304
|
var LIMITS_TOOL_SCHEMAS = {
|
|
4189
4305
|
listRateLimits: {
|
|
4190
|
-
workspace_id:
|
|
4306
|
+
workspace_id: z10.string().optional().describe("Filter rate limits by workspace ID")
|
|
4191
4307
|
},
|
|
4192
4308
|
getRateLimit: {
|
|
4193
|
-
id:
|
|
4309
|
+
id: z10.string().describe("The unique identifier of the rate limit")
|
|
4194
4310
|
},
|
|
4195
4311
|
createRateLimit: {
|
|
4196
|
-
conditions:
|
|
4312
|
+
conditions: z10.array(conditionSchema).describe(
|
|
4197
4313
|
"Array of conditions that determine which requests this rate limit applies to"
|
|
4198
4314
|
),
|
|
4199
|
-
group_by:
|
|
4315
|
+
group_by: z10.array(z10.string()).describe(
|
|
4200
4316
|
"Array of fields to group the rate limit by (e.g., ['virtual_key'], ['api_key', 'user_id'])"
|
|
4201
4317
|
),
|
|
4202
|
-
type:
|
|
4203
|
-
unit:
|
|
4318
|
+
type: z10.enum(["requests", "tokens"]).describe("What to rate limit: 'requests' or 'tokens'"),
|
|
4319
|
+
unit: z10.enum(["rpm", "rph", "rpd"]).describe(
|
|
4204
4320
|
"Time unit: 'rpm' (per minute), 'rph' (per hour), or 'rpd' (per day)"
|
|
4205
4321
|
),
|
|
4206
|
-
value:
|
|
4207
|
-
name:
|
|
4208
|
-
workspace_id:
|
|
4209
|
-
organisation_id:
|
|
4322
|
+
value: z10.coerce.number().positive().describe("The maximum allowed value per unit (e.g., 100 rpm)"),
|
|
4323
|
+
name: z10.string().optional().describe("Optional name for the rate limit"),
|
|
4324
|
+
workspace_id: z10.string().optional().describe("Workspace ID to scope the limit to"),
|
|
4325
|
+
organisation_id: z10.string().optional().describe("Organisation ID to scope the limit to")
|
|
4210
4326
|
},
|
|
4211
4327
|
updateRateLimit: {
|
|
4212
|
-
id:
|
|
4213
|
-
name:
|
|
4214
|
-
unit:
|
|
4328
|
+
id: z10.string().describe("The unique identifier of the rate limit"),
|
|
4329
|
+
name: z10.string().optional().describe("New name for the rate limit"),
|
|
4330
|
+
unit: z10.enum(["rpm", "rph", "rpd"]).optional().describe(
|
|
4215
4331
|
"New time unit: 'rpm' (per minute), 'rph' (per hour), or 'rpd' (per day)"
|
|
4216
4332
|
),
|
|
4217
|
-
value:
|
|
4333
|
+
value: z10.coerce.number().positive().optional().describe("New maximum allowed value per unit")
|
|
4218
4334
|
},
|
|
4219
4335
|
deleteRateLimit: {
|
|
4220
|
-
id:
|
|
4336
|
+
id: z10.string().describe("The unique identifier of the rate limit")
|
|
4221
4337
|
},
|
|
4222
4338
|
listUsageLimits: {
|
|
4223
|
-
workspace_id:
|
|
4339
|
+
workspace_id: z10.string().optional().describe("Filter usage limits by workspace ID")
|
|
4224
4340
|
},
|
|
4225
4341
|
getUsageLimit: {
|
|
4226
|
-
id:
|
|
4342
|
+
id: z10.string().describe("The unique identifier of the usage limit")
|
|
4227
4343
|
},
|
|
4228
4344
|
createUsageLimit: {
|
|
4229
|
-
conditions:
|
|
4345
|
+
conditions: z10.array(conditionSchema).describe(
|
|
4230
4346
|
"Array of conditions that determine which requests this usage limit applies to"
|
|
4231
4347
|
),
|
|
4232
|
-
group_by:
|
|
4348
|
+
group_by: z10.array(z10.string()).describe(
|
|
4233
4349
|
"Array of fields to group the usage limit by (e.g., ['virtual_key'], ['api_key', 'user_id'])"
|
|
4234
4350
|
),
|
|
4235
|
-
type:
|
|
4236
|
-
credit_limit:
|
|
4237
|
-
name:
|
|
4238
|
-
alert_threshold:
|
|
4239
|
-
periodic_reset:
|
|
4240
|
-
workspace_id:
|
|
4241
|
-
organisation_id:
|
|
4351
|
+
type: z10.enum(["cost", "tokens"]).describe("What to limit: 'cost' (in dollars) or 'tokens'"),
|
|
4352
|
+
credit_limit: z10.coerce.number().positive().describe("The maximum allowed usage (cost in dollars or token count)"),
|
|
4353
|
+
name: z10.string().optional().describe("Optional name for the usage limit"),
|
|
4354
|
+
alert_threshold: z10.coerce.number().optional().describe("Percentage threshold (0-100) at which to send an alert"),
|
|
4355
|
+
periodic_reset: z10.enum(["monthly", "weekly"]).optional().describe("Automatically reset usage counters on this schedule"),
|
|
4356
|
+
workspace_id: z10.string().optional().describe("Workspace ID to scope the limit to"),
|
|
4357
|
+
organisation_id: z10.string().optional().describe("Organisation ID to scope the limit to")
|
|
4242
4358
|
},
|
|
4243
4359
|
updateUsageLimit: {
|
|
4244
|
-
id:
|
|
4245
|
-
name:
|
|
4246
|
-
credit_limit:
|
|
4247
|
-
alert_threshold:
|
|
4248
|
-
periodic_reset:
|
|
4249
|
-
reset_usage_for_value:
|
|
4360
|
+
id: z10.string().describe("The unique identifier of the usage limit"),
|
|
4361
|
+
name: z10.string().optional().describe("New name for the usage limit"),
|
|
4362
|
+
credit_limit: z10.coerce.number().positive().optional().describe("New maximum allowed usage value"),
|
|
4363
|
+
alert_threshold: z10.coerce.number().optional().describe("New alert threshold percentage (0-100)"),
|
|
4364
|
+
periodic_reset: z10.enum(["monthly", "weekly"]).optional().describe("New periodic reset schedule"),
|
|
4365
|
+
reset_usage_for_value: z10.string().optional().describe("Reset usage counters for a specific group_by value")
|
|
4250
4366
|
},
|
|
4251
4367
|
deleteUsageLimit: {
|
|
4252
|
-
id:
|
|
4368
|
+
id: z10.string().describe("The unique identifier of the usage limit")
|
|
4253
4369
|
},
|
|
4254
4370
|
listUsageLimitEntities: {
|
|
4255
|
-
limit_id:
|
|
4371
|
+
limit_id: z10.string().describe("Usage limit policy ID")
|
|
4256
4372
|
},
|
|
4257
4373
|
resetUsageLimitEntity: {
|
|
4258
|
-
limit_id:
|
|
4259
|
-
entity_id:
|
|
4374
|
+
limit_id: z10.string().describe("Usage limit policy ID"),
|
|
4375
|
+
entity_id: z10.string().describe("Entity ID to reset usage for")
|
|
4260
4376
|
}
|
|
4261
4377
|
};
|
|
4262
4378
|
function formatRateLimit(limit) {
|
|
@@ -4562,8 +4678,8 @@ function registerLimitsTools(server, service) {
|
|
|
4562
4678
|
}
|
|
4563
4679
|
|
|
4564
4680
|
// src/tools/logging.tools.ts
|
|
4565
|
-
import { z as
|
|
4566
|
-
var logExportFieldSchema =
|
|
4681
|
+
import { z as z11 } from "zod";
|
|
4682
|
+
var logExportFieldSchema = z11.enum([
|
|
4567
4683
|
"id",
|
|
4568
4684
|
"trace_id",
|
|
4569
4685
|
"created_at",
|
|
@@ -4587,64 +4703,64 @@ var logExportFieldSchema = z10.enum([
|
|
|
4587
4703
|
]);
|
|
4588
4704
|
var LOGGING_TOOL_SCHEMAS = {
|
|
4589
4705
|
insertLog: {
|
|
4590
|
-
request_url:
|
|
4591
|
-
request_provider:
|
|
4592
|
-
request_method:
|
|
4593
|
-
request_headers:
|
|
4594
|
-
request_body:
|
|
4595
|
-
response_status:
|
|
4596
|
-
response_headers:
|
|
4597
|
-
response_body:
|
|
4598
|
-
response_time:
|
|
4599
|
-
streaming_mode:
|
|
4600
|
-
metadata_organization:
|
|
4601
|
-
metadata_user:
|
|
4602
|
-
metadata_trace_id:
|
|
4603
|
-
metadata_span_id:
|
|
4604
|
-
metadata_span_name:
|
|
4605
|
-
metadata_parent_span_id:
|
|
4606
|
-
metadata_custom:
|
|
4706
|
+
request_url: z11.string().optional().describe("The endpoint URL being called"),
|
|
4707
|
+
request_provider: z11.string().optional().describe("AI provider name (e.g., 'openai', 'anthropic')"),
|
|
4708
|
+
request_method: z11.string().optional().default("post").describe("HTTP method used (defaults to 'post')"),
|
|
4709
|
+
request_headers: z11.record(z11.string(), z11.string()).optional().describe("Request headers as key-value pairs"),
|
|
4710
|
+
request_body: z11.record(z11.string(), z11.unknown()).optional().describe("Request payload/body"),
|
|
4711
|
+
response_status: z11.coerce.number().optional().default(200).describe("HTTP response status code (defaults to 200)"),
|
|
4712
|
+
response_headers: z11.record(z11.string(), z11.string()).optional().describe("Response headers as key-value pairs"),
|
|
4713
|
+
response_body: z11.record(z11.string(), z11.unknown()).optional().describe("Response payload/body"),
|
|
4714
|
+
response_time: z11.coerce.number().optional().describe("Response latency in milliseconds"),
|
|
4715
|
+
streaming_mode: z11.boolean().optional().default(false).describe("Whether the response was streamed"),
|
|
4716
|
+
metadata_organization: z11.string().optional().describe("Organization identifier for the log"),
|
|
4717
|
+
metadata_user: z11.string().optional().describe("User identifier for the log"),
|
|
4718
|
+
metadata_trace_id: z11.string().optional().describe("Trace ID for distributed tracing"),
|
|
4719
|
+
metadata_span_id: z11.string().optional().describe("Span ID for tracing"),
|
|
4720
|
+
metadata_span_name: z11.string().optional().describe("Span name for tracing"),
|
|
4721
|
+
metadata_parent_span_id: z11.string().optional().describe("Parent span ID for tracing"),
|
|
4722
|
+
metadata_custom: z11.record(z11.string(), z11.unknown()).optional().describe("Additional custom metadata key-value pairs")
|
|
4607
4723
|
},
|
|
4608
4724
|
createLogExport: {
|
|
4609
|
-
workspace_id:
|
|
4610
|
-
description:
|
|
4611
|
-
time_min:
|
|
4725
|
+
workspace_id: z11.string().optional().describe("Workspace ID for the export"),
|
|
4726
|
+
description: z11.string().optional().describe("Human-readable description for the export job"),
|
|
4727
|
+
time_min: z11.string().describe(
|
|
4612
4728
|
"Minimum time filter in date format (e.g., '2024-01-01' or ISO 8601)"
|
|
4613
4729
|
),
|
|
4614
|
-
time_max:
|
|
4730
|
+
time_max: z11.string().describe(
|
|
4615
4731
|
"Maximum time filter in date format (e.g., '2024-01-31' or ISO 8601)"
|
|
4616
4732
|
),
|
|
4617
|
-
cost_min:
|
|
4618
|
-
cost_max:
|
|
4619
|
-
total_units_min:
|
|
4620
|
-
total_units_max:
|
|
4621
|
-
ai_model:
|
|
4622
|
-
requested_fields:
|
|
4733
|
+
cost_min: z11.coerce.number().optional().describe("Minimum cost filter"),
|
|
4734
|
+
cost_max: z11.coerce.number().optional().describe("Maximum cost filter"),
|
|
4735
|
+
total_units_min: z11.coerce.number().optional().describe("Minimum total units (tokens) filter"),
|
|
4736
|
+
total_units_max: z11.coerce.number().optional().describe("Maximum total units (tokens) filter"),
|
|
4737
|
+
ai_model: z11.array(z11.string()).optional().describe("Filter by specific AI model names"),
|
|
4738
|
+
requested_fields: z11.array(logExportFieldSchema).describe(
|
|
4623
4739
|
"Fields to include in export: id, trace_id, created_at, request, response, is_success, ai_org, ai_model, req_units, res_units, total_units, request_url, cost, cost_currency, response_time, response_status_code, mode, config, prompt_slug, metadata"
|
|
4624
4740
|
)
|
|
4625
4741
|
},
|
|
4626
4742
|
listLogExports: {
|
|
4627
|
-
workspace_id:
|
|
4743
|
+
workspace_id: z11.string().describe("Workspace ID to list exports for (required)")
|
|
4628
4744
|
},
|
|
4629
4745
|
getLogExport: {
|
|
4630
|
-
export_id:
|
|
4746
|
+
export_id: z11.string().describe("The unique ID of the log export")
|
|
4631
4747
|
},
|
|
4632
4748
|
startLogExport: {
|
|
4633
|
-
export_id:
|
|
4749
|
+
export_id: z11.string().describe("The unique ID of the log export to start")
|
|
4634
4750
|
},
|
|
4635
4751
|
cancelLogExport: {
|
|
4636
|
-
export_id:
|
|
4752
|
+
export_id: z11.string().describe("The unique ID of the log export to cancel")
|
|
4637
4753
|
},
|
|
4638
4754
|
downloadLogExport: {
|
|
4639
|
-
export_id:
|
|
4755
|
+
export_id: z11.string().describe("The unique ID of the log export to download")
|
|
4640
4756
|
},
|
|
4641
4757
|
updateLogExport: {
|
|
4642
|
-
export_id:
|
|
4643
|
-
workspace_id:
|
|
4644
|
-
time_of_generation_max:
|
|
4758
|
+
export_id: z11.string().describe("The unique ID of the log export to update"),
|
|
4759
|
+
workspace_id: z11.string().optional().describe("Workspace ID for the export"),
|
|
4760
|
+
time_of_generation_max: z11.string().optional().describe(
|
|
4645
4761
|
"Maximum time filter in date format (e.g., '2024-07-25' or ISO 8601)"
|
|
4646
4762
|
),
|
|
4647
|
-
requested_fields:
|
|
4763
|
+
requested_fields: z11.array(logExportFieldSchema).optional().describe(
|
|
4648
4764
|
"Fields to include in export: id, trace_id, created_at, request, response, is_success, ai_org, ai_model, req_units, res_units, total_units, request_url, cost, cost_currency, response_time, response_status_code, mode, config, prompt_slug, metadata"
|
|
4649
4765
|
)
|
|
4650
4766
|
}
|
|
@@ -4885,73 +5001,73 @@ function registerLoggingTools(server, service) {
|
|
|
4885
5001
|
}
|
|
4886
5002
|
|
|
4887
5003
|
// src/tools/mcp-integrations.tools.ts
|
|
4888
|
-
import { z as
|
|
5004
|
+
import { z as z12 } from "zod";
|
|
4889
5005
|
var MCP_INTEGRATIONS_TOOL_SCHEMAS = {
|
|
4890
5006
|
listMcpIntegrations: {
|
|
4891
|
-
current_page:
|
|
4892
|
-
page_size:
|
|
4893
|
-
workspace_id:
|
|
5007
|
+
current_page: z12.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
5008
|
+
page_size: z12.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
|
|
5009
|
+
workspace_id: z12.string().optional().describe("Filter by workspace ID")
|
|
4894
5010
|
},
|
|
4895
5011
|
createMcpIntegration: {
|
|
4896
|
-
name:
|
|
4897
|
-
url:
|
|
4898
|
-
auth_type:
|
|
5012
|
+
name: z12.string().describe("Display name for the MCP integration"),
|
|
5013
|
+
url: z12.string().describe("URL endpoint of the MCP server to integrate"),
|
|
5014
|
+
auth_type: z12.enum(["oauth_auto", "headers", "none"]).describe(
|
|
4899
5015
|
"Authentication type: 'none', 'headers' (custom headers), or 'oauth_auto' (OAuth)"
|
|
4900
5016
|
),
|
|
4901
|
-
transport:
|
|
5017
|
+
transport: z12.enum(["http", "sse"]).describe(
|
|
4902
5018
|
"MCP transport protocol: 'http' (streamable HTTP) or 'sse' (server-sent events)"
|
|
4903
5019
|
),
|
|
4904
|
-
slug:
|
|
4905
|
-
description:
|
|
4906
|
-
custom_headers:
|
|
5020
|
+
slug: z12.string().optional().describe("Custom slug. Auto-generated if omitted"),
|
|
5021
|
+
description: z12.string().optional().describe("Description of the MCP integration"),
|
|
5022
|
+
custom_headers: z12.record(z12.string(), z12.string()).optional().describe(
|
|
4907
5023
|
'Custom headers for authentication (e.g. { "Authorization": "Bearer xxx" }). Sent via configurations.custom_headers'
|
|
4908
5024
|
),
|
|
4909
|
-
workspace_id:
|
|
5025
|
+
workspace_id: z12.string().optional().describe(
|
|
4910
5026
|
"Workspace ID \u2014 required when using organization admin API keys"
|
|
4911
5027
|
)
|
|
4912
5028
|
},
|
|
4913
5029
|
getMcpIntegration: {
|
|
4914
|
-
id:
|
|
5030
|
+
id: z12.string().describe("The MCP integration ID or slug to retrieve")
|
|
4915
5031
|
},
|
|
4916
5032
|
updateMcpIntegration: {
|
|
4917
|
-
id:
|
|
4918
|
-
name:
|
|
4919
|
-
description:
|
|
4920
|
-
url:
|
|
4921
|
-
auth_type:
|
|
4922
|
-
transport:
|
|
4923
|
-
custom_headers:
|
|
5033
|
+
id: z12.string().describe("The MCP integration ID or slug to update"),
|
|
5034
|
+
name: z12.string().optional().describe("New display name"),
|
|
5035
|
+
description: z12.string().optional().describe("New description"),
|
|
5036
|
+
url: z12.string().optional().describe("New URL endpoint"),
|
|
5037
|
+
auth_type: z12.enum(["oauth_auto", "headers", "none"]).optional().describe("New authentication type"),
|
|
5038
|
+
transport: z12.enum(["http", "sse"]).optional().describe("New transport protocol"),
|
|
5039
|
+
custom_headers: z12.record(z12.string(), z12.string()).optional().describe(
|
|
4924
5040
|
"New custom headers for authentication. Sent via configurations.custom_headers"
|
|
4925
5041
|
)
|
|
4926
5042
|
},
|
|
4927
5043
|
deleteMcpIntegration: {
|
|
4928
|
-
id:
|
|
5044
|
+
id: z12.string().describe("The MCP integration ID or slug to delete")
|
|
4929
5045
|
},
|
|
4930
5046
|
getMcpIntegrationMetadata: {
|
|
4931
|
-
id:
|
|
5047
|
+
id: z12.string().describe("The MCP integration ID or slug")
|
|
4932
5048
|
},
|
|
4933
5049
|
listMcpIntegrationCapabilities: {
|
|
4934
|
-
id:
|
|
5050
|
+
id: z12.string().describe("The MCP integration ID or slug")
|
|
4935
5051
|
},
|
|
4936
5052
|
updateMcpIntegrationCapabilities: {
|
|
4937
|
-
id:
|
|
4938
|
-
capabilities:
|
|
4939
|
-
|
|
4940
|
-
name:
|
|
4941
|
-
type:
|
|
4942
|
-
enabled:
|
|
5053
|
+
id: z12.string().describe("The MCP integration ID or slug"),
|
|
5054
|
+
capabilities: z12.array(
|
|
5055
|
+
z12.object({
|
|
5056
|
+
name: z12.string().describe("Capability name"),
|
|
5057
|
+
type: z12.enum(["tool", "prompt", "resource"]).describe("Capability type"),
|
|
5058
|
+
enabled: z12.boolean().describe("Whether to enable the capability")
|
|
4943
5059
|
})
|
|
4944
5060
|
).min(1).describe("Array of capability updates")
|
|
4945
5061
|
},
|
|
4946
5062
|
listMcpIntegrationWorkspaces: {
|
|
4947
|
-
id:
|
|
5063
|
+
id: z12.string().describe("The MCP integration ID or slug")
|
|
4948
5064
|
},
|
|
4949
5065
|
updateMcpIntegrationWorkspaces: {
|
|
4950
|
-
id:
|
|
4951
|
-
workspaces:
|
|
4952
|
-
|
|
4953
|
-
id:
|
|
4954
|
-
enabled:
|
|
5066
|
+
id: z12.string().describe("The MCP integration ID or slug"),
|
|
5067
|
+
workspaces: z12.array(
|
|
5068
|
+
z12.object({
|
|
5069
|
+
id: z12.string().describe("Workspace ID"),
|
|
5070
|
+
enabled: z12.boolean().describe("Whether workspace has access")
|
|
4955
5071
|
})
|
|
4956
5072
|
).min(1).describe("Array of workspace access updates")
|
|
4957
5073
|
}
|
|
@@ -5243,7 +5359,7 @@ function registerMcpIntegrationsTools(server, service) {
|
|
|
5243
5359
|
}
|
|
5244
5360
|
|
|
5245
5361
|
// src/tools/mcp-servers.tools.ts
|
|
5246
|
-
import { z as
|
|
5362
|
+
import { z as z13 } from "zod";
|
|
5247
5363
|
|
|
5248
5364
|
// src/tools/utils.ts
|
|
5249
5365
|
function formatFullName(firstName, lastName) {
|
|
@@ -5253,56 +5369,56 @@ function formatFullName(firstName, lastName) {
|
|
|
5253
5369
|
// src/tools/mcp-servers.tools.ts
|
|
5254
5370
|
var MCP_SERVERS_TOOL_SCHEMAS = {
|
|
5255
5371
|
listMcpServers: {
|
|
5256
|
-
current_page:
|
|
5257
|
-
page_size:
|
|
5258
|
-
workspace_id:
|
|
5372
|
+
current_page: z13.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
5373
|
+
page_size: z13.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
|
|
5374
|
+
workspace_id: z13.string().optional().describe("Filter by workspace ID")
|
|
5259
5375
|
},
|
|
5260
5376
|
createMcpServer: {
|
|
5261
|
-
name:
|
|
5262
|
-
mcp_integration_id:
|
|
5263
|
-
slug:
|
|
5264
|
-
description:
|
|
5377
|
+
name: z13.string().describe("Display name for the MCP server"),
|
|
5378
|
+
mcp_integration_id: z13.string().describe("ID or slug of the MCP integration this server belongs to"),
|
|
5379
|
+
slug: z13.string().optional().describe("Custom slug. Auto-generated if omitted"),
|
|
5380
|
+
description: z13.string().optional().describe("Description of the MCP server")
|
|
5265
5381
|
},
|
|
5266
5382
|
getMcpServer: {
|
|
5267
|
-
id:
|
|
5383
|
+
id: z13.string().describe("The MCP server ID or slug to retrieve")
|
|
5268
5384
|
},
|
|
5269
5385
|
updateMcpServer: {
|
|
5270
|
-
id:
|
|
5271
|
-
name:
|
|
5272
|
-
description:
|
|
5386
|
+
id: z13.string().describe("The MCP server ID or slug to update"),
|
|
5387
|
+
name: z13.string().optional().describe("New display name"),
|
|
5388
|
+
description: z13.string().optional().describe("New description")
|
|
5273
5389
|
},
|
|
5274
5390
|
deleteMcpServer: {
|
|
5275
|
-
id:
|
|
5391
|
+
id: z13.string().describe("The MCP server ID or slug to delete")
|
|
5276
5392
|
},
|
|
5277
5393
|
testMcpServer: {
|
|
5278
|
-
id:
|
|
5394
|
+
id: z13.string().describe("The MCP server ID or slug to test")
|
|
5279
5395
|
},
|
|
5280
5396
|
listMcpServerCapabilities: {
|
|
5281
|
-
id:
|
|
5282
|
-
current_page:
|
|
5283
|
-
page_size:
|
|
5397
|
+
id: z13.string().describe("The MCP server ID or slug"),
|
|
5398
|
+
current_page: z13.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
5399
|
+
page_size: z13.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
5284
5400
|
},
|
|
5285
5401
|
updateMcpServerCapabilities: {
|
|
5286
|
-
id:
|
|
5287
|
-
capabilities:
|
|
5288
|
-
|
|
5289
|
-
name:
|
|
5290
|
-
type:
|
|
5291
|
-
enabled:
|
|
5402
|
+
id: z13.string().describe("The MCP server ID or slug"),
|
|
5403
|
+
capabilities: z13.array(
|
|
5404
|
+
z13.object({
|
|
5405
|
+
name: z13.string().describe("Capability name"),
|
|
5406
|
+
type: z13.enum(["tool", "prompt", "resource"]).describe("Capability type"),
|
|
5407
|
+
enabled: z13.boolean().describe("Whether to enable the capability")
|
|
5292
5408
|
})
|
|
5293
5409
|
).min(1).describe("Array of capability updates")
|
|
5294
5410
|
},
|
|
5295
5411
|
listMcpServerUserAccess: {
|
|
5296
|
-
id:
|
|
5297
|
-
current_page:
|
|
5298
|
-
page_size:
|
|
5412
|
+
id: z13.string().describe("The MCP server ID or slug"),
|
|
5413
|
+
current_page: z13.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
5414
|
+
page_size: z13.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
5299
5415
|
},
|
|
5300
5416
|
updateMcpServerUserAccess: {
|
|
5301
|
-
id:
|
|
5302
|
-
users:
|
|
5303
|
-
|
|
5304
|
-
user_id:
|
|
5305
|
-
enabled:
|
|
5417
|
+
id: z13.string().describe("The MCP server ID or slug"),
|
|
5418
|
+
users: z13.array(
|
|
5419
|
+
z13.object({
|
|
5420
|
+
user_id: z13.string().describe("User ID"),
|
|
5421
|
+
enabled: z13.boolean().describe("Whether user has access")
|
|
5306
5422
|
})
|
|
5307
5423
|
).min(1).describe("Array of user access updates")
|
|
5308
5424
|
}
|
|
@@ -5546,40 +5662,40 @@ function registerMcpServersTools(server, service) {
|
|
|
5546
5662
|
}
|
|
5547
5663
|
|
|
5548
5664
|
// src/tools/partials.tools.ts
|
|
5549
|
-
import { z as
|
|
5665
|
+
import { z as z14 } from "zod";
|
|
5550
5666
|
var PARTIALS_TOOL_SCHEMAS = {
|
|
5551
5667
|
createPromptPartial: {
|
|
5552
|
-
name:
|
|
5553
|
-
string:
|
|
5554
|
-
workspace_id:
|
|
5668
|
+
name: z14.string().describe("Display name for the partial"),
|
|
5669
|
+
string: z14.string().describe("The partial content/template string"),
|
|
5670
|
+
workspace_id: z14.string().optional().describe(
|
|
5555
5671
|
"Workspace ID to create partial in (required for org-level API keys)"
|
|
5556
5672
|
),
|
|
5557
|
-
version_description:
|
|
5673
|
+
version_description: z14.string().optional().describe("Description for this version")
|
|
5558
5674
|
},
|
|
5559
5675
|
listPromptPartials: {
|
|
5560
|
-
collection_id:
|
|
5676
|
+
collection_id: z14.string().optional().describe(
|
|
5561
5677
|
"Filter by collection ID. Optional \u2014 omit to list all partials across collections"
|
|
5562
5678
|
)
|
|
5563
5679
|
},
|
|
5564
5680
|
getPromptPartial: {
|
|
5565
|
-
prompt_partial_id:
|
|
5681
|
+
prompt_partial_id: z14.string().describe("Prompt partial ID or slug to retrieve")
|
|
5566
5682
|
},
|
|
5567
5683
|
updatePromptPartial: {
|
|
5568
|
-
prompt_partial_id:
|
|
5569
|
-
name:
|
|
5570
|
-
string:
|
|
5571
|
-
description:
|
|
5572
|
-
status:
|
|
5684
|
+
prompt_partial_id: z14.string().describe("Prompt partial ID or slug to update"),
|
|
5685
|
+
name: z14.string().optional().describe("New display name for the partial"),
|
|
5686
|
+
string: z14.string().optional().describe("New content for the partial"),
|
|
5687
|
+
description: z14.string().optional().describe("Description for this version"),
|
|
5688
|
+
status: z14.enum(["active", "archived"]).optional().describe("New status for the partial")
|
|
5573
5689
|
},
|
|
5574
5690
|
deletePromptPartial: {
|
|
5575
|
-
prompt_partial_id:
|
|
5691
|
+
prompt_partial_id: z14.string().describe("Prompt partial ID or slug to delete")
|
|
5576
5692
|
},
|
|
5577
5693
|
listPartialVersions: {
|
|
5578
|
-
prompt_partial_id:
|
|
5694
|
+
prompt_partial_id: z14.string().describe("Prompt partial ID or slug to list versions for")
|
|
5579
5695
|
},
|
|
5580
5696
|
publishPartial: {
|
|
5581
|
-
prompt_partial_id:
|
|
5582
|
-
version:
|
|
5697
|
+
prompt_partial_id: z14.string().describe("Prompt partial ID or slug"),
|
|
5698
|
+
version: z14.coerce.number().positive().describe("Version number to publish as default")
|
|
5583
5699
|
}
|
|
5584
5700
|
};
|
|
5585
5701
|
function registerPartialsTools(server, service) {
|
|
@@ -5765,57 +5881,57 @@ function registerPartialsTools(server, service) {
|
|
|
5765
5881
|
}
|
|
5766
5882
|
|
|
5767
5883
|
// src/tools/prompts.tools.ts
|
|
5768
|
-
import { z as
|
|
5884
|
+
import { z as z16 } from "zod";
|
|
5769
5885
|
|
|
5770
5886
|
// src/lib/schemas.ts
|
|
5771
|
-
import { z as
|
|
5772
|
-
var PromptFunctionSchema =
|
|
5773
|
-
name:
|
|
5774
|
-
description:
|
|
5775
|
-
parameters:
|
|
5887
|
+
import { z as z15 } from "zod";
|
|
5888
|
+
var PromptFunctionSchema = z15.object({
|
|
5889
|
+
name: z15.string().describe("Function name"),
|
|
5890
|
+
description: z15.string().optional().describe("Function description"),
|
|
5891
|
+
parameters: z15.record(z15.string(), z15.unknown()).optional().describe("Function parameters schema")
|
|
5776
5892
|
});
|
|
5777
|
-
var PromptToolSchema =
|
|
5778
|
-
type:
|
|
5893
|
+
var PromptToolSchema = z15.object({
|
|
5894
|
+
type: z15.literal("function").describe("Tool type"),
|
|
5779
5895
|
function: PromptFunctionSchema.describe("Function definition")
|
|
5780
5896
|
});
|
|
5781
|
-
var HyperparametersSchema =
|
|
5782
|
-
max_tokens:
|
|
5783
|
-
temperature:
|
|
5784
|
-
top_p:
|
|
5785
|
-
top_k:
|
|
5786
|
-
presence_penalty:
|
|
5787
|
-
frequency_penalty:
|
|
5788
|
-
stop:
|
|
5897
|
+
var HyperparametersSchema = z15.object({
|
|
5898
|
+
max_tokens: z15.coerce.number().positive().optional().describe("Maximum tokens to generate"),
|
|
5899
|
+
temperature: z15.coerce.number().min(0).max(2).optional().describe("Sampling temperature (0-2)"),
|
|
5900
|
+
top_p: z15.coerce.number().min(0).max(1).optional().describe("Top-p sampling (0-1)"),
|
|
5901
|
+
top_k: z15.coerce.number().positive().optional().describe("Top-k sampling"),
|
|
5902
|
+
presence_penalty: z15.coerce.number().min(-2).max(2).optional().describe("Presence penalty (-2 to 2)"),
|
|
5903
|
+
frequency_penalty: z15.coerce.number().min(-2).max(2).optional().describe("Frequency penalty (-2 to 2)"),
|
|
5904
|
+
stop: z15.array(z15.string()).optional().describe("Stop sequences")
|
|
5789
5905
|
});
|
|
5790
|
-
var PromptAppIdentifierSchema =
|
|
5906
|
+
var PromptAppIdentifierSchema = z15.string().min(1).describe(
|
|
5791
5907
|
"App identifier (REQUIRED). Use your deployed app name, for example 'hourlink' or 'support-console'."
|
|
5792
5908
|
);
|
|
5793
|
-
var PromptEnvironmentIdentifierSchema =
|
|
5909
|
+
var PromptEnvironmentIdentifierSchema = z15.string().min(1).describe(
|
|
5794
5910
|
"Environment identifier (REQUIRED). Use your environment name, for example 'dev', 'staging', 'prod', or 'qa'."
|
|
5795
5911
|
);
|
|
5796
|
-
var BillingMetadataSchema =
|
|
5797
|
-
client_id:
|
|
5912
|
+
var BillingMetadataSchema = z15.object({
|
|
5913
|
+
client_id: z15.string().describe("Client ID for billing attribution (REQUIRED)"),
|
|
5798
5914
|
app: PromptAppIdentifierSchema,
|
|
5799
5915
|
env: PromptEnvironmentIdentifierSchema,
|
|
5800
|
-
project_id:
|
|
5801
|
-
feature:
|
|
5916
|
+
project_id: z15.string().optional().describe("Project ID for granular billing"),
|
|
5917
|
+
feature: z15.string().optional().describe("Feature name for tracking")
|
|
5802
5918
|
});
|
|
5803
|
-
var ToolChoiceSchema =
|
|
5804
|
-
mode:
|
|
5919
|
+
var ToolChoiceSchema = z15.object({
|
|
5920
|
+
mode: z15.enum(["auto", "none", "function"]).describe(
|
|
5805
5921
|
"Tool choice mode: auto lets the model decide, none disables tool use, function forces one function by name"
|
|
5806
5922
|
),
|
|
5807
|
-
function_name:
|
|
5923
|
+
function_name: z15.string().optional().describe("Required when mode is 'function'; ignored otherwise")
|
|
5808
5924
|
}).superRefine((value, ctx) => {
|
|
5809
5925
|
if (value.mode === "function" && !value.function_name) {
|
|
5810
5926
|
ctx.addIssue({
|
|
5811
|
-
code:
|
|
5927
|
+
code: z15.ZodIssueCode.custom,
|
|
5812
5928
|
path: ["function_name"],
|
|
5813
5929
|
message: "function_name is required when mode is 'function'"
|
|
5814
5930
|
});
|
|
5815
5931
|
}
|
|
5816
5932
|
if (value.mode !== "function" && value.function_name !== void 0) {
|
|
5817
5933
|
ctx.addIssue({
|
|
5818
|
-
code:
|
|
5934
|
+
code: z15.ZodIssueCode.custom,
|
|
5819
5935
|
path: ["function_name"],
|
|
5820
5936
|
message: "function_name is only allowed when mode is 'function'"
|
|
5821
5937
|
});
|
|
@@ -5837,98 +5953,98 @@ function toPromptToolChoice(toolChoice) {
|
|
|
5837
5953
|
}
|
|
5838
5954
|
|
|
5839
5955
|
// src/tools/prompts.tools.ts
|
|
5840
|
-
var PROMPT_VARIABLES_SCHEMA =
|
|
5841
|
-
var PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA =
|
|
5842
|
-
type:
|
|
5843
|
-
text:
|
|
5956
|
+
var PROMPT_VARIABLES_SCHEMA = z16.record(z16.string(), z16.union([z16.string(), z16.coerce.number(), z16.boolean()])).describe("Variable values to substitute into the template");
|
|
5957
|
+
var PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA = z16.object({
|
|
5958
|
+
type: z16.string().describe("Content block type"),
|
|
5959
|
+
text: z16.string().optional().describe("Text content for text-based blocks")
|
|
5844
5960
|
}).passthrough().describe("Content block within a structured chat message");
|
|
5845
|
-
var PROMPT_TEMPLATE_MESSAGE_SCHEMA =
|
|
5846
|
-
role:
|
|
5847
|
-
content:
|
|
5961
|
+
var PROMPT_TEMPLATE_MESSAGE_SCHEMA = z16.object({
|
|
5962
|
+
role: z16.enum(["system", "user", "assistant"]).describe("Message role in the chat template"),
|
|
5963
|
+
content: z16.array(PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA).describe("Message content blocks")
|
|
5848
5964
|
}).passthrough().describe("Structured chat message in a prompt template");
|
|
5849
5965
|
var PROMPTS_TOOL_SCHEMAS = {
|
|
5850
5966
|
createPrompt: {
|
|
5851
|
-
name:
|
|
5852
|
-
collection_id:
|
|
5967
|
+
name: z16.string().describe("Display name for the prompt"),
|
|
5968
|
+
collection_id: z16.string().describe(
|
|
5853
5969
|
"Collection ID to organize the prompt in (use list_collections to find)"
|
|
5854
5970
|
),
|
|
5855
|
-
string:
|
|
5971
|
+
string: z16.string().optional().describe(
|
|
5856
5972
|
"Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
|
|
5857
5973
|
),
|
|
5858
|
-
messages:
|
|
5974
|
+
messages: z16.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
|
|
5859
5975
|
"Structured chat template alias. Serialized to the legacy string format before creation."
|
|
5860
5976
|
),
|
|
5861
|
-
parameters:
|
|
5862
|
-
virtual_key:
|
|
5863
|
-
model:
|
|
5977
|
+
parameters: z16.record(z16.string(), z16.unknown()).describe("Default values for template variables"),
|
|
5978
|
+
virtual_key: z16.string().describe("Virtual key slug for model access"),
|
|
5979
|
+
model: z16.string().optional().describe(
|
|
5864
5980
|
"Model identifier (e.g., 'gpt-4', 'claude-3-opus'). Required unless ai_model_id or finetune_id is provided"
|
|
5865
5981
|
),
|
|
5866
|
-
ai_model_id:
|
|
5982
|
+
ai_model_id: z16.string().optional().describe(
|
|
5867
5983
|
"AI model ID (alternative to model). Required unless model or finetune_id is provided"
|
|
5868
5984
|
),
|
|
5869
|
-
finetune_id:
|
|
5985
|
+
finetune_id: z16.string().optional().describe(
|
|
5870
5986
|
"Fine-tune ID (alternative to model). Required unless model or ai_model_id is provided"
|
|
5871
5987
|
),
|
|
5872
|
-
version_description:
|
|
5873
|
-
template_metadata:
|
|
5874
|
-
functions:
|
|
5875
|
-
tools:
|
|
5988
|
+
version_description: z16.string().optional().describe("Description for this prompt version"),
|
|
5989
|
+
template_metadata: z16.record(z16.string(), z16.unknown()).optional().describe("Custom metadata (app, env, source_file, etc.)"),
|
|
5990
|
+
functions: z16.array(PromptFunctionSchema).optional().describe("Function definitions for function calling"),
|
|
5991
|
+
tools: z16.array(PromptToolSchema).optional().describe("Tool definitions for tool use"),
|
|
5876
5992
|
tool_choice: ToolChoiceSchema.optional().describe("Tool choice strategy"),
|
|
5877
|
-
dry_run:
|
|
5993
|
+
dry_run: z16.boolean().optional().describe("When true, validate without creating")
|
|
5878
5994
|
},
|
|
5879
5995
|
listPrompts: {
|
|
5880
|
-
collection_id:
|
|
5996
|
+
collection_id: z16.string().optional().describe(
|
|
5881
5997
|
"Filter by collection ID (recommended for app-specific prompts)"
|
|
5882
5998
|
),
|
|
5883
|
-
workspace_id:
|
|
5884
|
-
search:
|
|
5885
|
-
current_page:
|
|
5886
|
-
page_size:
|
|
5999
|
+
workspace_id: z16.string().optional().describe("Filter by workspace ID"),
|
|
6000
|
+
search: z16.string().optional().describe("Search prompts by name"),
|
|
6001
|
+
current_page: z16.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
6002
|
+
page_size: z16.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
|
|
5887
6003
|
},
|
|
5888
6004
|
getPrompt: {
|
|
5889
|
-
prompt_id:
|
|
6005
|
+
prompt_id: z16.string().describe("Prompt ID or slug to retrieve")
|
|
5890
6006
|
},
|
|
5891
6007
|
updatePrompt: {
|
|
5892
|
-
prompt_id:
|
|
5893
|
-
name:
|
|
5894
|
-
collection_id:
|
|
5895
|
-
string:
|
|
6008
|
+
prompt_id: z16.string().describe("Prompt ID or slug to update"),
|
|
6009
|
+
name: z16.string().optional().describe("New display name for the prompt"),
|
|
6010
|
+
collection_id: z16.string().optional().describe("Move to a different collection"),
|
|
6011
|
+
string: z16.string().optional().describe(
|
|
5896
6012
|
"Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
|
|
5897
6013
|
),
|
|
5898
|
-
messages:
|
|
6014
|
+
messages: z16.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
|
|
5899
6015
|
"Structured chat template alias for updates. Serialized to the legacy string format before the prompt is updated."
|
|
5900
6016
|
),
|
|
5901
|
-
parameters:
|
|
5902
|
-
model:
|
|
5903
|
-
virtual_key:
|
|
5904
|
-
version_description:
|
|
5905
|
-
template_metadata:
|
|
5906
|
-
functions:
|
|
5907
|
-
tools:
|
|
6017
|
+
parameters: z16.record(z16.string(), z16.unknown()).optional().describe("New default values for template variables"),
|
|
6018
|
+
model: z16.string().optional().describe("New model identifier"),
|
|
6019
|
+
virtual_key: z16.string().optional().describe("New virtual key slug"),
|
|
6020
|
+
version_description: z16.string().optional().describe("Description for this version"),
|
|
6021
|
+
template_metadata: z16.record(z16.string(), z16.unknown()).optional().describe("New metadata"),
|
|
6022
|
+
functions: z16.array(PromptFunctionSchema).optional().describe("New function definitions"),
|
|
6023
|
+
tools: z16.array(PromptToolSchema).optional().describe("New tool definitions"),
|
|
5908
6024
|
tool_choice: ToolChoiceSchema.optional().describe(
|
|
5909
6025
|
"New tool choice strategy"
|
|
5910
6026
|
),
|
|
5911
|
-
dry_run:
|
|
6027
|
+
dry_run: z16.boolean().optional().describe("When true, validate without updating")
|
|
5912
6028
|
},
|
|
5913
6029
|
deletePrompt: {
|
|
5914
|
-
prompt_id:
|
|
6030
|
+
prompt_id: z16.string().describe("Prompt ID or slug to delete")
|
|
5915
6031
|
},
|
|
5916
6032
|
publishPrompt: {
|
|
5917
|
-
prompt_id:
|
|
5918
|
-
version:
|
|
6033
|
+
prompt_id: z16.string().describe("Prompt ID or slug to publish"),
|
|
6034
|
+
version: z16.coerce.number().positive().describe("Version number to publish as the default")
|
|
5919
6035
|
},
|
|
5920
6036
|
listPromptVersions: {
|
|
5921
|
-
prompt_id:
|
|
6037
|
+
prompt_id: z16.string().describe("Prompt ID or slug to list versions for")
|
|
5922
6038
|
},
|
|
5923
6039
|
renderPrompt: {
|
|
5924
|
-
prompt_id:
|
|
6040
|
+
prompt_id: z16.string().describe("Prompt ID or slug to render"),
|
|
5925
6041
|
variables: PROMPT_VARIABLES_SCHEMA,
|
|
5926
6042
|
hyperparameters: HyperparametersSchema.optional().describe(
|
|
5927
6043
|
"Override default hyperparameters"
|
|
5928
6044
|
)
|
|
5929
6045
|
},
|
|
5930
6046
|
runPromptCompletion: {
|
|
5931
|
-
prompt_id:
|
|
6047
|
+
prompt_id: z16.string().describe("Prompt ID or slug to execute"),
|
|
5932
6048
|
variables: PROMPT_VARIABLES_SCHEMA,
|
|
5933
6049
|
metadata: BillingMetadataSchema.describe(
|
|
5934
6050
|
"Billing metadata - client_id, app, env are REQUIRED for cost attribution"
|
|
@@ -5938,54 +6054,54 @@ var PROMPTS_TOOL_SCHEMAS = {
|
|
|
5938
6054
|
)
|
|
5939
6055
|
},
|
|
5940
6056
|
migratePrompt: {
|
|
5941
|
-
name:
|
|
6057
|
+
name: z16.string().describe("Prompt name to create or find for update"),
|
|
5942
6058
|
app: PromptAppIdentifierSchema,
|
|
5943
6059
|
env: PromptEnvironmentIdentifierSchema,
|
|
5944
|
-
collection_id:
|
|
5945
|
-
string:
|
|
6060
|
+
collection_id: z16.string().describe("Collection ID to search in and create under"),
|
|
6061
|
+
string: z16.string().optional().describe(
|
|
5946
6062
|
"Legacy prompt template string with {{variable}} mustache syntax."
|
|
5947
6063
|
),
|
|
5948
|
-
messages:
|
|
6064
|
+
messages: z16.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
|
|
5949
6065
|
"Structured chat template alias for migrations. Serialized to the legacy string format before the prompt is created or updated."
|
|
5950
6066
|
),
|
|
5951
|
-
parameters:
|
|
5952
|
-
virtual_key:
|
|
5953
|
-
model:
|
|
5954
|
-
version_description:
|
|
5955
|
-
template_metadata:
|
|
5956
|
-
functions:
|
|
5957
|
-
tools:
|
|
6067
|
+
parameters: z16.record(z16.string(), z16.unknown()).describe("Default values for template variables"),
|
|
6068
|
+
virtual_key: z16.string().describe("Virtual key slug for model access"),
|
|
6069
|
+
model: z16.string().optional().describe("Model identifier"),
|
|
6070
|
+
version_description: z16.string().optional().describe("Description for this version"),
|
|
6071
|
+
template_metadata: z16.record(z16.string(), z16.unknown()).optional().describe("Additional custom metadata"),
|
|
6072
|
+
functions: z16.array(PromptFunctionSchema).optional().describe("Function definitions"),
|
|
6073
|
+
tools: z16.array(PromptToolSchema).optional().describe("Tool definitions"),
|
|
5958
6074
|
tool_choice: ToolChoiceSchema.optional().describe("Tool choice strategy"),
|
|
5959
|
-
dry_run:
|
|
6075
|
+
dry_run: z16.boolean().optional().describe(
|
|
5960
6076
|
"When true, only check what action would be taken without making changes"
|
|
5961
6077
|
)
|
|
5962
6078
|
},
|
|
5963
6079
|
promotePrompt: {
|
|
5964
|
-
source_prompt_id:
|
|
5965
|
-
target_collection_id:
|
|
5966
|
-
target_name:
|
|
6080
|
+
source_prompt_id: z16.string().describe("Source prompt ID or slug (e.g., staging prompt)"),
|
|
6081
|
+
target_collection_id: z16.string().describe("Target collection ID for the promoted prompt"),
|
|
6082
|
+
target_name: z16.string().optional().describe(
|
|
5967
6083
|
"Target prompt name (defaults to source name with env suffix replaced)"
|
|
5968
6084
|
),
|
|
5969
6085
|
target_env: PromptEnvironmentIdentifierSchema,
|
|
5970
|
-
virtual_key:
|
|
6086
|
+
virtual_key: z16.string().optional().describe(
|
|
5971
6087
|
"Virtual key ID to use (defaults to source prompt's virtual_key)"
|
|
5972
6088
|
)
|
|
5973
6089
|
},
|
|
5974
6090
|
validateCompletionMetadata: {
|
|
5975
|
-
client_id:
|
|
6091
|
+
client_id: z16.string().optional().describe("Client ID for billing attribution"),
|
|
5976
6092
|
app: PromptAppIdentifierSchema.optional(),
|
|
5977
6093
|
env: PromptEnvironmentIdentifierSchema.optional(),
|
|
5978
|
-
project_id:
|
|
5979
|
-
feature:
|
|
6094
|
+
project_id: z16.string().optional().describe("Project ID for granular billing"),
|
|
6095
|
+
feature: z16.string().optional().describe("Feature name for tracking")
|
|
5980
6096
|
},
|
|
5981
6097
|
getPromptVersion: {
|
|
5982
|
-
prompt_id:
|
|
5983
|
-
version_id:
|
|
6098
|
+
prompt_id: z16.string().describe("Prompt ID or slug"),
|
|
6099
|
+
version_id: z16.string().describe("Version UUID to retrieve")
|
|
5984
6100
|
},
|
|
5985
6101
|
updatePromptVersion: {
|
|
5986
|
-
prompt_id:
|
|
5987
|
-
version_id:
|
|
5988
|
-
label_id:
|
|
6102
|
+
prompt_id: z16.string().describe("Prompt ID or slug"),
|
|
6103
|
+
version_id: z16.string().describe("Version UUID to update"),
|
|
6104
|
+
label_id: z16.string().nullable().describe(
|
|
5989
6105
|
"Label ID to assign to this version, or null to remove the label"
|
|
5990
6106
|
)
|
|
5991
6107
|
}
|
|
@@ -6575,68 +6691,68 @@ function registerPromptsTools(server, service) {
|
|
|
6575
6691
|
}
|
|
6576
6692
|
|
|
6577
6693
|
// src/tools/providers.tools.ts
|
|
6578
|
-
import { z as
|
|
6694
|
+
import { z as z17 } from "zod";
|
|
6579
6695
|
var PROVIDERS_TOOL_SCHEMAS = {
|
|
6580
6696
|
listProviders: {
|
|
6581
|
-
current_page:
|
|
6582
|
-
page_size:
|
|
6583
|
-
workspace_id:
|
|
6697
|
+
current_page: z17.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
6698
|
+
page_size: z17.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100, default 50)"),
|
|
6699
|
+
workspace_id: z17.string().optional().describe(
|
|
6584
6700
|
"Workspace ID - required when using organization admin keys, optional with workspace API keys"
|
|
6585
6701
|
)
|
|
6586
6702
|
},
|
|
6587
6703
|
createProvider: {
|
|
6588
|
-
name:
|
|
6589
|
-
integration_id:
|
|
6704
|
+
name: z17.string().describe("Display name for the provider"),
|
|
6705
|
+
integration_id: z17.string().describe(
|
|
6590
6706
|
"Integration slug for the provider (e.g., 'openai', 'anthropic', 'azure-openai')"
|
|
6591
6707
|
),
|
|
6592
|
-
workspace_id:
|
|
6708
|
+
workspace_id: z17.string().optional().describe(
|
|
6593
6709
|
"Workspace ID - required when using organization admin API keys"
|
|
6594
6710
|
),
|
|
6595
|
-
slug:
|
|
6711
|
+
slug: z17.string().optional().describe(
|
|
6596
6712
|
"Custom slug for the provider. Auto-generated with random suffix if omitted"
|
|
6597
6713
|
),
|
|
6598
|
-
note:
|
|
6599
|
-
credit_limit:
|
|
6600
|
-
alert_threshold:
|
|
6601
|
-
usage_limit_type:
|
|
6714
|
+
note: z17.string().optional().describe("Optional note or description for the provider"),
|
|
6715
|
+
credit_limit: z17.coerce.number().positive().optional().describe("Credit limit for usage"),
|
|
6716
|
+
alert_threshold: z17.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
|
|
6717
|
+
usage_limit_type: z17.enum(["cost", "tokens"]).optional().describe(
|
|
6602
6718
|
"Type of usage limit: 'cost' (monetary) or 'tokens' (token count). Defaults to 'cost'."
|
|
6603
6719
|
),
|
|
6604
|
-
periodic_reset:
|
|
6720
|
+
periodic_reset: z17.enum(["monthly", "weekly"]).optional().describe(
|
|
6605
6721
|
"Period for resetting usage limits: 'monthly' or 'weekly'. Defaults to 'monthly'."
|
|
6606
6722
|
),
|
|
6607
|
-
rate_limit_value:
|
|
6608
|
-
rate_limit_unit:
|
|
6723
|
+
rate_limit_value: z17.coerce.number().positive().optional().describe("Must be provided together with rate_limit_unit."),
|
|
6724
|
+
rate_limit_unit: z17.enum(["rpm", "rph", "rpd"]).optional().describe(
|
|
6609
6725
|
"Must be provided together with rate_limit_value. Values: 'rpm' (requests/min), 'rph' (requests/hour), or 'rpd' (requests/day)."
|
|
6610
6726
|
),
|
|
6611
|
-
expires_at:
|
|
6727
|
+
expires_at: z17.string().optional().describe("Expiration date in ISO 8601 format")
|
|
6612
6728
|
},
|
|
6613
6729
|
getProvider: {
|
|
6614
|
-
slug:
|
|
6615
|
-
workspace_id:
|
|
6730
|
+
slug: z17.string().describe("The unique slug identifier of the provider to retrieve"),
|
|
6731
|
+
workspace_id: z17.string().optional().describe("Workspace ID - required when using organization admin keys")
|
|
6616
6732
|
},
|
|
6617
6733
|
updateProvider: {
|
|
6618
|
-
slug:
|
|
6619
|
-
workspace_id:
|
|
6620
|
-
name:
|
|
6621
|
-
note:
|
|
6622
|
-
credit_limit:
|
|
6623
|
-
alert_threshold:
|
|
6624
|
-
usage_limit_type:
|
|
6734
|
+
slug: z17.string().describe("The slug of the provider to update"),
|
|
6735
|
+
workspace_id: z17.string().optional().describe("Workspace ID - required when using organization admin keys"),
|
|
6736
|
+
name: z17.string().optional().describe("New display name for the provider"),
|
|
6737
|
+
note: z17.string().optional().describe("New note or description for the provider"),
|
|
6738
|
+
credit_limit: z17.coerce.number().positive().optional().describe("New credit limit for usage"),
|
|
6739
|
+
alert_threshold: z17.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
|
|
6740
|
+
usage_limit_type: z17.enum(["cost", "tokens"]).optional().describe(
|
|
6625
6741
|
"Type of usage limit: 'cost' (monetary) or 'tokens' (token count). Defaults to 'cost'."
|
|
6626
6742
|
),
|
|
6627
|
-
periodic_reset:
|
|
6743
|
+
periodic_reset: z17.enum(["monthly", "weekly"]).optional().describe(
|
|
6628
6744
|
"Period for resetting usage limits: 'monthly' or 'weekly'. Defaults to 'monthly'."
|
|
6629
6745
|
),
|
|
6630
|
-
rate_limit_value:
|
|
6631
|
-
rate_limit_unit:
|
|
6746
|
+
rate_limit_value: z17.coerce.number().positive().optional().describe("New rate limit value"),
|
|
6747
|
+
rate_limit_unit: z17.enum(["rpm", "rph", "rpd"]).optional().describe(
|
|
6632
6748
|
"Rate limit unit: 'rpm' (requests per minute), 'rph' (requests per hour), or 'rpd' (requests per day)"
|
|
6633
6749
|
),
|
|
6634
|
-
expires_at:
|
|
6635
|
-
reset_usage:
|
|
6750
|
+
expires_at: z17.string().optional().describe("New expiration date in ISO 8601 format"),
|
|
6751
|
+
reset_usage: z17.boolean().optional().describe("Set to true to reset accumulated usage metrics")
|
|
6636
6752
|
},
|
|
6637
6753
|
deleteProvider: {
|
|
6638
|
-
slug:
|
|
6639
|
-
workspace_id:
|
|
6754
|
+
slug: z17.string().describe("The slug of the provider to delete"),
|
|
6755
|
+
workspace_id: z17.string().optional().describe("Workspace ID - required when using organization admin keys")
|
|
6640
6756
|
}
|
|
6641
6757
|
};
|
|
6642
6758
|
function registerProvidersTools(server, service) {
|
|
@@ -6817,30 +6933,427 @@ function registerProvidersTools(server, service) {
|
|
|
6817
6933
|
);
|
|
6818
6934
|
}
|
|
6819
6935
|
|
|
6936
|
+
// src/tools/secret-references.tools.ts
|
|
6937
|
+
import { z as z18 } from "zod";
|
|
6938
|
+
var authFields = {
|
|
6939
|
+
aws_auth_type: z18.enum(["accessKey", "assumedRole", "serviceRole"]).describe(
|
|
6940
|
+
"AWS authentication mode: accessKey uses a key pair, assumedRole uses an IAM role, and serviceRole uses the runtime workload identity"
|
|
6941
|
+
),
|
|
6942
|
+
aws_access_key_id: z18.string().min(1).describe("AWS access key ID; required when aws_auth_type is accessKey"),
|
|
6943
|
+
aws_secret_access_key: z18.string().min(1).describe(
|
|
6944
|
+
"AWS secret access key; required when aws_auth_type is accessKey and exposed to the MCP transcript"
|
|
6945
|
+
),
|
|
6946
|
+
aws_region: z18.string().min(1).describe("AWS region containing the secret, for example us-east-1"),
|
|
6947
|
+
aws_role_arn: z18.string().min(1).describe(
|
|
6948
|
+
"IAM role ARN to assume; required when aws_auth_type is assumedRole"
|
|
6949
|
+
),
|
|
6950
|
+
aws_external_id: z18.string().nullable().describe("Optional external ID required by the target IAM role"),
|
|
6951
|
+
azure_auth_mode: z18.enum(["entra", "managed", "default"]).describe(
|
|
6952
|
+
"Azure authentication mode: entra uses a client secret, managed uses managed identity, and default uses the runtime credential chain"
|
|
6953
|
+
),
|
|
6954
|
+
azure_entra_tenant_id: z18.string().min(1).describe("Microsoft Entra tenant ID; required for entra authentication"),
|
|
6955
|
+
azure_entra_client_id: z18.string().min(1).describe(
|
|
6956
|
+
"Microsoft Entra application client ID; required for entra authentication"
|
|
6957
|
+
),
|
|
6958
|
+
azure_entra_client_secret: z18.string().min(1).describe(
|
|
6959
|
+
"Microsoft Entra client secret; required for entra authentication and exposed to the MCP transcript"
|
|
6960
|
+
),
|
|
6961
|
+
azure_managed_client_id: z18.string().min(1).describe(
|
|
6962
|
+
"Optional client ID of a user-assigned managed identity; omit for the system-assigned identity"
|
|
6963
|
+
),
|
|
6964
|
+
azure_vault_url: z18.url().describe(
|
|
6965
|
+
"Azure Key Vault URL, for example https://example.vault.azure.net"
|
|
6966
|
+
),
|
|
6967
|
+
vault_auth_type: z18.enum(["token", "approle", "kubernetes"]).describe(
|
|
6968
|
+
"HashiCorp Vault authentication mode: token, AppRole, or Kubernetes"
|
|
6969
|
+
),
|
|
6970
|
+
vault_addr: z18.url().describe("Base URL of the HashiCorp Vault server"),
|
|
6971
|
+
vault_token: z18.string().min(1).describe(
|
|
6972
|
+
"HashiCorp Vault token; required for token authentication and exposed to the MCP transcript"
|
|
6973
|
+
),
|
|
6974
|
+
vault_namespace: z18.string().min(1).describe("Optional HashiCorp Vault Enterprise namespace"),
|
|
6975
|
+
vault_role_id: z18.string().min(1).describe(
|
|
6976
|
+
"HashiCorp Vault AppRole role ID; required for approle authentication"
|
|
6977
|
+
),
|
|
6978
|
+
vault_secret_id: z18.string().min(1).describe(
|
|
6979
|
+
"HashiCorp Vault AppRole secret ID; required for approle authentication and exposed to the MCP transcript"
|
|
6980
|
+
),
|
|
6981
|
+
vault_role: z18.string().min(1).describe("HashiCorp Vault Kubernetes auth role name")
|
|
6982
|
+
};
|
|
6983
|
+
var authConfigSchema = z18.union([
|
|
6984
|
+
z18.object({
|
|
6985
|
+
aws_auth_type: z18.literal("accessKey").describe("Use an AWS access key ID and secret access key"),
|
|
6986
|
+
aws_access_key_id: authFields.aws_access_key_id,
|
|
6987
|
+
aws_secret_access_key: authFields.aws_secret_access_key,
|
|
6988
|
+
aws_region: authFields.aws_region
|
|
6989
|
+
}).strict(),
|
|
6990
|
+
z18.object({
|
|
6991
|
+
aws_auth_type: z18.literal("assumedRole").describe("Assume the specified AWS IAM role"),
|
|
6992
|
+
aws_role_arn: authFields.aws_role_arn,
|
|
6993
|
+
aws_external_id: authFields.aws_external_id.optional(),
|
|
6994
|
+
aws_region: authFields.aws_region
|
|
6995
|
+
}).strict(),
|
|
6996
|
+
z18.object({
|
|
6997
|
+
aws_auth_type: z18.literal("serviceRole").describe("Use the AWS workload or service role available at runtime"),
|
|
6998
|
+
aws_region: z18.string().optional().describe(
|
|
6999
|
+
"Optional AWS region containing the secret, for example us-east-1"
|
|
7000
|
+
)
|
|
7001
|
+
}).strict(),
|
|
7002
|
+
z18.object({
|
|
7003
|
+
azure_auth_mode: z18.literal("entra").describe(
|
|
7004
|
+
"Authenticate with a Microsoft Entra application client secret"
|
|
7005
|
+
),
|
|
7006
|
+
azure_entra_tenant_id: authFields.azure_entra_tenant_id,
|
|
7007
|
+
azure_entra_client_id: authFields.azure_entra_client_id,
|
|
7008
|
+
azure_entra_client_secret: authFields.azure_entra_client_secret,
|
|
7009
|
+
azure_vault_url: authFields.azure_vault_url
|
|
7010
|
+
}).strict(),
|
|
7011
|
+
z18.object({
|
|
7012
|
+
azure_auth_mode: z18.literal("managed").describe("Authenticate with an Azure managed identity"),
|
|
7013
|
+
azure_managed_client_id: authFields.azure_managed_client_id.optional(),
|
|
7014
|
+
azure_vault_url: authFields.azure_vault_url
|
|
7015
|
+
}).strict(),
|
|
7016
|
+
z18.object({
|
|
7017
|
+
azure_auth_mode: z18.literal("default").describe("Use Azure's default runtime credential chain"),
|
|
7018
|
+
azure_vault_url: authFields.azure_vault_url
|
|
7019
|
+
}).strict(),
|
|
7020
|
+
z18.object({
|
|
7021
|
+
vault_auth_type: z18.literal("token").describe("Authenticate to HashiCorp Vault with a token"),
|
|
7022
|
+
vault_addr: authFields.vault_addr,
|
|
7023
|
+
vault_token: authFields.vault_token,
|
|
7024
|
+
vault_namespace: authFields.vault_namespace.optional()
|
|
7025
|
+
}).strict(),
|
|
7026
|
+
z18.object({
|
|
7027
|
+
vault_auth_type: z18.literal("approle").describe("Authenticate to HashiCorp Vault with AppRole credentials"),
|
|
7028
|
+
vault_addr: authFields.vault_addr,
|
|
7029
|
+
vault_role_id: authFields.vault_role_id,
|
|
7030
|
+
vault_secret_id: authFields.vault_secret_id,
|
|
7031
|
+
vault_namespace: authFields.vault_namespace.optional()
|
|
7032
|
+
}).strict(),
|
|
7033
|
+
z18.object({
|
|
7034
|
+
vault_auth_type: z18.literal("kubernetes").describe(
|
|
7035
|
+
"Authenticate to HashiCorp Vault with a Kubernetes service account"
|
|
7036
|
+
),
|
|
7037
|
+
vault_addr: authFields.vault_addr,
|
|
7038
|
+
vault_role: authFields.vault_role,
|
|
7039
|
+
vault_namespace: authFields.vault_namespace.optional()
|
|
7040
|
+
}).strict()
|
|
7041
|
+
]);
|
|
7042
|
+
var updateAuthConfigSchema = z18.union([
|
|
7043
|
+
z18.object({
|
|
7044
|
+
aws_auth_type: authFields.aws_auth_type.optional(),
|
|
7045
|
+
aws_access_key_id: authFields.aws_access_key_id.optional(),
|
|
7046
|
+
aws_secret_access_key: authFields.aws_secret_access_key.optional(),
|
|
7047
|
+
aws_region: z18.string().optional().describe("AWS region containing the secret, for example us-east-1"),
|
|
7048
|
+
aws_role_arn: authFields.aws_role_arn.optional(),
|
|
7049
|
+
aws_external_id: authFields.aws_external_id.optional()
|
|
7050
|
+
}).strict(),
|
|
7051
|
+
z18.object({
|
|
7052
|
+
azure_auth_mode: authFields.azure_auth_mode.optional(),
|
|
7053
|
+
azure_entra_tenant_id: authFields.azure_entra_tenant_id.optional(),
|
|
7054
|
+
azure_entra_client_id: authFields.azure_entra_client_id.optional(),
|
|
7055
|
+
azure_entra_client_secret: authFields.azure_entra_client_secret.optional(),
|
|
7056
|
+
azure_managed_client_id: z18.string().optional().describe(
|
|
7057
|
+
"Optional client ID of a user-assigned managed identity; omit for the system-assigned identity"
|
|
7058
|
+
),
|
|
7059
|
+
azure_vault_url: authFields.azure_vault_url.optional()
|
|
7060
|
+
}).strict(),
|
|
7061
|
+
z18.object({
|
|
7062
|
+
vault_auth_type: authFields.vault_auth_type.optional(),
|
|
7063
|
+
vault_addr: authFields.vault_addr.optional(),
|
|
7064
|
+
vault_token: authFields.vault_token.optional(),
|
|
7065
|
+
vault_namespace: z18.string().optional().describe("Optional HashiCorp Vault Enterprise namespace"),
|
|
7066
|
+
vault_role_id: authFields.vault_role_id.optional(),
|
|
7067
|
+
vault_secret_id: authFields.vault_secret_id.optional(),
|
|
7068
|
+
vault_role: authFields.vault_role.optional()
|
|
7069
|
+
}).strict()
|
|
7070
|
+
]);
|
|
7071
|
+
var managerTypeSchema = z18.enum(["aws_sm", "azure_kv", "hashicorp_vault"]).describe(
|
|
7072
|
+
"External secret manager: aws_sm for AWS Secrets Manager, azure_kv for Azure Key Vault, or hashicorp_vault for HashiCorp Vault; must match the auth_config field family"
|
|
7073
|
+
);
|
|
7074
|
+
var tagsSchema = z18.record(z18.string(), z18.string()).describe("Tag filters or metadata as string key-value pairs");
|
|
7075
|
+
var SECRET_REFERENCE_TOOL_SCHEMAS = {
|
|
7076
|
+
create: {
|
|
7077
|
+
name: z18.string().min(1).max(255).describe("Human-readable name"),
|
|
7078
|
+
manager_type: managerTypeSchema,
|
|
7079
|
+
auth_config: authConfigSchema.describe(
|
|
7080
|
+
"Choose exactly one documented authentication shape matching manager_type. Credentials are sent to Portkey and visible in the MCP transcript; prefer workload identity or short-lived credentials when available."
|
|
7081
|
+
),
|
|
7082
|
+
secret_path: z18.string().max(1024).describe("Path of the secret in the external secret manager"),
|
|
7083
|
+
organisation_id: z18.string().uuid().optional().describe(
|
|
7084
|
+
"Organisation UUID; required when the MCP server is not authenticated with a Portkey API key"
|
|
7085
|
+
),
|
|
7086
|
+
slug: z18.string().max(255).regex(/^[a-zA-Z0-9_-]+$/).optional().describe(
|
|
7087
|
+
"Optional stable slug containing only letters, numbers, underscores, or hyphens; Portkey generates one when omitted"
|
|
7088
|
+
),
|
|
7089
|
+
description: z18.string().max(1024).nullable().optional().describe("Optional description; use null to leave it empty"),
|
|
7090
|
+
secret_key: z18.string().max(255).nullable().optional().describe(
|
|
7091
|
+
"Optional key within a structured external secret; null uses the whole secret value"
|
|
7092
|
+
),
|
|
7093
|
+
allow_all_workspaces: z18.boolean().optional().describe(
|
|
7094
|
+
"Whether every workspace may use this reference; defaults to true and cannot be true with allowed_workspaces"
|
|
7095
|
+
),
|
|
7096
|
+
allowed_workspaces: z18.array(z18.string()).min(1).optional().describe(
|
|
7097
|
+
"Workspace UUIDs or slugs allowed to use this reference; omit when allow_all_workspaces is true"
|
|
7098
|
+
),
|
|
7099
|
+
tags: tagsSchema.nullable().optional().describe(
|
|
7100
|
+
"Optional string key-value tags for filtering and organization"
|
|
7101
|
+
)
|
|
7102
|
+
},
|
|
7103
|
+
list: {
|
|
7104
|
+
manager_type: managerTypeSchema.optional().describe(
|
|
7105
|
+
"Filter by external secret manager: aws_sm, azure_kv, or hashicorp_vault"
|
|
7106
|
+
),
|
|
7107
|
+
tags: tagsSchema.optional().describe("Return references matching these tags"),
|
|
7108
|
+
search: z18.string().min(1).max(255).optional().describe("Search references by name"),
|
|
7109
|
+
current_page: z18.coerce.number().int().nonnegative().optional().describe("Zero-based page number; defaults to 0"),
|
|
7110
|
+
page_size: z18.coerce.number().int().min(1).max(100).optional().describe("References per page, from 1 to 100; defaults to 20")
|
|
7111
|
+
},
|
|
7112
|
+
get: {
|
|
7113
|
+
id: z18.string().min(1).describe("Secret Reference UUID or slug")
|
|
7114
|
+
},
|
|
7115
|
+
update: {
|
|
7116
|
+
id: z18.string().min(1).describe("Secret Reference UUID or slug"),
|
|
7117
|
+
name: z18.string().min(1).max(255).optional().describe("New human-readable name"),
|
|
7118
|
+
description: z18.string().max(1024).nullable().optional().describe("New description, or null to clear it"),
|
|
7119
|
+
auth_config: updateAuthConfigSchema.optional().describe(
|
|
7120
|
+
"Provide at least one changed authentication field to merge into the existing configuration; choose one AWS, Azure, or HashiCorp field family and do not mix families"
|
|
7121
|
+
),
|
|
7122
|
+
secret_path: z18.string().max(1024).optional().describe("New path of the secret in the external secret manager"),
|
|
7123
|
+
secret_key: z18.string().max(255).nullable().optional().describe(
|
|
7124
|
+
"New key within a structured secret, or null to use the whole value"
|
|
7125
|
+
),
|
|
7126
|
+
allow_all_workspaces: z18.boolean().optional().describe(
|
|
7127
|
+
"Whether every workspace may use this reference; cannot be true with allowed_workspaces"
|
|
7128
|
+
),
|
|
7129
|
+
allowed_workspaces: z18.array(z18.string()).min(1).optional().describe(
|
|
7130
|
+
"Replacement list of workspace UUIDs or slugs allowed to use this reference; supplying it sets allow_all_workspaces=false"
|
|
7131
|
+
),
|
|
7132
|
+
tags: tagsSchema.nullable().optional().describe("Replacement string key-value tags, or null to clear them")
|
|
7133
|
+
},
|
|
7134
|
+
delete: {
|
|
7135
|
+
id: z18.string().min(1).describe("Secret Reference UUID or slug")
|
|
7136
|
+
}
|
|
7137
|
+
};
|
|
7138
|
+
function validateWorkspaceAccess(value) {
|
|
7139
|
+
if (value.allow_all_workspaces === true && value.allowed_workspaces) {
|
|
7140
|
+
throw new Error(
|
|
7141
|
+
"allow_all_workspaces=true is mutually exclusive with allowed_workspaces"
|
|
7142
|
+
);
|
|
7143
|
+
}
|
|
7144
|
+
}
|
|
7145
|
+
function validateManagerAuth(managerType, authConfig) {
|
|
7146
|
+
const matches = managerType === "aws_sm" && "aws_auth_type" in authConfig || managerType === "azure_kv" && "azure_auth_mode" in authConfig || managerType === "hashicorp_vault" && "vault_auth_type" in authConfig;
|
|
7147
|
+
if (!matches) {
|
|
7148
|
+
throw new Error(`auth_config does not match manager_type ${managerType}`);
|
|
7149
|
+
}
|
|
7150
|
+
}
|
|
7151
|
+
function validateAuthUpdate(authConfig) {
|
|
7152
|
+
if (Object.keys(authConfig).length === 0) {
|
|
7153
|
+
throw new Error("auth_config update must contain at least one field");
|
|
7154
|
+
}
|
|
7155
|
+
const families = new Set(
|
|
7156
|
+
Object.keys(authConfig).map((key) => {
|
|
7157
|
+
if (key.startsWith("aws_")) return "AWS";
|
|
7158
|
+
if (key.startsWith("azure_")) return "Azure";
|
|
7159
|
+
if (key.startsWith("vault_")) return "HashiCorp Vault";
|
|
7160
|
+
return "unknown";
|
|
7161
|
+
})
|
|
7162
|
+
);
|
|
7163
|
+
if (families.size > 1) {
|
|
7164
|
+
throw new Error(
|
|
7165
|
+
"auth_config update must contain fields for exactly one secret-manager family"
|
|
7166
|
+
);
|
|
7167
|
+
}
|
|
7168
|
+
}
|
|
7169
|
+
var SENSITIVE_AUTH_FIELD = /(?:secret|token|password|credential|access_key_id)/i;
|
|
7170
|
+
function redactAuthConfig(authConfig) {
|
|
7171
|
+
return Object.fromEntries(
|
|
7172
|
+
Object.entries(authConfig).map(([key, value]) => {
|
|
7173
|
+
if (SENSITIVE_AUTH_FIELD.test(key)) return [key, "[REDACTED]"];
|
|
7174
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
7175
|
+
return [key, redactAuthConfig(value)];
|
|
7176
|
+
}
|
|
7177
|
+
return [key, value];
|
|
7178
|
+
})
|
|
7179
|
+
);
|
|
7180
|
+
}
|
|
7181
|
+
function registerSecretReferencesTools(server, service) {
|
|
7182
|
+
server.tool(
|
|
7183
|
+
"create_secret_reference",
|
|
7184
|
+
"Create a reference to a secret stored in AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault. Authentication credentials are sent to Portkey and exposed to this MCP transcript; use short-lived or workload identity modes when possible. Returns the new UUID and slug, never the resolved external secret.",
|
|
7185
|
+
SECRET_REFERENCE_TOOL_SCHEMAS.create,
|
|
7186
|
+
{
|
|
7187
|
+
title: "Create Secret Reference",
|
|
7188
|
+
readOnlyHint: false,
|
|
7189
|
+
destructiveHint: false,
|
|
7190
|
+
idempotentHint: false,
|
|
7191
|
+
openWorldHint: true
|
|
7192
|
+
},
|
|
7193
|
+
async (params) => {
|
|
7194
|
+
validateWorkspaceAccess(params);
|
|
7195
|
+
validateManagerAuth(params.manager_type, params.auth_config);
|
|
7196
|
+
const result = await service.secretReferences.createSecretReference(params);
|
|
7197
|
+
return {
|
|
7198
|
+
content: [
|
|
7199
|
+
{
|
|
7200
|
+
type: "text",
|
|
7201
|
+
text: JSON.stringify({
|
|
7202
|
+
message: `Successfully created Secret Reference "${result.slug}"`,
|
|
7203
|
+
id: result.id,
|
|
7204
|
+
slug: result.slug
|
|
7205
|
+
})
|
|
7206
|
+
}
|
|
7207
|
+
]
|
|
7208
|
+
};
|
|
7209
|
+
}
|
|
7210
|
+
);
|
|
7211
|
+
server.tool(
|
|
7212
|
+
"list_secret_references",
|
|
7213
|
+
"List Secret References without returning authentication configuration or resolved secret values. Filter by manager type, tags, or name and use a returned UUID or slug with get_secret_reference.",
|
|
7214
|
+
SECRET_REFERENCE_TOOL_SCHEMAS.list,
|
|
7215
|
+
{
|
|
7216
|
+
title: "List Secret References",
|
|
7217
|
+
readOnlyHint: true,
|
|
7218
|
+
destructiveHint: false,
|
|
7219
|
+
idempotentHint: true,
|
|
7220
|
+
openWorldHint: true
|
|
7221
|
+
},
|
|
7222
|
+
async (params) => {
|
|
7223
|
+
const result = await service.secretReferences.listSecretReferences({
|
|
7224
|
+
...params,
|
|
7225
|
+
tags: params.tags ? JSON.stringify(params.tags) : void 0
|
|
7226
|
+
});
|
|
7227
|
+
return {
|
|
7228
|
+
content: [
|
|
7229
|
+
{
|
|
7230
|
+
type: "text",
|
|
7231
|
+
text: JSON.stringify({
|
|
7232
|
+
total: result.total,
|
|
7233
|
+
secret_references: result.data.map((reference) => ({
|
|
7234
|
+
id: reference.id,
|
|
7235
|
+
name: reference.name,
|
|
7236
|
+
slug: reference.slug,
|
|
7237
|
+
manager_type: reference.manager_type,
|
|
7238
|
+
status: reference.status,
|
|
7239
|
+
created_at: reference.created_at,
|
|
7240
|
+
last_updated_at: reference.last_updated_at
|
|
7241
|
+
}))
|
|
7242
|
+
})
|
|
7243
|
+
}
|
|
7244
|
+
]
|
|
7245
|
+
};
|
|
7246
|
+
}
|
|
7247
|
+
);
|
|
7248
|
+
server.tool(
|
|
7249
|
+
"get_secret_reference",
|
|
7250
|
+
"Retrieve one Secret Reference by UUID or slug. Portkey masks sensitive authentication fields for non-system users; the tool returns metadata and the masked auth configuration, not the resolved external secret value.",
|
|
7251
|
+
SECRET_REFERENCE_TOOL_SCHEMAS.get,
|
|
7252
|
+
{
|
|
7253
|
+
title: "Get Secret Reference",
|
|
7254
|
+
readOnlyHint: true,
|
|
7255
|
+
destructiveHint: false,
|
|
7256
|
+
idempotentHint: true,
|
|
7257
|
+
openWorldHint: true
|
|
7258
|
+
},
|
|
7259
|
+
async ({ id }) => {
|
|
7260
|
+
const result = await service.secretReferences.getSecretReference(id);
|
|
7261
|
+
return {
|
|
7262
|
+
content: [
|
|
7263
|
+
{
|
|
7264
|
+
type: "text",
|
|
7265
|
+
text: JSON.stringify({
|
|
7266
|
+
...result,
|
|
7267
|
+
auth_config: redactAuthConfig(result.auth_config)
|
|
7268
|
+
})
|
|
7269
|
+
}
|
|
7270
|
+
]
|
|
7271
|
+
};
|
|
7272
|
+
}
|
|
7273
|
+
);
|
|
7274
|
+
server.tool(
|
|
7275
|
+
"update_secret_reference",
|
|
7276
|
+
"Update at least one selected field on a Secret Reference. auth_config is merged into the existing manager-specific configuration. allowed_workspaces replaces all workspace mappings and sets allow_all_workspaces=false; allow_all_workspaces=true removes workspace-specific mappings. Credential values are sent to Portkey and exposed to the MCP transcript.",
|
|
7277
|
+
SECRET_REFERENCE_TOOL_SCHEMAS.update,
|
|
7278
|
+
{
|
|
7279
|
+
title: "Update Secret Reference",
|
|
7280
|
+
readOnlyHint: false,
|
|
7281
|
+
destructiveHint: true,
|
|
7282
|
+
idempotentHint: true,
|
|
7283
|
+
openWorldHint: true
|
|
7284
|
+
},
|
|
7285
|
+
async ({ id, ...updates }) => {
|
|
7286
|
+
validateWorkspaceAccess(updates);
|
|
7287
|
+
if (Object.keys(updates).length === 0) {
|
|
7288
|
+
throw new Error("Provide at least one field to update");
|
|
7289
|
+
}
|
|
7290
|
+
if (updates.auth_config) validateAuthUpdate(updates.auth_config);
|
|
7291
|
+
await service.secretReferences.updateSecretReference(id, updates);
|
|
7292
|
+
return {
|
|
7293
|
+
content: [
|
|
7294
|
+
{
|
|
7295
|
+
type: "text",
|
|
7296
|
+
text: JSON.stringify({
|
|
7297
|
+
message: `Successfully updated Secret Reference "${id}"`,
|
|
7298
|
+
success: true
|
|
7299
|
+
})
|
|
7300
|
+
}
|
|
7301
|
+
]
|
|
7302
|
+
};
|
|
7303
|
+
}
|
|
7304
|
+
);
|
|
7305
|
+
server.tool(
|
|
7306
|
+
"delete_secret_reference",
|
|
7307
|
+
"Permanently delete a Secret Reference. This is irreversible and integrations or virtual keys using it can fail to resolve credentials immediately; confirm dependencies before deletion.",
|
|
7308
|
+
SECRET_REFERENCE_TOOL_SCHEMAS.delete,
|
|
7309
|
+
{
|
|
7310
|
+
title: "Delete Secret Reference",
|
|
7311
|
+
readOnlyHint: false,
|
|
7312
|
+
destructiveHint: true,
|
|
7313
|
+
idempotentHint: true,
|
|
7314
|
+
openWorldHint: true
|
|
7315
|
+
},
|
|
7316
|
+
async ({ id }) => {
|
|
7317
|
+
const result = await service.secretReferences.deleteSecretReference(id);
|
|
7318
|
+
return {
|
|
7319
|
+
content: [
|
|
7320
|
+
{
|
|
7321
|
+
type: "text",
|
|
7322
|
+
text: JSON.stringify({
|
|
7323
|
+
message: `Successfully deleted Secret Reference "${id}"`,
|
|
7324
|
+
success: result.success
|
|
7325
|
+
})
|
|
7326
|
+
}
|
|
7327
|
+
]
|
|
7328
|
+
};
|
|
7329
|
+
}
|
|
7330
|
+
);
|
|
7331
|
+
}
|
|
7332
|
+
|
|
6820
7333
|
// src/tools/tracing.tools.ts
|
|
6821
|
-
import { z as
|
|
7334
|
+
import { z as z19 } from "zod";
|
|
6822
7335
|
var TRACING_TOOL_SCHEMAS = {
|
|
6823
7336
|
createFeedback: {
|
|
6824
|
-
trace_id:
|
|
7337
|
+
trace_id: z19.string().describe(
|
|
6825
7338
|
"The trace ID to associate the feedback with. This links feedback to a specific request/generation."
|
|
6826
7339
|
),
|
|
6827
|
-
value:
|
|
7340
|
+
value: z19.coerce.number().describe(
|
|
6828
7341
|
"Feedback value/rating. Common patterns: 1 for positive (thumbs up), 0 for negative (thumbs down), or use a scale like 1-5."
|
|
6829
7342
|
),
|
|
6830
|
-
weight:
|
|
7343
|
+
weight: z19.coerce.number().positive().optional().describe(
|
|
6831
7344
|
"Optional weighting factor for the feedback. Use to give more importance to certain feedback."
|
|
6832
7345
|
),
|
|
6833
|
-
metadata:
|
|
7346
|
+
metadata: z19.record(z19.string(), z19.unknown()).optional().describe(
|
|
6834
7347
|
"Optional custom metadata for categorization and analysis (e.g., feedback_source, category, user_segment)."
|
|
6835
7348
|
)
|
|
6836
7349
|
},
|
|
6837
7350
|
updateFeedback: {
|
|
6838
|
-
id:
|
|
6839
|
-
value:
|
|
7351
|
+
id: z19.string().describe("The unique identifier of the feedback to update"),
|
|
7352
|
+
value: z19.coerce.number().optional().describe(
|
|
6840
7353
|
"New feedback value/rating. Common patterns: 1 for positive, 0 for negative."
|
|
6841
7354
|
),
|
|
6842
|
-
weight:
|
|
6843
|
-
metadata:
|
|
7355
|
+
weight: z19.coerce.number().positive().optional().describe("New weighting factor for the feedback"),
|
|
7356
|
+
metadata: z19.record(z19.string(), z19.unknown()).optional().describe("New or updated custom metadata for the feedback")
|
|
6844
7357
|
}
|
|
6845
7358
|
};
|
|
6846
7359
|
function registerTracingTools(server, service) {
|
|
@@ -6896,77 +7409,77 @@ function registerTracingTools(server, service) {
|
|
|
6896
7409
|
}
|
|
6897
7410
|
|
|
6898
7411
|
// src/tools/users.tools.ts
|
|
6899
|
-
import { z as
|
|
7412
|
+
import { z as z20 } from "zod";
|
|
6900
7413
|
var USERS_TOOL_SCHEMAS = {
|
|
6901
7414
|
listAllUsers: {
|
|
6902
|
-
current_page:
|
|
6903
|
-
page_size:
|
|
7415
|
+
current_page: z20.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
7416
|
+
page_size: z20.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
6904
7417
|
},
|
|
6905
7418
|
inviteUser: {
|
|
6906
|
-
email:
|
|
6907
|
-
role:
|
|
7419
|
+
email: z20.string().email().describe("Email address of the user to invite"),
|
|
7420
|
+
role: z20.enum(["admin", "member"]).describe(
|
|
6908
7421
|
"Organization-level role: 'admin' for full access, 'member' for limited access"
|
|
6909
7422
|
),
|
|
6910
|
-
first_name:
|
|
6911
|
-
last_name:
|
|
6912
|
-
workspaces:
|
|
6913
|
-
|
|
6914
|
-
id:
|
|
7423
|
+
first_name: z20.string().optional().describe("User's first name"),
|
|
7424
|
+
last_name: z20.string().optional().describe("User's last name"),
|
|
7425
|
+
workspaces: z20.array(
|
|
7426
|
+
z20.object({
|
|
7427
|
+
id: z20.string().describe(
|
|
6915
7428
|
"Workspace ID/slug where the user will be granted access"
|
|
6916
7429
|
),
|
|
6917
|
-
role:
|
|
7430
|
+
role: z20.enum(["admin", "member", "manager"]).describe(
|
|
6918
7431
|
"Workspace-level role: 'admin' for full access, 'manager' for workspace management, 'member' for basic access"
|
|
6919
7432
|
)
|
|
6920
7433
|
})
|
|
6921
7434
|
).describe(
|
|
6922
7435
|
"List of workspaces and corresponding roles to grant to the user"
|
|
6923
7436
|
),
|
|
6924
|
-
workspace_api_key_details:
|
|
6925
|
-
name:
|
|
6926
|
-
expiry:
|
|
6927
|
-
metadata:
|
|
6928
|
-
scopes:
|
|
7437
|
+
workspace_api_key_details: z20.object({
|
|
7438
|
+
name: z20.string().optional().describe("Name of the API key to be created"),
|
|
7439
|
+
expiry: z20.string().optional().describe("Expiration date for the API key (ISO8601 format)"),
|
|
7440
|
+
metadata: z20.record(z20.string(), z20.string()).optional().describe("Additional metadata key-value pairs for the API key"),
|
|
7441
|
+
scopes: z20.array(z20.string()).describe("List of permission scopes for the API key")
|
|
6929
7442
|
}).optional().describe("Optional API key to be created for the user")
|
|
6930
7443
|
},
|
|
6931
7444
|
getUserStats: {
|
|
6932
|
-
time_of_generation_min:
|
|
7445
|
+
time_of_generation_min: z20.string().describe(
|
|
6933
7446
|
"Start time for the analytics period (ISO8601 format, e.g., '2024-01-01T00:00:00Z')"
|
|
6934
7447
|
),
|
|
6935
|
-
time_of_generation_max:
|
|
7448
|
+
time_of_generation_max: z20.string().describe(
|
|
6936
7449
|
"End time for the analytics period (ISO8601 format, e.g., '2024-02-01T00:00:00Z')"
|
|
6937
7450
|
),
|
|
6938
|
-
total_units_min:
|
|
6939
|
-
total_units_max:
|
|
6940
|
-
cost_min:
|
|
6941
|
-
cost_max:
|
|
6942
|
-
status_code:
|
|
6943
|
-
virtual_keys:
|
|
6944
|
-
page_size:
|
|
7451
|
+
total_units_min: z20.coerce.number().positive().optional().describe("Minimum number of total tokens to filter by"),
|
|
7452
|
+
total_units_max: z20.coerce.number().positive().optional().describe("Maximum number of total tokens to filter by"),
|
|
7453
|
+
cost_min: z20.coerce.number().positive().optional().describe("Minimum cost in cents to filter by"),
|
|
7454
|
+
cost_max: z20.coerce.number().positive().optional().describe("Maximum cost in cents to filter by"),
|
|
7455
|
+
status_code: z20.string().optional().describe("Filter by specific HTTP status codes (comma-separated)"),
|
|
7456
|
+
virtual_keys: z20.string().optional().describe("Filter by specific virtual key slugs (comma-separated)"),
|
|
7457
|
+
page_size: z20.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
6945
7458
|
},
|
|
6946
7459
|
getUser: {
|
|
6947
|
-
user_id:
|
|
7460
|
+
user_id: z20.string().describe("The user ID to retrieve")
|
|
6948
7461
|
},
|
|
6949
7462
|
updateUser: {
|
|
6950
|
-
user_id:
|
|
6951
|
-
first_name:
|
|
6952
|
-
last_name:
|
|
6953
|
-
role:
|
|
7463
|
+
user_id: z20.string().describe("The user ID to update"),
|
|
7464
|
+
first_name: z20.string().optional().describe("New first name"),
|
|
7465
|
+
last_name: z20.string().optional().describe("New last name"),
|
|
7466
|
+
role: z20.enum(["admin", "member"]).optional().describe("New organization-level role")
|
|
6954
7467
|
},
|
|
6955
7468
|
deleteUser: {
|
|
6956
|
-
user_id:
|
|
7469
|
+
user_id: z20.string().describe("The user ID to delete")
|
|
6957
7470
|
},
|
|
6958
7471
|
listUserInvites: {
|
|
6959
|
-
current_page:
|
|
6960
|
-
page_size:
|
|
7472
|
+
current_page: z20.coerce.number().int().positive().optional().describe("Page number for pagination"),
|
|
7473
|
+
page_size: z20.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
|
|
6961
7474
|
},
|
|
6962
7475
|
getUserInvite: {
|
|
6963
|
-
invite_id:
|
|
7476
|
+
invite_id: z20.string().describe("The invite ID to retrieve")
|
|
6964
7477
|
},
|
|
6965
7478
|
deleteUserInvite: {
|
|
6966
|
-
invite_id:
|
|
7479
|
+
invite_id: z20.string().describe("The invite ID to delete")
|
|
6967
7480
|
},
|
|
6968
7481
|
resendUserInvite: {
|
|
6969
|
-
invite_id:
|
|
7482
|
+
invite_id: z20.string().describe("The invite ID to resend")
|
|
6970
7483
|
}
|
|
6971
7484
|
};
|
|
6972
7485
|
function formatUser(user) {
|
|
@@ -7192,59 +7705,59 @@ function registerUsersTools(server, service) {
|
|
|
7192
7705
|
}
|
|
7193
7706
|
|
|
7194
7707
|
// src/tools/workspaces.tools.ts
|
|
7195
|
-
import { z as
|
|
7708
|
+
import { z as z21 } from "zod";
|
|
7196
7709
|
var WORKSPACES_TOOL_SCHEMAS = {
|
|
7197
7710
|
listWorkspaces: {
|
|
7198
|
-
page_size:
|
|
7199
|
-
current_page:
|
|
7711
|
+
page_size: z21.coerce.number().int().positive().max(100).optional().describe("Number of workspaces to return per page (max 100)"),
|
|
7712
|
+
current_page: z21.coerce.number().int().positive().optional().describe("Page number to retrieve when results are paginated")
|
|
7200
7713
|
},
|
|
7201
7714
|
getWorkspace: {
|
|
7202
|
-
workspace_id:
|
|
7715
|
+
workspace_id: z21.string().describe(
|
|
7203
7716
|
"The unique identifier of the workspace to retrieve. This can be found in the workspace's URL or from the list_workspaces tool response"
|
|
7204
7717
|
)
|
|
7205
7718
|
},
|
|
7206
7719
|
createWorkspace: {
|
|
7207
|
-
name:
|
|
7208
|
-
slug:
|
|
7209
|
-
description:
|
|
7210
|
-
is_default:
|
|
7211
|
-
metadata:
|
|
7720
|
+
name: z21.string().describe("Name of the workspace"),
|
|
7721
|
+
slug: z21.string().optional().describe("URL-friendly slug (auto-generated if not provided)"),
|
|
7722
|
+
description: z21.string().optional().describe("Description of the workspace"),
|
|
7723
|
+
is_default: z21.coerce.number().optional().describe("Set as default workspace (1 = yes, 0 = no)"),
|
|
7724
|
+
metadata: z21.record(z21.string(), z21.string()).optional().describe("Custom metadata key-value pairs")
|
|
7212
7725
|
},
|
|
7213
7726
|
updateWorkspace: {
|
|
7214
|
-
workspace_id:
|
|
7215
|
-
name:
|
|
7216
|
-
slug:
|
|
7217
|
-
description:
|
|
7218
|
-
is_default:
|
|
7219
|
-
metadata:
|
|
7727
|
+
workspace_id: z21.string().describe("The workspace ID to update"),
|
|
7728
|
+
name: z21.string().optional().describe("New name for the workspace"),
|
|
7729
|
+
slug: z21.string().optional().describe("New slug for the workspace"),
|
|
7730
|
+
description: z21.string().optional().describe("New description"),
|
|
7731
|
+
is_default: z21.coerce.number().optional().describe("Set as default workspace (1 = yes, 0 = no)"),
|
|
7732
|
+
metadata: z21.record(z21.string(), z21.string()).optional().describe("New metadata key-value pairs")
|
|
7220
7733
|
},
|
|
7221
7734
|
deleteWorkspace: {
|
|
7222
|
-
workspace_id:
|
|
7735
|
+
workspace_id: z21.string().describe("The workspace ID to delete")
|
|
7223
7736
|
},
|
|
7224
7737
|
addWorkspaceMember: {
|
|
7225
|
-
workspace_id:
|
|
7226
|
-
user_id:
|
|
7738
|
+
workspace_id: z21.string().describe("The workspace ID to add the member to"),
|
|
7739
|
+
user_id: z21.string().uuid(
|
|
7227
7740
|
"user_id must be a valid UUID (use list_all_users to find user IDs)"
|
|
7228
7741
|
).describe(
|
|
7229
7742
|
"The user ID to add (must be a valid UUID from list_all_users, not an email address)"
|
|
7230
7743
|
),
|
|
7231
|
-
role:
|
|
7744
|
+
role: z21.enum(["admin", "member", "manager"]).describe("Role in the workspace")
|
|
7232
7745
|
},
|
|
7233
7746
|
listWorkspaceMembers: {
|
|
7234
|
-
workspace_id:
|
|
7747
|
+
workspace_id: z21.string().describe("The workspace ID to list members for")
|
|
7235
7748
|
},
|
|
7236
7749
|
getWorkspaceMember: {
|
|
7237
|
-
workspace_id:
|
|
7238
|
-
user_id:
|
|
7750
|
+
workspace_id: z21.string().describe("The workspace ID"),
|
|
7751
|
+
user_id: z21.string().describe("The user ID to retrieve")
|
|
7239
7752
|
},
|
|
7240
7753
|
updateWorkspaceMember: {
|
|
7241
|
-
workspace_id:
|
|
7242
|
-
user_id:
|
|
7243
|
-
role:
|
|
7754
|
+
workspace_id: z21.string().describe("The workspace ID"),
|
|
7755
|
+
user_id: z21.string().describe("The user ID to update"),
|
|
7756
|
+
role: z21.enum(["admin", "member", "manager"]).describe("New role in the workspace")
|
|
7244
7757
|
},
|
|
7245
7758
|
removeWorkspaceMember: {
|
|
7246
|
-
workspace_id:
|
|
7247
|
-
user_id:
|
|
7759
|
+
workspace_id: z21.string().describe("The workspace ID"),
|
|
7760
|
+
user_id: z21.string().describe("The user ID to remove")
|
|
7248
7761
|
}
|
|
7249
7762
|
};
|
|
7250
7763
|
function formatWorkspaceDefaults(defaults) {
|
|
@@ -7531,6 +8044,7 @@ var TOOL_DOMAIN_REGISTRARS = [
|
|
|
7531
8044
|
["tracing", registerTracingTools],
|
|
7532
8045
|
["logging", registerLoggingTools],
|
|
7533
8046
|
["providers", registerProvidersTools],
|
|
8047
|
+
["secret-references", registerSecretReferencesTools],
|
|
7534
8048
|
["integrations", registerIntegrationsTools],
|
|
7535
8049
|
["mcp-integrations", registerMcpIntegrationsTools],
|
|
7536
8050
|
["mcp-servers", registerMcpServersTools]
|
|
@@ -7653,13 +8167,81 @@ function getToolErrorMessage(error) {
|
|
|
7653
8167
|
return String(error);
|
|
7654
8168
|
}
|
|
7655
8169
|
var STANDARD_TOOL_OUTPUT_SCHEMA = {
|
|
7656
|
-
ok:
|
|
7657
|
-
data:
|
|
7658
|
-
error:
|
|
7659
|
-
message:
|
|
7660
|
-
details:
|
|
8170
|
+
ok: z22.boolean().describe("Whether the tool call succeeded and returned structured data"),
|
|
8171
|
+
data: z22.unknown().optional().describe("Structured success payload when ok is true"),
|
|
8172
|
+
error: z22.object({
|
|
8173
|
+
message: z22.string().describe("Human-readable error message"),
|
|
8174
|
+
details: z22.unknown().optional().describe("Optional structured error details")
|
|
7661
8175
|
}).optional().describe("Structured error payload when ok is false")
|
|
7662
8176
|
};
|
|
8177
|
+
var TOOL_SUCCESS_DATA_SCHEMAS = {
|
|
8178
|
+
rotate_api_key: z22.object({
|
|
8179
|
+
message: z22.string().describe("Rotation confirmation"),
|
|
8180
|
+
warning: z22.string().describe("Required handling guidance for the one-time secret"),
|
|
8181
|
+
id: z22.string().uuid().describe("Rotated API key UUID"),
|
|
8182
|
+
key: z22.string().describe("New API key secret, returned only once"),
|
|
8183
|
+
key_transition_expires_at: z22.iso.datetime().describe("Time when the previous key stops working")
|
|
8184
|
+
}),
|
|
8185
|
+
create_secret_reference: z22.object({
|
|
8186
|
+
message: z22.string().describe("Creation confirmation"),
|
|
8187
|
+
id: z22.string().uuid().describe("New Secret Reference UUID"),
|
|
8188
|
+
slug: z22.string().describe("New Secret Reference slug")
|
|
8189
|
+
}),
|
|
8190
|
+
list_secret_references: z22.object({
|
|
8191
|
+
total: z22.number().int().nonnegative().describe("Total matching references"),
|
|
8192
|
+
secret_references: z22.array(
|
|
8193
|
+
z22.object({
|
|
8194
|
+
id: z22.string().uuid().describe("Secret Reference UUID"),
|
|
8195
|
+
name: z22.string().describe("Human-readable name"),
|
|
8196
|
+
slug: z22.string().describe("Stable Secret Reference slug"),
|
|
8197
|
+
manager_type: SecretManagerTypeSchema.describe(
|
|
8198
|
+
"External secret manager type"
|
|
8199
|
+
),
|
|
8200
|
+
status: z22.literal("ACTIVE").describe("Current reference status"),
|
|
8201
|
+
created_at: z22.iso.datetime().describe("ISO 8601 creation timestamp"),
|
|
8202
|
+
last_updated_at: z22.iso.datetime().describe("ISO 8601 last-update timestamp")
|
|
8203
|
+
})
|
|
8204
|
+
).describe(
|
|
8205
|
+
"Current page of Secret References without authentication values"
|
|
8206
|
+
)
|
|
8207
|
+
}),
|
|
8208
|
+
get_secret_reference: z22.object({
|
|
8209
|
+
id: z22.string().uuid().describe("Secret Reference UUID"),
|
|
8210
|
+
organisation_id: z22.string().uuid().describe("Owning organisation UUID"),
|
|
8211
|
+
name: z22.string().describe("Human-readable name"),
|
|
8212
|
+
slug: z22.string().describe("Stable Secret Reference slug"),
|
|
8213
|
+
description: z22.string().nullable().describe("Reference description"),
|
|
8214
|
+
manager_type: SecretManagerTypeSchema.describe(
|
|
8215
|
+
"External secret manager type"
|
|
8216
|
+
),
|
|
8217
|
+
secret_path: z22.string().describe("Path in the external secret manager"),
|
|
8218
|
+
secret_key: z22.string().nullable().describe("Selected key within a structured secret"),
|
|
8219
|
+
allow_all_workspaces: z22.boolean().describe("Whether all workspaces may use the reference"),
|
|
8220
|
+
tags: z22.record(z22.string(), z22.string()).nullable().describe("String metadata tags"),
|
|
8221
|
+
status: z22.literal("ACTIVE").describe("Current reference status"),
|
|
8222
|
+
created_by: z22.string().describe("Creator identifier"),
|
|
8223
|
+
created_at: z22.iso.datetime().describe("ISO 8601 creation timestamp"),
|
|
8224
|
+
last_updated_at: z22.iso.datetime().describe("ISO 8601 last-update timestamp"),
|
|
8225
|
+
auth_config: z22.record(z22.string(), z22.unknown()).describe("Authentication configuration with sensitive values redacted"),
|
|
8226
|
+
object: z22.literal("secret-reference").describe("Portkey object type")
|
|
8227
|
+
}),
|
|
8228
|
+
update_secret_reference: z22.object({
|
|
8229
|
+
message: z22.string().describe("Update confirmation"),
|
|
8230
|
+
success: z22.literal(true).describe("Whether the update succeeded")
|
|
8231
|
+
}),
|
|
8232
|
+
delete_secret_reference: z22.object({
|
|
8233
|
+
message: z22.string().describe("Deletion confirmation"),
|
|
8234
|
+
success: z22.literal(true).describe("Whether the deletion succeeded")
|
|
8235
|
+
})
|
|
8236
|
+
};
|
|
8237
|
+
function getToolOutputSchema(toolName) {
|
|
8238
|
+
const dataSchema = TOOL_SUCCESS_DATA_SCHEMAS[toolName];
|
|
8239
|
+
if (!dataSchema) return STANDARD_TOOL_OUTPUT_SCHEMA;
|
|
8240
|
+
return {
|
|
8241
|
+
...STANDARD_TOOL_OUTPUT_SCHEMA,
|
|
8242
|
+
data: dataSchema.optional().describe("Structured success payload when ok is true")
|
|
8243
|
+
};
|
|
8244
|
+
}
|
|
7663
8245
|
function isStandardToolEnvelope(value) {
|
|
7664
8246
|
if (!isRecord(value) || typeof value.ok !== "boolean") {
|
|
7665
8247
|
return false;
|
|
@@ -7806,7 +8388,7 @@ function createSafeToolServer(server) {
|
|
|
7806
8388
|
{
|
|
7807
8389
|
...registration.description ? { description: registration.description } : {},
|
|
7808
8390
|
...registration.inputSchema !== void 0 ? { inputSchema: registration.inputSchema } : {},
|
|
7809
|
-
outputSchema:
|
|
8391
|
+
outputSchema: getToolOutputSchema(name),
|
|
7810
8392
|
annotations: registration.annotations
|
|
7811
8393
|
},
|
|
7812
8394
|
registration.callback
|
|
@@ -7841,7 +8423,7 @@ function registerAllTools(server, service, options = {}) {
|
|
|
7841
8423
|
}
|
|
7842
8424
|
|
|
7843
8425
|
// src/lib/auth.ts
|
|
7844
|
-
import
|
|
8426
|
+
import crypto2 from "node:crypto";
|
|
7845
8427
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
7846
8428
|
var AUTH_SCHEMES = {
|
|
7847
8429
|
bearer: "Bearer"
|
|
@@ -7956,9 +8538,9 @@ function extractBearerToken(req) {
|
|
|
7956
8538
|
return token.trim();
|
|
7957
8539
|
}
|
|
7958
8540
|
function timingSafeEqual(a, b) {
|
|
7959
|
-
const left =
|
|
7960
|
-
const right =
|
|
7961
|
-
return
|
|
8541
|
+
const left = crypto2.createHash("sha256").update(a, "utf8").digest();
|
|
8542
|
+
const right = crypto2.createHash("sha256").update(b, "utf8").digest();
|
|
8543
|
+
return crypto2.timingSafeEqual(left, right);
|
|
7962
8544
|
}
|
|
7963
8545
|
var jwksCache = /* @__PURE__ */ new Map();
|
|
7964
8546
|
async function verifyClerkToken(token, config) {
|
|
@@ -8022,10 +8604,17 @@ async function mcpAuthMiddleware(req, res, next) {
|
|
|
8022
8604
|
}
|
|
8023
8605
|
|
|
8024
8606
|
// src/lib/config.ts
|
|
8607
|
+
function parseStrictInteger(value) {
|
|
8608
|
+
if (!/^\d+$/.test(value)) {
|
|
8609
|
+
return Number.NaN;
|
|
8610
|
+
}
|
|
8611
|
+
const parsed = Number(value);
|
|
8612
|
+
return Number.isSafeInteger(parsed) ? parsed : Number.NaN;
|
|
8613
|
+
}
|
|
8025
8614
|
function getServerConfig() {
|
|
8026
8615
|
const transport = process.env.MCP_TRANSPORT?.trim() || "stdio";
|
|
8027
8616
|
const sessionMode = process.env.MCP_SESSION_MODE?.trim().toLowerCase() || "stateful";
|
|
8028
|
-
const eventStoreMode = process.env.MCP_EVENT_STORE?.trim().toLowerCase() ||
|
|
8617
|
+
const eventStoreMode = process.env.MCP_EVENT_STORE?.trim().toLowerCase() || "off";
|
|
8029
8618
|
if (transport !== "stdio" && transport !== "http") {
|
|
8030
8619
|
throw new Error(
|
|
8031
8620
|
`Invalid MCP_TRANSPORT value: ${transport}. Must be 'stdio' or 'http'`
|
|
@@ -8041,13 +8630,12 @@ function getServerConfig() {
|
|
|
8041
8630
|
`Invalid MCP_EVENT_STORE value: ${eventStoreMode}. Must be 'off', 'memory', or 'redis'`
|
|
8042
8631
|
);
|
|
8043
8632
|
}
|
|
8044
|
-
const
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
);
|
|
8633
|
+
const portVariable = process.env.PORT?.trim() ? "PORT" : "MCP_PORT";
|
|
8634
|
+
const portValue = process.env.PORT?.trim() || process.env.MCP_PORT?.trim() || "3000";
|
|
8635
|
+
const port = parseStrictInteger(portValue);
|
|
8048
8636
|
if (Number.isNaN(port) || port < 1 || port > 65535) {
|
|
8049
8637
|
throw new Error(
|
|
8050
|
-
`Invalid
|
|
8638
|
+
`Invalid ${portVariable} value: ${portValue}. Must be a valid port number (1-65535)`
|
|
8051
8639
|
);
|
|
8052
8640
|
}
|
|
8053
8641
|
let host;
|
|
@@ -8061,21 +8649,28 @@ function getServerConfig() {
|
|
|
8061
8649
|
host = "127.0.0.1";
|
|
8062
8650
|
}
|
|
8063
8651
|
const sessionTimeoutStr = (process.env.MCP_SESSION_TIMEOUT || "3600000").trim();
|
|
8064
|
-
const sessionTimeout =
|
|
8652
|
+
const sessionTimeout = parseStrictInteger(sessionTimeoutStr);
|
|
8065
8653
|
if (Number.isNaN(sessionTimeout) || sessionTimeout < 0) {
|
|
8066
8654
|
throw new Error(
|
|
8067
8655
|
`Invalid MCP_SESSION_TIMEOUT value: ${sessionTimeoutStr}. Must be a non-negative number`
|
|
8068
8656
|
);
|
|
8069
8657
|
}
|
|
8658
|
+
const shutdownTimeoutStr = (process.env.MCP_SHUTDOWN_TIMEOUT_MS || "10000").trim();
|
|
8659
|
+
const shutdownTimeout = parseStrictInteger(shutdownTimeoutStr);
|
|
8660
|
+
if (Number.isNaN(shutdownTimeout) || shutdownTimeout <= 0) {
|
|
8661
|
+
throw new Error(
|
|
8662
|
+
`Invalid MCP_SHUTDOWN_TIMEOUT_MS value: ${shutdownTimeoutStr}. Must be a positive integer`
|
|
8663
|
+
);
|
|
8664
|
+
}
|
|
8070
8665
|
const maxSessionsStr = (process.env.MCP_MAX_SESSIONS || "100").trim();
|
|
8071
|
-
const maxSessions =
|
|
8666
|
+
const maxSessions = parseStrictInteger(maxSessionsStr);
|
|
8072
8667
|
if (!Number.isInteger(maxSessions) || maxSessions <= 0) {
|
|
8073
8668
|
throw new Error(
|
|
8074
8669
|
`Invalid MCP_MAX_SESSIONS value: ${maxSessionsStr}. Must be a positive integer`
|
|
8075
8670
|
);
|
|
8076
8671
|
}
|
|
8077
8672
|
const eventStoreTtlStr = (process.env.MCP_EVENT_TTL_SECONDS || "3600").trim();
|
|
8078
|
-
const eventStoreTtlSeconds =
|
|
8673
|
+
const eventStoreTtlSeconds = parseStrictInteger(eventStoreTtlStr);
|
|
8079
8674
|
if (Number.isNaN(eventStoreTtlSeconds) || eventStoreTtlSeconds <= 0) {
|
|
8080
8675
|
throw new Error(
|
|
8081
8676
|
`Invalid MCP_EVENT_TTL_SECONDS value: ${eventStoreTtlStr}. Must be a positive integer`
|
|
@@ -8114,6 +8709,7 @@ function getServerConfig() {
|
|
|
8114
8709
|
host,
|
|
8115
8710
|
maxSessions,
|
|
8116
8711
|
sessionTimeout,
|
|
8712
|
+
shutdownTimeout,
|
|
8117
8713
|
tls: {
|
|
8118
8714
|
enabled: tlsEnabled,
|
|
8119
8715
|
keyPath,
|
|
@@ -8124,6 +8720,7 @@ function getServerConfig() {
|
|
|
8124
8720
|
}
|
|
8125
8721
|
|
|
8126
8722
|
// src/lib/event-store.ts
|
|
8723
|
+
import { randomUUID } from "node:crypto";
|
|
8127
8724
|
var EVENT_STORE_CLEANUP_INTERVAL_MS = 3e4;
|
|
8128
8725
|
var SAFE_EVENT_ID_PATTERN = /^[\w-]{1,128}$/;
|
|
8129
8726
|
function assertSafeRedisId(id, kind) {
|
|
@@ -8135,10 +8732,10 @@ function assertSafeRedisId(id, kind) {
|
|
|
8135
8732
|
return id;
|
|
8136
8733
|
}
|
|
8137
8734
|
var InMemoryEventStore = class {
|
|
8138
|
-
sequence = 0;
|
|
8139
8735
|
ttlMs;
|
|
8140
8736
|
events = /* @__PURE__ */ new Map();
|
|
8141
8737
|
streamEvents = /* @__PURE__ */ new Map();
|
|
8738
|
+
activeReplayStreams = /* @__PURE__ */ new Set();
|
|
8142
8739
|
lastCleanupAt = 0;
|
|
8143
8740
|
constructor(ttlSeconds) {
|
|
8144
8741
|
this.ttlMs = ttlSeconds * 1e3;
|
|
@@ -8194,8 +8791,7 @@ var InMemoryEventStore = class {
|
|
|
8194
8791
|
}
|
|
8195
8792
|
async storeEvent(streamId, message) {
|
|
8196
8793
|
this.maybeCleanupExpired();
|
|
8197
|
-
|
|
8198
|
-
const eventId = String(this.sequence);
|
|
8794
|
+
const eventId = randomUUID();
|
|
8199
8795
|
this.events.set(eventId, {
|
|
8200
8796
|
streamId,
|
|
8201
8797
|
message,
|
|
@@ -8211,6 +8807,26 @@ var InMemoryEventStore = class {
|
|
|
8211
8807
|
this.maybeCleanupExpired(now);
|
|
8212
8808
|
return this.getEventIfUnexpired(eventId, now)?.streamId;
|
|
8213
8809
|
}
|
|
8810
|
+
async acquireReplayLease(eventId) {
|
|
8811
|
+
const streamId = await this.getStreamIdForEventId(eventId);
|
|
8812
|
+
if (!streamId) {
|
|
8813
|
+
return { status: "missing" };
|
|
8814
|
+
}
|
|
8815
|
+
if (this.activeReplayStreams.has(streamId)) {
|
|
8816
|
+
return { status: "conflict" };
|
|
8817
|
+
}
|
|
8818
|
+
this.activeReplayStreams.add(streamId);
|
|
8819
|
+
let released = false;
|
|
8820
|
+
return {
|
|
8821
|
+
status: "acquired",
|
|
8822
|
+
release: async () => {
|
|
8823
|
+
if (!released) {
|
|
8824
|
+
released = true;
|
|
8825
|
+
this.activeReplayStreams.delete(streamId);
|
|
8826
|
+
}
|
|
8827
|
+
}
|
|
8828
|
+
};
|
|
8829
|
+
}
|
|
8214
8830
|
async replayEventsAfter(lastEventId, {
|
|
8215
8831
|
send
|
|
8216
8832
|
}) {
|
|
@@ -8257,10 +8873,21 @@ var RedisEventStore = class {
|
|
|
8257
8873
|
streamEventsKey(streamId) {
|
|
8258
8874
|
return `${this.keyPrefix}:stream:${assertSafeRedisId(streamId, "streamId")}:events`;
|
|
8259
8875
|
}
|
|
8876
|
+
replayLeaseKey(streamId) {
|
|
8877
|
+
return `${this.keyPrefix}:stream:${assertSafeRedisId(streamId, "streamId")}:replay-lease`;
|
|
8878
|
+
}
|
|
8260
8879
|
async ensureConnected() {
|
|
8261
8880
|
if (!this.client) {
|
|
8262
8881
|
const { createClient } = await import("redis");
|
|
8263
|
-
this.client = createClient({
|
|
8882
|
+
this.client = createClient({
|
|
8883
|
+
url: this.redisUrl,
|
|
8884
|
+
// node-redis v6 defaults to RESP3, a 5-second command timeout, and a
|
|
8885
|
+
// 30-second keepalive delay. Keep the event store's v5 behavior stable
|
|
8886
|
+
// while taking the v6 fixes and supported runtime baseline.
|
|
8887
|
+
RESP: 2,
|
|
8888
|
+
socket: { keepAliveInitialDelay: 5e3 },
|
|
8889
|
+
commandOptions: { timeout: void 0 }
|
|
8890
|
+
});
|
|
8264
8891
|
this.client.on("error", (error) => {
|
|
8265
8892
|
Logger.error("Redis event store error", {
|
|
8266
8893
|
metadata: {
|
|
@@ -8289,17 +8916,19 @@ var RedisEventStore = class {
|
|
|
8289
8916
|
async storeEvent(streamId, message) {
|
|
8290
8917
|
await this.ensureConnected();
|
|
8291
8918
|
const client = this.getConnectedClient();
|
|
8292
|
-
const
|
|
8919
|
+
const sequence = await client.incr(this.counterKey());
|
|
8920
|
+
const eventId = randomUUID();
|
|
8293
8921
|
const eventKey = this.eventKey(eventId);
|
|
8294
8922
|
const streamKey = this.streamEventsKey(streamId);
|
|
8295
8923
|
const tx = client.multi();
|
|
8296
8924
|
tx.hSet(eventKey, {
|
|
8297
8925
|
streamId,
|
|
8926
|
+
sequence: String(sequence),
|
|
8298
8927
|
message: JSON.stringify(message)
|
|
8299
8928
|
});
|
|
8300
8929
|
tx.expire(eventKey, this.ttlSeconds);
|
|
8301
8930
|
tx.zAdd(streamKey, {
|
|
8302
|
-
score:
|
|
8931
|
+
score: sequence,
|
|
8303
8932
|
value: eventId
|
|
8304
8933
|
});
|
|
8305
8934
|
tx.expire(streamKey, this.ttlSeconds);
|
|
@@ -8317,6 +8946,36 @@ var RedisEventStore = class {
|
|
|
8317
8946
|
);
|
|
8318
8947
|
return streamId || void 0;
|
|
8319
8948
|
}
|
|
8949
|
+
async acquireReplayLease(eventId) {
|
|
8950
|
+
const streamId = await this.getStreamIdForEventId(eventId);
|
|
8951
|
+
if (!streamId) {
|
|
8952
|
+
return { status: "missing" };
|
|
8953
|
+
}
|
|
8954
|
+
const client = this.getConnectedClient();
|
|
8955
|
+
const leaseKey = this.replayLeaseKey(streamId);
|
|
8956
|
+
const ownerToken = randomUUID();
|
|
8957
|
+
const acquired = await client.set(leaseKey, ownerToken, {
|
|
8958
|
+
NX: true,
|
|
8959
|
+
PX: 6e4
|
|
8960
|
+
});
|
|
8961
|
+
if (acquired !== "OK") {
|
|
8962
|
+
return { status: "conflict" };
|
|
8963
|
+
}
|
|
8964
|
+
let released = false;
|
|
8965
|
+
return {
|
|
8966
|
+
status: "acquired",
|
|
8967
|
+
release: async () => {
|
|
8968
|
+
if (released) {
|
|
8969
|
+
return;
|
|
8970
|
+
}
|
|
8971
|
+
released = true;
|
|
8972
|
+
await client.eval(
|
|
8973
|
+
"if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end",
|
|
8974
|
+
{ keys: [leaseKey], arguments: [ownerToken] }
|
|
8975
|
+
);
|
|
8976
|
+
}
|
|
8977
|
+
};
|
|
8978
|
+
}
|
|
8320
8979
|
async replayEventsAfter(lastEventId, {
|
|
8321
8980
|
send
|
|
8322
8981
|
}) {
|
|
@@ -8327,9 +8986,9 @@ var RedisEventStore = class {
|
|
|
8327
8986
|
if (!streamId) {
|
|
8328
8987
|
throw new Error(`Event not found for replay: ${lastEventId}`);
|
|
8329
8988
|
}
|
|
8330
|
-
const baseScore = Number(
|
|
8989
|
+
const baseScore = Number(baseEvent.sequence);
|
|
8331
8990
|
if (!Number.isFinite(baseScore)) {
|
|
8332
|
-
throw new Error(`Invalid replay event
|
|
8991
|
+
throw new Error(`Invalid replay sequence for event: ${lastEventId}`);
|
|
8333
8992
|
}
|
|
8334
8993
|
const eventIds = await client.zRangeByScore(
|
|
8335
8994
|
this.streamEventsKey(streamId),
|
|
@@ -8370,7 +9029,7 @@ var RedisEventStore = class {
|
|
|
8370
9029
|
}
|
|
8371
9030
|
}
|
|
8372
9031
|
if (this.client.isOpen) {
|
|
8373
|
-
await this.client.
|
|
9032
|
+
await this.client.close();
|
|
8374
9033
|
}
|
|
8375
9034
|
}
|
|
8376
9035
|
};
|
|
@@ -8383,9 +9042,11 @@ function createManagedEventStore(config) {
|
|
|
8383
9042
|
};
|
|
8384
9043
|
}
|
|
8385
9044
|
if (config.eventStore.mode === "memory") {
|
|
9045
|
+
const memoryStore = new InMemoryEventStore(config.eventStore.ttlSeconds);
|
|
8386
9046
|
return {
|
|
8387
9047
|
mode: "memory",
|
|
8388
|
-
eventStore:
|
|
9048
|
+
eventStore: memoryStore,
|
|
9049
|
+
acquireReplayLease: (eventId) => memoryStore.acquireReplayLease(eventId),
|
|
8389
9050
|
close: async () => {
|
|
8390
9051
|
}
|
|
8391
9052
|
};
|
|
@@ -8398,6 +9059,7 @@ function createManagedEventStore(config) {
|
|
|
8398
9059
|
return {
|
|
8399
9060
|
mode: "redis",
|
|
8400
9061
|
eventStore: redisStore,
|
|
9062
|
+
acquireReplayLease: (eventId) => redisStore.acquireReplayLease(eventId),
|
|
8401
9063
|
close: async () => {
|
|
8402
9064
|
await redisStore.close();
|
|
8403
9065
|
}
|
|
@@ -8407,7 +9069,7 @@ function createManagedEventStore(config) {
|
|
|
8407
9069
|
// src/lib/mcp-server.ts
|
|
8408
9070
|
import { readFileSync } from "node:fs";
|
|
8409
9071
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8410
|
-
import { z as
|
|
9072
|
+
import { z as z23 } from "zod";
|
|
8411
9073
|
var PACKAGE_JSON_URL_CANDIDATES = [
|
|
8412
9074
|
new URL("../../package.json", import.meta.url),
|
|
8413
9075
|
new URL("../package.json", import.meta.url)
|
|
@@ -8480,8 +9142,8 @@ function registerServerPromptsAndResources(server) {
|
|
|
8480
9142
|
title: "Plan Portkey Admin Workflow",
|
|
8481
9143
|
description: "Create a concise, safe plan for a Portkey Admin API task using this MCP server.",
|
|
8482
9144
|
argsSchema: {
|
|
8483
|
-
task:
|
|
8484
|
-
area:
|
|
9145
|
+
task: z23.string().min(1).max(500).describe("Portkey admin task to plan, such as promoting a prompt"),
|
|
9146
|
+
area: z23.string().max(80).optional().describe(
|
|
8485
9147
|
"Optional Portkey area, such as prompts, analytics, configs, or users"
|
|
8486
9148
|
)
|
|
8487
9149
|
}
|
|
@@ -8576,7 +9238,16 @@ function parseOriginParts(value) {
|
|
|
8576
9238
|
}
|
|
8577
9239
|
}
|
|
8578
9240
|
function normalizeHostWithoutPort(value) {
|
|
8579
|
-
|
|
9241
|
+
const normalized = value.trim().toLowerCase();
|
|
9242
|
+
if (normalized.startsWith("[")) {
|
|
9243
|
+
const bracketEnd = normalized.indexOf("]");
|
|
9244
|
+
if (bracketEnd < 0) {
|
|
9245
|
+
return normalized;
|
|
9246
|
+
}
|
|
9247
|
+
const remainder = normalized.slice(bracketEnd + 1);
|
|
9248
|
+
return remainder === "" || /^:\d+$/.test(remainder) ? normalized.slice(0, bracketEnd + 1) : normalized;
|
|
9249
|
+
}
|
|
9250
|
+
return normalized.split(":", 1)[0];
|
|
8580
9251
|
}
|
|
8581
9252
|
function isOriginMatch(origin, allowedOrigin) {
|
|
8582
9253
|
const originParts = parseOriginParts(origin);
|
|
@@ -8600,7 +9271,14 @@ function resolveAllowedOrigins() {
|
|
|
8600
9271
|
return parsed;
|
|
8601
9272
|
}
|
|
8602
9273
|
}
|
|
8603
|
-
return [
|
|
9274
|
+
return [
|
|
9275
|
+
"http://localhost",
|
|
9276
|
+
"https://localhost",
|
|
9277
|
+
"http://127.0.0.1",
|
|
9278
|
+
"https://127.0.0.1",
|
|
9279
|
+
"http://[::1]",
|
|
9280
|
+
"https://[::1]"
|
|
9281
|
+
];
|
|
8604
9282
|
}
|
|
8605
9283
|
var ALLOWED_ORIGINS = resolveAllowedOrigins();
|
|
8606
9284
|
function getAllowedOrigins() {
|
|
@@ -8669,7 +9347,8 @@ function parsePositiveIntegerEnv(name, fallback) {
|
|
|
8669
9347
|
if (raw === void 0) {
|
|
8670
9348
|
return fallback;
|
|
8671
9349
|
}
|
|
8672
|
-
const
|
|
9350
|
+
const normalized = raw.trim();
|
|
9351
|
+
const parsed = /^\d+$/.test(normalized) ? Number(normalized) : Number.NaN;
|
|
8673
9352
|
if (Number.isFinite(parsed) && Number.isInteger(parsed) && parsed > 0) {
|
|
8674
9353
|
return parsed;
|
|
8675
9354
|
}
|
|
@@ -8951,6 +9630,17 @@ var SessionStore = class {
|
|
|
8951
9630
|
};
|
|
8952
9631
|
|
|
8953
9632
|
// src/lib/http-app.ts
|
|
9633
|
+
function waitForResponseWritable(response) {
|
|
9634
|
+
return new Promise((resolve) => {
|
|
9635
|
+
const done = () => {
|
|
9636
|
+
response.off("drain", done);
|
|
9637
|
+
response.off("close", done);
|
|
9638
|
+
resolve();
|
|
9639
|
+
};
|
|
9640
|
+
response.once("drain", done);
|
|
9641
|
+
response.once("close", done);
|
|
9642
|
+
});
|
|
9643
|
+
}
|
|
8954
9644
|
function getReadyCheckMode() {
|
|
8955
9645
|
const readyCheckMode = process.env.MCP_READY_CHECK_MODE?.trim().toLowerCase() || "local";
|
|
8956
9646
|
if (readyCheckMode !== "local" && readyCheckMode !== "portkey") {
|
|
@@ -9114,7 +9804,7 @@ function getMcpProtocolVersion(req) {
|
|
|
9114
9804
|
}
|
|
9115
9805
|
function validateRequiredProtocolVersion(protocolVersion, expectedProtocolVersion) {
|
|
9116
9806
|
if (!protocolVersion) {
|
|
9117
|
-
return
|
|
9807
|
+
return void 0;
|
|
9118
9808
|
}
|
|
9119
9809
|
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
|
|
9120
9810
|
const safe = sanitizeProtocolVersion(protocolVersion);
|
|
@@ -9146,6 +9836,8 @@ function createHttpAppRuntime() {
|
|
|
9146
9836
|
const isStatefulSessionMode = config.sessionMode === "stateful";
|
|
9147
9837
|
const publicBaseUrl = buildConfiguredPublicBaseUrl(config);
|
|
9148
9838
|
const sessionStore = new SessionStore(config.maxSessions);
|
|
9839
|
+
const activeStatelessConnections = /* @__PURE__ */ new Set();
|
|
9840
|
+
const activeReplayOperations = /* @__PURE__ */ new Set();
|
|
9149
9841
|
const app = express();
|
|
9150
9842
|
let isReady = false;
|
|
9151
9843
|
let server;
|
|
@@ -9154,11 +9846,31 @@ function createHttpAppRuntime() {
|
|
|
9154
9846
|
let sigintHandler;
|
|
9155
9847
|
let sigtermHandler;
|
|
9156
9848
|
async function handleStatelessRequest(req, res, context, parsedBody, toolDomains) {
|
|
9849
|
+
let replayStreamId;
|
|
9850
|
+
let responseDisconnected = false;
|
|
9851
|
+
const storedMessages = /* @__PURE__ */ new WeakSet();
|
|
9852
|
+
const sharedEventStore = managedEventStore.eventStore;
|
|
9853
|
+
const requestEventStore = sharedEventStore ? {
|
|
9854
|
+
storeEvent: async (streamId, message) => {
|
|
9855
|
+
replayStreamId ??= streamId;
|
|
9856
|
+
storedMessages.add(message);
|
|
9857
|
+
return sharedEventStore.storeEvent(streamId, message);
|
|
9858
|
+
},
|
|
9859
|
+
getStreamIdForEventId: async (eventId) => sharedEventStore.getStreamIdForEventId?.(eventId),
|
|
9860
|
+
replayEventsAfter: (lastEventId, options) => sharedEventStore.replayEventsAfter(lastEventId, options)
|
|
9861
|
+
} : void 0;
|
|
9157
9862
|
const transport = new StreamableHTTPServerTransport({
|
|
9158
9863
|
sessionIdGenerator: void 0,
|
|
9159
|
-
eventStore:
|
|
9864
|
+
eventStore: requestEventStore
|
|
9160
9865
|
});
|
|
9161
9866
|
const { server: mcpServer } = createMcpServer({ toolDomains });
|
|
9867
|
+
const requestMessages = Array.isArray(parsedBody) ? parsedBody : [parsedBody];
|
|
9868
|
+
const pendingRequestIds = /* @__PURE__ */ new Set();
|
|
9869
|
+
for (const message of requestMessages) {
|
|
9870
|
+
if (isRecord(message) && typeof message.method === "string" && (typeof message.id === "string" || typeof message.id === "number")) {
|
|
9871
|
+
pendingRequestIds.add(message.id);
|
|
9872
|
+
}
|
|
9873
|
+
}
|
|
9162
9874
|
let closePromise;
|
|
9163
9875
|
const closeConnection = () => {
|
|
9164
9876
|
if (!closePromise) {
|
|
@@ -9169,16 +9881,60 @@ function createHttpAppRuntime() {
|
|
|
9169
9881
|
error: error instanceof Error ? error.message : String(error)
|
|
9170
9882
|
}
|
|
9171
9883
|
});
|
|
9884
|
+
}).finally(() => {
|
|
9885
|
+
activeStatelessConnections.delete(closeConnection);
|
|
9172
9886
|
});
|
|
9173
9887
|
}
|
|
9174
9888
|
return closePromise;
|
|
9175
9889
|
};
|
|
9890
|
+
activeStatelessConnections.add(closeConnection);
|
|
9891
|
+
const originalSend = transport.send.bind(transport);
|
|
9892
|
+
transport.send = async (message, options) => {
|
|
9893
|
+
if ((responseDisconnected || res.destroyed) && replayStreamId && sharedEventStore) {
|
|
9894
|
+
await sharedEventStore.storeEvent(replayStreamId, message);
|
|
9895
|
+
storedMessages.add(message);
|
|
9896
|
+
} else {
|
|
9897
|
+
try {
|
|
9898
|
+
await originalSend(message, options);
|
|
9899
|
+
} catch (error) {
|
|
9900
|
+
const disconnected = error instanceof Error && error.message.startsWith(
|
|
9901
|
+
"No connection established for request ID:"
|
|
9902
|
+
);
|
|
9903
|
+
if (!disconnected || !replayStreamId || !sharedEventStore) {
|
|
9904
|
+
throw error;
|
|
9905
|
+
}
|
|
9906
|
+
if (!storedMessages.has(message)) {
|
|
9907
|
+
await sharedEventStore.storeEvent(replayStreamId, message);
|
|
9908
|
+
storedMessages.add(message);
|
|
9909
|
+
}
|
|
9910
|
+
}
|
|
9911
|
+
if ((responseDisconnected || res.destroyed) && replayStreamId && sharedEventStore && !storedMessages.has(message)) {
|
|
9912
|
+
await sharedEventStore.storeEvent(replayStreamId, message);
|
|
9913
|
+
storedMessages.add(message);
|
|
9914
|
+
}
|
|
9915
|
+
}
|
|
9916
|
+
if ("id" in message && ("result" in message || "error" in message)) {
|
|
9917
|
+
pendingRequestIds.delete(message.id);
|
|
9918
|
+
if (pendingRequestIds.size === 0) {
|
|
9919
|
+
queueMicrotask(() => {
|
|
9920
|
+
void closeConnection();
|
|
9921
|
+
});
|
|
9922
|
+
}
|
|
9923
|
+
}
|
|
9924
|
+
};
|
|
9176
9925
|
res.once("close", () => {
|
|
9177
|
-
|
|
9926
|
+
if (pendingRequestIds.size > 0 && replayStreamId) {
|
|
9927
|
+
responseDisconnected = true;
|
|
9928
|
+
} else {
|
|
9929
|
+
void closeConnection();
|
|
9930
|
+
}
|
|
9178
9931
|
});
|
|
9179
9932
|
try {
|
|
9180
9933
|
await mcpServer.connect(transport);
|
|
9181
9934
|
await transport.handleRequest(req, res, parsedBody);
|
|
9935
|
+
if (pendingRequestIds.size === 0) {
|
|
9936
|
+
await closeConnection();
|
|
9937
|
+
}
|
|
9182
9938
|
} catch (error) {
|
|
9183
9939
|
await closeConnection();
|
|
9184
9940
|
throw error;
|
|
@@ -9208,10 +9964,15 @@ function createHttpAppRuntime() {
|
|
|
9208
9964
|
app.use(mcpAuthMiddleware);
|
|
9209
9965
|
app.use(
|
|
9210
9966
|
(err, _req, res, next) => {
|
|
9211
|
-
|
|
9967
|
+
const errorType = err && typeof err === "object" && "type" in err ? err.type : void 0;
|
|
9968
|
+
if (errorType === "entity.too.large") {
|
|
9212
9969
|
res.status(413).json({ error: "Payload too large" });
|
|
9213
9970
|
return;
|
|
9214
9971
|
}
|
|
9972
|
+
if (errorType === "entity.parse.failed") {
|
|
9973
|
+
res.status(400).json({ error: "Malformed JSON request body" });
|
|
9974
|
+
return;
|
|
9975
|
+
}
|
|
9215
9976
|
next(err);
|
|
9216
9977
|
}
|
|
9217
9978
|
);
|
|
@@ -9370,6 +10131,15 @@ function createHttpAppRuntime() {
|
|
|
9370
10131
|
return;
|
|
9371
10132
|
}
|
|
9372
10133
|
if (!isStatefulSessionMode) {
|
|
10134
|
+
if (activeStatelessConnections.size >= config.maxSessions) {
|
|
10135
|
+
respondJsonRpcClientError(
|
|
10136
|
+
res,
|
|
10137
|
+
503,
|
|
10138
|
+
`Maximum active stateless request limit reached (${config.maxSessions})`,
|
|
10139
|
+
-32e3
|
|
10140
|
+
);
|
|
10141
|
+
return;
|
|
10142
|
+
}
|
|
9373
10143
|
if (!isInitializeRequest(req.body)) {
|
|
9374
10144
|
const protocolError = validateRequiredProtocolVersion(
|
|
9375
10145
|
protocolVersionHeader
|
|
@@ -9438,7 +10208,7 @@ function createHttpAppRuntime() {
|
|
|
9438
10208
|
}
|
|
9439
10209
|
hasReservedSessionSlot = true;
|
|
9440
10210
|
const newTransport = new StreamableHTTPServerTransport({
|
|
9441
|
-
sessionIdGenerator: () =>
|
|
10211
|
+
sessionIdGenerator: () => randomUUID2(),
|
|
9442
10212
|
eventStore: managedEventStore.eventStore,
|
|
9443
10213
|
onsessioninitialized: (id) => {
|
|
9444
10214
|
sessionStore.set(id, {
|
|
@@ -9508,19 +10278,6 @@ function createHttpAppRuntime() {
|
|
|
9508
10278
|
}
|
|
9509
10279
|
});
|
|
9510
10280
|
app.get("/mcp", async (req, res) => {
|
|
9511
|
-
if (!isStatefulSessionMode) {
|
|
9512
|
-
res.status(405).json({
|
|
9513
|
-
jsonrpc: "2.0",
|
|
9514
|
-
error: {
|
|
9515
|
-
code: -32e3,
|
|
9516
|
-
message: "GET /mcp is not used in stateless session mode"
|
|
9517
|
-
},
|
|
9518
|
-
id: null
|
|
9519
|
-
});
|
|
9520
|
-
return;
|
|
9521
|
-
}
|
|
9522
|
-
const sessionId = req.headers["mcp-session-id"];
|
|
9523
|
-
const protocolVersionHeader = getMcpProtocolVersion(req);
|
|
9524
10281
|
let requestedToolDomains;
|
|
9525
10282
|
try {
|
|
9526
10283
|
requestedToolDomains = parseRequestedToolDomains(req.query.tools);
|
|
@@ -9532,6 +10289,158 @@ function createHttpAppRuntime() {
|
|
|
9532
10289
|
);
|
|
9533
10290
|
return;
|
|
9534
10291
|
}
|
|
10292
|
+
if (!isStatefulSessionMode) {
|
|
10293
|
+
if (activeReplayOperations.size >= config.maxSessions) {
|
|
10294
|
+
respondJsonRpcClientError(
|
|
10295
|
+
res,
|
|
10296
|
+
503,
|
|
10297
|
+
`Maximum active stateless replay limit reached (${config.maxSessions})`,
|
|
10298
|
+
-32e3
|
|
10299
|
+
);
|
|
10300
|
+
return;
|
|
10301
|
+
}
|
|
10302
|
+
if (!managedEventStore.eventStore || !managedEventStore.acquireReplayLease) {
|
|
10303
|
+
res.setHeader("Allow", "POST");
|
|
10304
|
+
respondJsonRpcClientError(
|
|
10305
|
+
res,
|
|
10306
|
+
405,
|
|
10307
|
+
"Stateless GET /mcp replay requires MCP_EVENT_STORE=memory or redis",
|
|
10308
|
+
-32e3
|
|
10309
|
+
);
|
|
10310
|
+
return;
|
|
10311
|
+
}
|
|
10312
|
+
const lastEventId = req.headers["last-event-id"];
|
|
10313
|
+
if (typeof lastEventId !== "string" || lastEventId.length === 0) {
|
|
10314
|
+
res.setHeader("Allow", "POST");
|
|
10315
|
+
respondJsonRpcClientError(
|
|
10316
|
+
res,
|
|
10317
|
+
405,
|
|
10318
|
+
"Stateless GET /mcp only supports replay with Last-Event-ID",
|
|
10319
|
+
-32e3
|
|
10320
|
+
);
|
|
10321
|
+
return;
|
|
10322
|
+
}
|
|
10323
|
+
if (!req.headers.accept?.includes("text/event-stream")) {
|
|
10324
|
+
respondJsonRpcClientError(
|
|
10325
|
+
res,
|
|
10326
|
+
406,
|
|
10327
|
+
"Not Acceptable: Client must accept text/event-stream",
|
|
10328
|
+
-32e3
|
|
10329
|
+
);
|
|
10330
|
+
return;
|
|
10331
|
+
}
|
|
10332
|
+
const protocolError = validateRequiredProtocolVersion(
|
|
10333
|
+
getMcpProtocolVersion(req)
|
|
10334
|
+
);
|
|
10335
|
+
if (protocolError) {
|
|
10336
|
+
respondJsonRpcClientError(res, 400, protocolError, -32e3);
|
|
10337
|
+
return;
|
|
10338
|
+
}
|
|
10339
|
+
const replayEventStore = managedEventStore.eventStore;
|
|
10340
|
+
if (!replayEventStore) {
|
|
10341
|
+
return;
|
|
10342
|
+
}
|
|
10343
|
+
try {
|
|
10344
|
+
const lease = await managedEventStore.acquireReplayLease(lastEventId);
|
|
10345
|
+
if (lease.status !== "acquired") {
|
|
10346
|
+
if (lease.status === "missing") {
|
|
10347
|
+
respondJsonRpcClientError(
|
|
10348
|
+
res,
|
|
10349
|
+
400,
|
|
10350
|
+
"Invalid event ID format",
|
|
10351
|
+
-32e3
|
|
10352
|
+
);
|
|
10353
|
+
return;
|
|
10354
|
+
}
|
|
10355
|
+
respondJsonRpcClientError(
|
|
10356
|
+
res,
|
|
10357
|
+
409,
|
|
10358
|
+
"Conflict: Stream already has an active replay connection",
|
|
10359
|
+
-32e3
|
|
10360
|
+
);
|
|
10361
|
+
return;
|
|
10362
|
+
}
|
|
10363
|
+
const replayOperation = (async () => {
|
|
10364
|
+
try {
|
|
10365
|
+
res.status(200);
|
|
10366
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
10367
|
+
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
10368
|
+
res.flushHeaders();
|
|
10369
|
+
let cursor = lastEventId;
|
|
10370
|
+
let finalResponseSeen = false;
|
|
10371
|
+
const deadline = Date.now() + 25e3;
|
|
10372
|
+
while (isReady && !res.destroyed && !finalResponseSeen) {
|
|
10373
|
+
await replayEventStore.replayEventsAfter(cursor, {
|
|
10374
|
+
send: async (eventId, message) => {
|
|
10375
|
+
cursor = eventId;
|
|
10376
|
+
finalResponseSeen = "id" in message && ("result" in message || "error" in message);
|
|
10377
|
+
if (!res.write(
|
|
10378
|
+
`event: message
|
|
10379
|
+
id: ${eventId}
|
|
10380
|
+
data: ${JSON.stringify(message)}
|
|
10381
|
+
|
|
10382
|
+
`
|
|
10383
|
+
)) {
|
|
10384
|
+
await waitForResponseWritable(res);
|
|
10385
|
+
}
|
|
10386
|
+
}
|
|
10387
|
+
});
|
|
10388
|
+
if (finalResponseSeen || res.destroyed) {
|
|
10389
|
+
break;
|
|
10390
|
+
}
|
|
10391
|
+
if (Date.now() >= deadline) {
|
|
10392
|
+
res.write(`id: ${cursor}
|
|
10393
|
+
data:
|
|
10394
|
+
|
|
10395
|
+
`);
|
|
10396
|
+
break;
|
|
10397
|
+
}
|
|
10398
|
+
await new Promise((resolvePoll) => setTimeout(resolvePoll, 100));
|
|
10399
|
+
}
|
|
10400
|
+
if (!res.writableEnded && !res.destroyed) {
|
|
10401
|
+
await new Promise((resolveResponse) => {
|
|
10402
|
+
const done = () => resolveResponse();
|
|
10403
|
+
res.once("finish", done);
|
|
10404
|
+
res.once("close", done);
|
|
10405
|
+
res.end();
|
|
10406
|
+
});
|
|
10407
|
+
}
|
|
10408
|
+
} finally {
|
|
10409
|
+
try {
|
|
10410
|
+
await lease.release();
|
|
10411
|
+
} catch (error) {
|
|
10412
|
+
Logger.error("Failed to release stateless replay lease", {
|
|
10413
|
+
metadata: {
|
|
10414
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10415
|
+
}
|
|
10416
|
+
});
|
|
10417
|
+
}
|
|
10418
|
+
}
|
|
10419
|
+
})();
|
|
10420
|
+
activeReplayOperations.add(replayOperation);
|
|
10421
|
+
try {
|
|
10422
|
+
await replayOperation;
|
|
10423
|
+
} finally {
|
|
10424
|
+
activeReplayOperations.delete(replayOperation);
|
|
10425
|
+
}
|
|
10426
|
+
} catch (error) {
|
|
10427
|
+
if (res.headersSent) {
|
|
10428
|
+
Logger.error("GET /mcp stateless replay failed", {
|
|
10429
|
+
metadata: {
|
|
10430
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10431
|
+
}
|
|
10432
|
+
});
|
|
10433
|
+
if (!res.writableEnded) {
|
|
10434
|
+
res.end();
|
|
10435
|
+
}
|
|
10436
|
+
} else {
|
|
10437
|
+
respondJsonRpcInternalError(res, "GET /mcp stateless", error);
|
|
10438
|
+
}
|
|
10439
|
+
}
|
|
10440
|
+
return;
|
|
10441
|
+
}
|
|
10442
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
10443
|
+
const protocolVersionHeader = getMcpProtocolVersion(req);
|
|
9535
10444
|
if (!sessionId) {
|
|
9536
10445
|
res.status(400).json({
|
|
9537
10446
|
jsonrpc: "2.0",
|
|
@@ -9667,6 +10576,13 @@ function createHttpAppRuntime() {
|
|
|
9667
10576
|
if (isStatefulSessionMode) {
|
|
9668
10577
|
await sessionStore.closeAll();
|
|
9669
10578
|
}
|
|
10579
|
+
await Promise.allSettled(
|
|
10580
|
+
Array.from(
|
|
10581
|
+
activeStatelessConnections,
|
|
10582
|
+
(closeConnection) => closeConnection()
|
|
10583
|
+
)
|
|
10584
|
+
);
|
|
10585
|
+
await Promise.allSettled(activeReplayOperations);
|
|
9670
10586
|
} finally {
|
|
9671
10587
|
await managedEventStore.close();
|
|
9672
10588
|
}
|
|
@@ -9715,7 +10631,7 @@ function createHttpAppRuntime() {
|
|
|
9715
10631
|
console.log(" GET /ready - Readiness check");
|
|
9716
10632
|
console.log(" POST /mcp - MCP requests");
|
|
9717
10633
|
console.log(
|
|
9718
|
-
` GET /mcp - ${isStatefulSessionMode ? "SSE notifications" : "
|
|
10634
|
+
` GET /mcp - ${isStatefulSessionMode ? "SSE notifications and replay" : managedEventStore.eventStore ? "SSE replay (requires Last-Event-ID)" : "Unavailable (event store off)"}`
|
|
9719
10635
|
);
|
|
9720
10636
|
console.log(
|
|
9721
10637
|
` DELETE /mcp - ${isStatefulSessionMode ? "Close session" : "Not used in stateless mode"}`
|
|
@@ -9730,9 +10646,7 @@ function createHttpAppRuntime() {
|
|
|
9730
10646
|
async function shutdown(signal) {
|
|
9731
10647
|
console.log(`
|
|
9732
10648
|
[MCP] Received ${signal}, shutting down gracefully...`);
|
|
9733
|
-
const
|
|
9734
|
-
const parsedShutdownTimeout = rawShutdownTimeout ? Number.parseInt(rawShutdownTimeout, 10) : 1e4;
|
|
9735
|
-
const shutdownTimeoutMs = Number.isFinite(parsedShutdownTimeout) && parsedShutdownTimeout > 0 ? parsedShutdownTimeout : 1e4;
|
|
10649
|
+
const shutdownTimeoutMs = config.shutdownTimeout;
|
|
9736
10650
|
const forceExitTimer = setTimeout(() => {
|
|
9737
10651
|
console.error(
|
|
9738
10652
|
`[MCP] Forced shutdown after ${shutdownTimeoutMs}ms timeout`
|