portkey-admin-mcp 0.15.1 → 0.16.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/COMPATIBILITY.md CHANGED
@@ -1,16 +1,18 @@
1
1
  # Compatibility and deprecations
2
2
 
3
- Last reviewed: 2026-10-25. Package versions, SDK versions, and negotiated MCP
3
+ Last reviewed: 2026-10-30. Package versions, SDK versions, and negotiated MCP
4
4
  protocol revisions are separate compatibility boundaries.
5
5
 
6
6
  ## Release lines
7
7
 
8
8
  | Package release | MCP SDK | MCP protocol | Support and behavior |
9
9
  | --- | --- | --- | --- |
10
- | 0.15.1 | server/client 2.3.1, Node adapter 2.1.1 (exact pins) | Native `2026-07-28` plus older clients on the same endpoint | Current release, 194 tools across 22 domains, Node.js 24+. HTTP session and replay stores are retired; obsolete settings warn and are ignored. First warnings and ignored settings start in 0.15.0; session/replay behavior is removed in that release. |
11
- | 0.14.1 | v1; dependency floor 1.32.1 | Latest supported revision: `2025-11-25` | Previous line, 194 tools across 22 domains, Node.js 24+. Stateful HTTP sessions and optional replay stores remain active. |
10
+ | 0.16.0 | server/client 2.4.0, Node adapter 2.1.2 (exact pins) | Native `2026-07-28` plus older clients on the same endpoint | Current release, 194 tools across 22 domains, Node.js 24+, also tested on Node 26, which the Docker image runs. HTTP session and replay stores are retired; obsolete settings warn and are ignored. First warnings and ignored settings start in 0.15.0; session/replay behavior is removed in that release. |
11
+ | 0.15.2 | server/client 2.4.0, Node adapter 2.1.2 (exact pins) | Native `2026-07-28` plus older clients on the same endpoint | Previous line, 194 tools across 22 domains, Node.js 24+. HTTP session and replay stores are retired; obsolete settings warn and are ignored. First warnings and ignored settings start in 0.15.0; session/replay behavior is removed in that release. |
12
12
  | 0.13.0 | v1; dependency floor 1.31.0 | Latest supported revision: `2025-11-25` | Historical release, 184 tools across 20 domains. Upgrade to the latest minor for security fixes. |
13
13
 
14
+ Node.js 24 is the supported floor (`engines.node` is `>=24`). The main CI checks and the release build run on Node 24. Node 26 is also tested in CI, and the Docker image runs Node 26 from 0.16.0.
15
+
14
16
  The 0.14.x SDK supports `2025-11-25`, `2025-06-18`, `2025-03-26`,
15
17
  `2024-11-05`, and `2024-10-07`. A newer client that negotiates an older
16
18
  revision can use this server; that fallback does not mean the server natively
@@ -26,7 +28,7 @@ No deprecation warnings or removals for the settings below shipped in 0.14.x.
26
28
  As of 0.15.0, the listed settings warn and are ignored, and the underlying
27
29
  session/replay behavior is removed. There was no intermediate warning-only
28
30
  release. Obsolete names remain recognized for warnings; this does not retain
29
- their former functionality. 0.14.x is the previous line and is unchanged.
31
+ their former functionality. 0.14.x is unchanged.
30
32
 
31
33
  | Setting or behavior | 0.14.x | 0.15.0 behavior | First warning / ignored / removal release |
32
34
  | --- | --- | --- | --- |
package/README.md CHANGED
@@ -419,10 +419,10 @@ tool catalog in this repository as authoritative when a third-party index lags.
419
419
  <h2 align="center" id="built-with">Built With</h2>
420
420
 
421
421
  [![TypeScript](https://img.shields.io/badge/TypeScript_7.0-3178C6?logo=typescript&logoColor=fff)](https://www.typescriptlang.org/)
422
- [![MCP SDK](https://img.shields.io/badge/MCP_SDK_2.3-000?logo=modelcontextprotocol&logoColor=fff)](https://github.com/modelcontextprotocol/typescript-sdk)
422
+ [![MCP SDK](https://img.shields.io/badge/MCP_SDK_2.4-000?logo=modelcontextprotocol&logoColor=fff)](https://github.com/modelcontextprotocol/typescript-sdk)
423
423
  [![Zod 4](https://img.shields.io/badge/Zod_4-3E67B1?logo=zod&logoColor=fff)](https://zod.dev/)
424
424
  [![Biome](https://img.shields.io/badge/Biome_2.5-60a5fa?logo=biome&logoColor=fff)](https://biomejs.dev/)
425
- [![Node 24](https://img.shields.io/badge/Node_24-339933?logo=nodedotjs&logoColor=fff)](https://nodejs.org/)
425
+ [![Node 24 | 26](https://img.shields.io/badge/Node_24_%7C_26-339933?logo=nodedotjs&logoColor=fff)](https://nodejs.org/)
426
426
  [![Anthropic](https://img.shields.io/badge/Anthropic-CC785C?style=flat&logo=anthropic&logoColor=white)](https://claude.ai/)
427
427
 
428
428
  [![SemVer](https://img.shields.io/badge/semver-2.0.0-blue)](https://semver.org/)
@@ -439,7 +439,7 @@ Marketplace listings on [LobeHub](https://lobehub.com/mcp/codeswhat-portkey-admi
439
439
 
440
440
  **[MIT License](LICENSE)** · Inspired by [r-huijts/portkey-admin-mcp-server](https://github.com/r-huijts/portkey-admin-mcp-server)
441
441
 
442
- <a href="https://github.com/CodesWhat">
442
+ <a href="https://codeswhat.com">
443
443
  <picture>
444
444
  <source media="(prefers-color-scheme: dark)" srcset="assets/codeswhat-logo-dark.svg" />
445
445
  <source media="(prefers-color-scheme: light)" srcset="assets/codeswhat-logo-original.svg" />
@@ -447,6 +447,8 @@ Marketplace listings on [LobeHub](https://lobehub.com/mcp/codeswhat-portkey-admi
447
447
  </picture>
448
448
  </a>
449
449
 
450
+ [CodesWhat](https://codeswhat.com): small, sharp tools from one developer and a lot of agents.
451
+
450
452
  <a href="#portkey-admin-mcp-server">Back to top</a>
451
453
 
452
454
  </div>
package/build/index.js CHANGED
@@ -236,6 +236,19 @@ async function parseErrorResponse(response) {
236
236
  }
237
237
  }
238
238
 
239
+ // src/lib/path-segment.ts
240
+ function isDotPathSegment(value) {
241
+ let decoded = value;
242
+ try {
243
+ decoded = decodeURIComponent(value);
244
+ } catch {
245
+ }
246
+ return decoded === "." || decoded === ".." || value === "." || value === "..";
247
+ }
248
+ function isInvalidPathSegment(value) {
249
+ return value === "" || isDotPathSegment(value);
250
+ }
251
+
239
252
  // src/services/base.service.ts
240
253
  var DEFAULT_BASE_URL = "https://api.portkey.ai/v1";
241
254
  var DEFAULT_PUBLIC_BASE_URL = "https://api.portkey.ai";
@@ -379,9 +392,32 @@ var BaseService = class {
379
392
  this.baseUrl = baseUrl.replace(/\/+$/, "");
380
393
  this.v2BaseUrl = toV2BaseUrl(this.baseUrl);
381
394
  }
395
+ /**
396
+ * Encode a caller-supplied value for use as one URL path segment. "", "."
397
+ * and ".." (including percent-encoded forms) are refused: fetch's URL
398
+ * parser would collapse them and send the request to a different endpoint.
399
+ */
382
400
  encodePathSegment(value) {
401
+ if (isInvalidPathSegment(value)) {
402
+ throw new Error('Invalid path segment: must not be empty, "." or ".."');
403
+ }
383
404
  return encodeURIComponent(value);
384
405
  }
406
+ /**
407
+ * Defence in depth: refuse to send a request whose path the URL parser
408
+ * rewrote (dot segments), since that would reach a different endpoint than
409
+ * the one the service built.
410
+ */
411
+ assertPathNotNormalised(baseUrl, path, url) {
412
+ const queryIndex = path.search(/[?#]/);
413
+ const builtPath = queryIndex === -1 ? path : path.slice(0, queryIndex);
414
+ const expected = `${new URL(baseUrl).pathname.replace(/\/+$/, "")}${builtPath}`;
415
+ if (new URL(url).pathname !== expected) {
416
+ throw new Error(
417
+ "Refusing request: the request path would be normalised by the URL parser"
418
+ );
419
+ }
420
+ }
385
421
  buildUrl(path, params, baseUrl = this.baseUrl) {
386
422
  return `${baseUrl}${path}${buildQueryString(params)}`;
387
423
  }
@@ -404,6 +440,7 @@ var BaseService = class {
404
440
  }
405
441
  const requestId = crypto.randomUUID();
406
442
  const url = this.buildUrl(path, options.params, options.baseUrl);
443
+ this.assertPathNotNormalised(options.baseUrl ?? this.baseUrl, path, url);
407
444
  const startTime = Date.now();
408
445
  Logger.debug("HTTP request started", {
409
446
  requestId,
@@ -781,7 +818,7 @@ var AnalyticsService = class extends BaseService {
781
818
  throw new Error("metadataKey is required");
782
819
  }
783
820
  return this.get(
784
- `/analytics/groups/metadata/${encodeURIComponent(metadataKey)}`,
821
+ `/analytics/groups/metadata/${this.encodePathSegment(metadataKey)}`,
785
822
  this.buildAnalyticsParams(params)
786
823
  );
787
824
  }
@@ -2515,6 +2552,9 @@ function pageSizeSchema(max = 100) {
2515
2552
  return z4.coerce.number().int().positive().max(max).optional().describe(`Results per page (max ${max})`);
2516
2553
  }
2517
2554
  var PageSizeSchema = pageSizeSchema();
2555
+ var PathIdSchema = z4.string().min(1).refine((value) => !isInvalidPathSegment(value), {
2556
+ message: 'Must not be empty, "." or ".."'
2557
+ });
2518
2558
 
2519
2559
  // src/tools/utils.ts
2520
2560
  function formatFullName(firstName, lastName) {
@@ -3973,7 +4013,9 @@ var GUARDRAILS_TOOL_SCHEMAS = {
3973
4013
  current_page: CurrentPageSchema
3974
4014
  },
3975
4015
  getGuardrail: {
3976
- guardrail_id: z13.string().describe("The guardrail UUID or slug (with guard_ prefix) to retrieve")
4016
+ guardrail_id: PathIdSchema.describe(
4017
+ "The guardrail UUID or slug (with guard_ prefix) to retrieve"
4018
+ )
3977
4019
  },
3978
4020
  createGuardrail: {
3979
4021
  name: z13.string().describe("Name of the guardrail"),
@@ -3986,13 +4028,13 @@ var GUARDRAILS_TOOL_SCHEMAS = {
3986
4028
  organisation_id: z13.string().optional().describe("Organisation ID (required if workspace_id not provided)")
3987
4029
  },
3988
4030
  updateGuardrail: {
3989
- guardrail_id: z13.string().describe("The guardrail UUID or slug to update"),
4031
+ guardrail_id: PathIdSchema.describe("The guardrail UUID or slug to update"),
3990
4032
  name: z13.string().optional().describe("New name for the guardrail"),
3991
4033
  checks: z13.array(guardrailCheckSchema).min(1).optional().describe("Updated array of checks to apply"),
3992
4034
  actions: guardrailActionSchema.optional().describe("Updated actions configuration")
3993
4035
  },
3994
4036
  deleteGuardrail: {
3995
- guardrail_id: z13.string().describe("The guardrail UUID or slug to delete")
4037
+ guardrail_id: PathIdSchema.describe("The guardrail UUID or slug to delete")
3996
4038
  },
3997
4039
  updateOrganisationDefaults: {
3998
4040
  input_guardrails: z13.array(z13.string()).optional().describe("Ordered guardrail IDs or slugs to enforce on model input"),
@@ -4007,16 +4049,16 @@ var GUARDRAILS_TOOL_SCHEMAS = {
4007
4049
  override_existing: z13.boolean().optional().describe("Replace existing exclusion states instead of merging changes")
4008
4050
  },
4009
4051
  listGuardrailMcpServerMappings: {
4010
- guardrail_id: z13.string().min(1).describe("Guardrail UUID or slug")
4052
+ guardrail_id: PathIdSchema.describe("Guardrail UUID or slug")
4011
4053
  },
4012
4054
  replaceGuardrailMcpServerMappings: {
4013
- guardrail_id: z13.string().min(1).describe("Guardrail UUID or slug"),
4055
+ guardrail_id: PathIdSchema.describe("Guardrail UUID or slug"),
4014
4056
  mcp_servers: z13.record(z13.string().uuid(), guardrailMcpServerMappingConfigSchema).describe(
4015
4057
  "Complete MCP-server mapping set keyed by server UUID; an empty object clears every mapping"
4016
4058
  )
4017
4059
  },
4018
4060
  upsertGuardrailMcpServerMapping: {
4019
- guardrail_id: z13.string().min(1).describe("Guardrail UUID or slug"),
4061
+ guardrail_id: PathIdSchema.describe("Guardrail UUID or slug"),
4020
4062
  mcp_server_id: z13.string().uuid().describe("MCP server UUID"),
4021
4063
  ...guardrailMcpServerMappingConfigShape
4022
4064
  }
@@ -8765,7 +8807,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8765
8807
  status: z28.enum(["active", "archived"]).optional().describe("Filter by workspace lifecycle status")
8766
8808
  },
8767
8809
  getWorkspace: {
8768
- workspace_id: z28.string().describe(
8810
+ workspace_id: PathIdSchema.describe(
8769
8811
  "The unique identifier of the workspace to retrieve. This can be found in the workspace's URL or from the list_workspaces tool response"
8770
8812
  )
8771
8813
  },
@@ -8780,7 +8822,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8780
8822
  rate_limits: z28.array(workspaceRateLimitSchema).optional().describe("Initial workspace rate-limit settings")
8781
8823
  },
8782
8824
  updateWorkspace: {
8783
- workspace_id: z28.string().describe("The workspace ID to update"),
8825
+ workspace_id: PathIdSchema.describe("The workspace ID to update"),
8784
8826
  name: z28.string().optional().describe("New name for the workspace"),
8785
8827
  slug: z28.string().optional().describe("New slug for the workspace"),
8786
8828
  description: z28.string().optional().describe("New description"),
@@ -8795,10 +8837,12 @@ var WORKSPACES_TOOL_SCHEMAS = {
8795
8837
  rate_limits: z28.array(workspaceRateLimitSchema).optional().describe("Replacement workspace rate-limit settings")
8796
8838
  },
8797
8839
  deleteWorkspace: {
8798
- workspace_id: z28.string().describe("The workspace ID to delete")
8840
+ workspace_id: PathIdSchema.describe("The workspace ID to delete")
8799
8841
  },
8800
8842
  addWorkspaceMember: {
8801
- workspace_id: z28.string().describe("The workspace ID to add the member to"),
8843
+ workspace_id: PathIdSchema.describe(
8844
+ "The workspace ID to add the member to"
8845
+ ),
8802
8846
  user_id: z28.string().uuid(
8803
8847
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8804
8848
  ).describe(
@@ -8807,14 +8851,14 @@ var WORKSPACES_TOOL_SCHEMAS = {
8807
8851
  role: z28.enum(["admin", "member", "manager"]).describe("Role in the workspace")
8808
8852
  },
8809
8853
  listWorkspaceMembers: {
8810
- workspace_id: z28.string().describe("The workspace ID to list members for"),
8854
+ workspace_id: PathIdSchema.describe("The workspace ID to list members for"),
8811
8855
  current_page: CurrentPageSchema.describe("Zero-based page number"),
8812
8856
  page_size: PageSizeSchema.describe("Number of members per page"),
8813
8857
  role: z28.enum(["admin", "manager", "member"]).optional().describe("Filter by workspace role"),
8814
8858
  email: z28.string().email().optional().describe("Filter by member email")
8815
8859
  },
8816
8860
  getWorkspaceMember: {
8817
- workspace_id: z28.string().describe("The workspace ID"),
8861
+ workspace_id: PathIdSchema.describe("The workspace ID"),
8818
8862
  user_id: z28.string().uuid(
8819
8863
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8820
8864
  ).describe(
@@ -8822,7 +8866,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8822
8866
  )
8823
8867
  },
8824
8868
  updateWorkspaceMember: {
8825
- workspace_id: z28.string().describe("The workspace ID"),
8869
+ workspace_id: PathIdSchema.describe("The workspace ID"),
8826
8870
  user_id: z28.string().uuid(
8827
8871
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8828
8872
  ).describe(
@@ -8831,7 +8875,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8831
8875
  role: z28.enum(["admin", "member", "manager"]).describe("New role in the workspace")
8832
8876
  },
8833
8877
  removeWorkspaceMember: {
8834
- workspace_id: z28.string().describe("The workspace ID"),
8878
+ workspace_id: PathIdSchema.describe("The workspace ID"),
8835
8879
  user_id: z28.string().uuid(
8836
8880
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8837
8881
  ).describe("The user ID to remove")
package/build/server.js CHANGED
@@ -249,6 +249,19 @@ var Logger = {
249
249
  }
250
250
  };
251
251
 
252
+ // src/lib/path-segment.ts
253
+ function isDotPathSegment(value) {
254
+ let decoded = value;
255
+ try {
256
+ decoded = decodeURIComponent(value);
257
+ } catch {
258
+ }
259
+ return decoded === "." || decoded === ".." || value === "." || value === "..";
260
+ }
261
+ function isInvalidPathSegment(value) {
262
+ return value === "" || isDotPathSegment(value);
263
+ }
264
+
252
265
  // src/services/base.service.ts
253
266
  var DEFAULT_BASE_URL = "https://api.portkey.ai/v1";
254
267
  var DEFAULT_PUBLIC_BASE_URL = "https://api.portkey.ai";
@@ -392,9 +405,32 @@ var BaseService = class {
392
405
  this.baseUrl = baseUrl.replace(/\/+$/, "");
393
406
  this.v2BaseUrl = toV2BaseUrl(this.baseUrl);
394
407
  }
408
+ /**
409
+ * Encode a caller-supplied value for use as one URL path segment. "", "."
410
+ * and ".." (including percent-encoded forms) are refused: fetch's URL
411
+ * parser would collapse them and send the request to a different endpoint.
412
+ */
395
413
  encodePathSegment(value) {
414
+ if (isInvalidPathSegment(value)) {
415
+ throw new Error('Invalid path segment: must not be empty, "." or ".."');
416
+ }
396
417
  return encodeURIComponent(value);
397
418
  }
419
+ /**
420
+ * Defence in depth: refuse to send a request whose path the URL parser
421
+ * rewrote (dot segments), since that would reach a different endpoint than
422
+ * the one the service built.
423
+ */
424
+ assertPathNotNormalised(baseUrl, path, url) {
425
+ const queryIndex = path.search(/[?#]/);
426
+ const builtPath = queryIndex === -1 ? path : path.slice(0, queryIndex);
427
+ const expected = `${new URL(baseUrl).pathname.replace(/\/+$/, "")}${builtPath}`;
428
+ if (new URL(url).pathname !== expected) {
429
+ throw new Error(
430
+ "Refusing request: the request path would be normalised by the URL parser"
431
+ );
432
+ }
433
+ }
398
434
  buildUrl(path, params, baseUrl = this.baseUrl) {
399
435
  return `${baseUrl}${path}${buildQueryString(params)}`;
400
436
  }
@@ -417,6 +453,7 @@ var BaseService = class {
417
453
  }
418
454
  const requestId = crypto.randomUUID();
419
455
  const url = this.buildUrl(path, options.params, options.baseUrl);
456
+ this.assertPathNotNormalised(options.baseUrl ?? this.baseUrl, path, url);
420
457
  const startTime = Date.now();
421
458
  Logger.debug("HTTP request started", {
422
459
  requestId,
@@ -794,7 +831,7 @@ var AnalyticsService = class extends BaseService {
794
831
  throw new Error("metadataKey is required");
795
832
  }
796
833
  return this.get(
797
- `/analytics/groups/metadata/${encodeURIComponent(metadataKey)}`,
834
+ `/analytics/groups/metadata/${this.encodePathSegment(metadataKey)}`,
798
835
  this.buildAnalyticsParams(params)
799
836
  );
800
837
  }
@@ -2528,6 +2565,9 @@ function pageSizeSchema(max = 100) {
2528
2565
  return z4.coerce.number().int().positive().max(max).optional().describe(`Results per page (max ${max})`);
2529
2566
  }
2530
2567
  var PageSizeSchema = pageSizeSchema();
2568
+ var PathIdSchema = z4.string().min(1).refine((value) => !isInvalidPathSegment(value), {
2569
+ message: 'Must not be empty, "." or ".."'
2570
+ });
2531
2571
 
2532
2572
  // src/tools/utils.ts
2533
2573
  function formatFullName(firstName, lastName) {
@@ -3986,7 +4026,9 @@ var GUARDRAILS_TOOL_SCHEMAS = {
3986
4026
  current_page: CurrentPageSchema
3987
4027
  },
3988
4028
  getGuardrail: {
3989
- guardrail_id: z13.string().describe("The guardrail UUID or slug (with guard_ prefix) to retrieve")
4029
+ guardrail_id: PathIdSchema.describe(
4030
+ "The guardrail UUID or slug (with guard_ prefix) to retrieve"
4031
+ )
3990
4032
  },
3991
4033
  createGuardrail: {
3992
4034
  name: z13.string().describe("Name of the guardrail"),
@@ -3999,13 +4041,13 @@ var GUARDRAILS_TOOL_SCHEMAS = {
3999
4041
  organisation_id: z13.string().optional().describe("Organisation ID (required if workspace_id not provided)")
4000
4042
  },
4001
4043
  updateGuardrail: {
4002
- guardrail_id: z13.string().describe("The guardrail UUID or slug to update"),
4044
+ guardrail_id: PathIdSchema.describe("The guardrail UUID or slug to update"),
4003
4045
  name: z13.string().optional().describe("New name for the guardrail"),
4004
4046
  checks: z13.array(guardrailCheckSchema).min(1).optional().describe("Updated array of checks to apply"),
4005
4047
  actions: guardrailActionSchema.optional().describe("Updated actions configuration")
4006
4048
  },
4007
4049
  deleteGuardrail: {
4008
- guardrail_id: z13.string().describe("The guardrail UUID or slug to delete")
4050
+ guardrail_id: PathIdSchema.describe("The guardrail UUID or slug to delete")
4009
4051
  },
4010
4052
  updateOrganisationDefaults: {
4011
4053
  input_guardrails: z13.array(z13.string()).optional().describe("Ordered guardrail IDs or slugs to enforce on model input"),
@@ -4020,16 +4062,16 @@ var GUARDRAILS_TOOL_SCHEMAS = {
4020
4062
  override_existing: z13.boolean().optional().describe("Replace existing exclusion states instead of merging changes")
4021
4063
  },
4022
4064
  listGuardrailMcpServerMappings: {
4023
- guardrail_id: z13.string().min(1).describe("Guardrail UUID or slug")
4065
+ guardrail_id: PathIdSchema.describe("Guardrail UUID or slug")
4024
4066
  },
4025
4067
  replaceGuardrailMcpServerMappings: {
4026
- guardrail_id: z13.string().min(1).describe("Guardrail UUID or slug"),
4068
+ guardrail_id: PathIdSchema.describe("Guardrail UUID or slug"),
4027
4069
  mcp_servers: z13.record(z13.string().uuid(), guardrailMcpServerMappingConfigSchema).describe(
4028
4070
  "Complete MCP-server mapping set keyed by server UUID; an empty object clears every mapping"
4029
4071
  )
4030
4072
  },
4031
4073
  upsertGuardrailMcpServerMapping: {
4032
- guardrail_id: z13.string().min(1).describe("Guardrail UUID or slug"),
4074
+ guardrail_id: PathIdSchema.describe("Guardrail UUID or slug"),
4033
4075
  mcp_server_id: z13.string().uuid().describe("MCP server UUID"),
4034
4076
  ...guardrailMcpServerMappingConfigShape
4035
4077
  }
@@ -8778,7 +8820,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8778
8820
  status: z28.enum(["active", "archived"]).optional().describe("Filter by workspace lifecycle status")
8779
8821
  },
8780
8822
  getWorkspace: {
8781
- workspace_id: z28.string().describe(
8823
+ workspace_id: PathIdSchema.describe(
8782
8824
  "The unique identifier of the workspace to retrieve. This can be found in the workspace's URL or from the list_workspaces tool response"
8783
8825
  )
8784
8826
  },
@@ -8793,7 +8835,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8793
8835
  rate_limits: z28.array(workspaceRateLimitSchema).optional().describe("Initial workspace rate-limit settings")
8794
8836
  },
8795
8837
  updateWorkspace: {
8796
- workspace_id: z28.string().describe("The workspace ID to update"),
8838
+ workspace_id: PathIdSchema.describe("The workspace ID to update"),
8797
8839
  name: z28.string().optional().describe("New name for the workspace"),
8798
8840
  slug: z28.string().optional().describe("New slug for the workspace"),
8799
8841
  description: z28.string().optional().describe("New description"),
@@ -8808,10 +8850,12 @@ var WORKSPACES_TOOL_SCHEMAS = {
8808
8850
  rate_limits: z28.array(workspaceRateLimitSchema).optional().describe("Replacement workspace rate-limit settings")
8809
8851
  },
8810
8852
  deleteWorkspace: {
8811
- workspace_id: z28.string().describe("The workspace ID to delete")
8853
+ workspace_id: PathIdSchema.describe("The workspace ID to delete")
8812
8854
  },
8813
8855
  addWorkspaceMember: {
8814
- workspace_id: z28.string().describe("The workspace ID to add the member to"),
8856
+ workspace_id: PathIdSchema.describe(
8857
+ "The workspace ID to add the member to"
8858
+ ),
8815
8859
  user_id: z28.string().uuid(
8816
8860
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8817
8861
  ).describe(
@@ -8820,14 +8864,14 @@ var WORKSPACES_TOOL_SCHEMAS = {
8820
8864
  role: z28.enum(["admin", "member", "manager"]).describe("Role in the workspace")
8821
8865
  },
8822
8866
  listWorkspaceMembers: {
8823
- workspace_id: z28.string().describe("The workspace ID to list members for"),
8867
+ workspace_id: PathIdSchema.describe("The workspace ID to list members for"),
8824
8868
  current_page: CurrentPageSchema.describe("Zero-based page number"),
8825
8869
  page_size: PageSizeSchema.describe("Number of members per page"),
8826
8870
  role: z28.enum(["admin", "manager", "member"]).optional().describe("Filter by workspace role"),
8827
8871
  email: z28.string().email().optional().describe("Filter by member email")
8828
8872
  },
8829
8873
  getWorkspaceMember: {
8830
- workspace_id: z28.string().describe("The workspace ID"),
8874
+ workspace_id: PathIdSchema.describe("The workspace ID"),
8831
8875
  user_id: z28.string().uuid(
8832
8876
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8833
8877
  ).describe(
@@ -8835,7 +8879,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8835
8879
  )
8836
8880
  },
8837
8881
  updateWorkspaceMember: {
8838
- workspace_id: z28.string().describe("The workspace ID"),
8882
+ workspace_id: PathIdSchema.describe("The workspace ID"),
8839
8883
  user_id: z28.string().uuid(
8840
8884
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8841
8885
  ).describe(
@@ -8844,7 +8888,7 @@ var WORKSPACES_TOOL_SCHEMAS = {
8844
8888
  role: z28.enum(["admin", "member", "manager"]).describe("New role in the workspace")
8845
8889
  },
8846
8890
  removeWorkspaceMember: {
8847
- workspace_id: z28.string().describe("The workspace ID"),
8891
+ workspace_id: PathIdSchema.describe("The workspace ID"),
8848
8892
  user_id: z28.string().uuid(
8849
8893
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
8850
8894
  ).describe("The user ID to remove")
@@ -4,8 +4,8 @@
4
4
 
5
5
  This guide describes how to self-deploy this MCP server on Vercel.
6
6
 
7
- This guide follows the **unreleased SDK v2 candidate**, not the published 0.14.x
8
- session/replay implementation. No deployment of this candidate has been verified.
7
+ This guide follows the **SDK v2 implementation shipped in 0.15.0**, not the 0.14.x
8
+ session/replay implementation. No Vercel deployment of it has been verified.
9
9
  Use the guide from your installed release when operating 0.14.x. See
10
10
  [compatibility and recovery](../COMPATIBILITY.md) before upgrading; the retirement and names-only warnings target 0.15.0.
11
11
 
@@ -17,7 +17,7 @@ Use the guide from your installed release when operating 0.14.x. See
17
17
  - Redis: shared rate limiting only
18
18
  - Auth: `clerk` (preferred for teams) or `bearer` (internal-only)
19
19
 
20
- Each POST is independent. GET replay, session IDs and DELETE session operations are retired in the candidate. After an interrupted mutation, inspect Portkey state before retrying; see the recovery guide. Forward `MCP-Protocol-Version`, `Mcp-Method` and `Mcp-Name` through any proxy. No idle change-notification streams are advertised.
20
+ Each POST is independent. GET replay, session IDs and DELETE session operations are retired in 0.15.0. After an interrupted mutation, inspect Portkey state before retrying; see the recovery guide. Forward `MCP-Protocol-Version`, `Mcp-Method` and `Mcp-Name` through any proxy. No idle change-notification streams are advertised.
21
21
 
22
22
  ## 1. Prerequisites
23
23
 
package/package.json CHANGED
@@ -57,12 +57,12 @@
57
57
  "jose": "^6.2.2",
58
58
  "redis": "^6.3.0",
59
59
  "zod": "^4.6.7",
60
- "@modelcontextprotocol/server": "2.3.1",
61
- "@modelcontextprotocol/node": "2.1.1"
60
+ "@modelcontextprotocol/server": "2.4.0",
61
+ "@modelcontextprotocol/node": "2.1.2"
62
62
  },
63
63
  "name": "portkey-admin-mcp",
64
64
  "mcpName": "io.github.CodesWhat/portkey-admin-mcp",
65
- "version": "0.15.1",
65
+ "version": "0.16.0",
66
66
  "main": "build/index.js",
67
67
  "keywords": [
68
68
  "mcp",
@@ -101,6 +101,6 @@
101
101
  "lefthook": "2.2.2",
102
102
  "tsx": "4.23.15",
103
103
  "typescript": "7.0.2",
104
- "@modelcontextprotocol/client": "2.3.1"
104
+ "@modelcontextprotocol/client": "2.4.0"
105
105
  }
106
106
  }